1 /*
2  * Copyright (C) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <ctype.h>
16 #include <stdbool.h>
17 #include <stdlib.h>
18 #ifndef _GNU_SOURCE
19 #define _GNU_SOURCE
20 #endif
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <sched.h>
24 #include <stdio.h>
25 #include <unistd.h>
26 
27 #include <sys/mount.h>
28 #include <sys/types.h>
29 
30 #include "appspawn_msg.h"
31 #include "appspawn_permission.h"
32 #include "appspawn_sandbox.h"
33 #include "appspawn_utils.h"
34 #include "cJSON.h"
35 #include "init_utils.h"
36 #include "json_utils.h"
37 #include "parameter.h"
38 #include "securec.h"
39 
40 static const SandboxFlagInfo NAMESPACE_FLAGS_MAP[] = {
41     {"pid", CLONE_NEWPID}, {"net", CLONE_NEWNET}
42 };
43 
44 static const SandboxFlagInfo FLAGE_POINT_MAP[] = {
45     {"0", 0},
46     {"START_FLAGS_BACKUP", (unsigned long)APP_FLAGS_BACKUP_EXTENSION},
47     {"DLP_MANAGER", (unsigned long)APP_FLAGS_DLP_MANAGER},
48     {"DEVELOPER_MODE", (unsigned long)APP_FLAGS_DEVELOPER_MODE}
49 };
50 
51 static const SandboxFlagInfo MOUNT_MODE_MAP[] = {
52     {"not-exists", (unsigned long)MOUNT_MODE_NOT_EXIST},
53     {"always", (unsigned long)MOUNT_MODE_ALWAYS}
54 };
55 
56 static const SandboxFlagInfo NAME_GROUP_TYPE_MAP[] = {
57     {"system-const", (unsigned long)SANDBOX_TAG_SYSTEM_CONST},
58     {"app-variable", (unsigned long)SANDBOX_TAG_APP_VARIABLE}
59 };
60 
CreatePathMountNode(uint32_t type,uint32_t hasDemandInfo)61 static inline PathMountNode *CreatePathMountNode(uint32_t type, uint32_t hasDemandInfo)
62 {
63     uint32_t len = hasDemandInfo ? sizeof(PathDemandInfo) : 0;
64     return (PathMountNode *)CreateSandboxMountNode(sizeof(PathMountNode) + len, type);
65 }
66 
CreateSymbolLinkNode(void)67 static inline SymbolLinkNode *CreateSymbolLinkNode(void)
68 {
69     return (SymbolLinkNode *)CreateSandboxMountNode(sizeof(SymbolLinkNode), SANDBOX_TAG_SYMLINK);
70 }
71 
CreateSandboxPackageNameNode(const char * name)72 static inline SandboxPackageNameNode *CreateSandboxPackageNameNode(const char *name)
73 {
74     return (SandboxPackageNameNode *)CreateSandboxSection(name,
75         sizeof(SandboxPackageNameNode), SANDBOX_TAG_PACKAGE_NAME);
76 }
77 
CreateSandboxFlagsNode(const char * name)78 static inline SandboxFlagsNode *CreateSandboxFlagsNode(const char *name)
79 {
80     return (SandboxFlagsNode *)CreateSandboxSection(name, sizeof(SandboxFlagsNode), SANDBOX_TAG_SPAWN_FLAGS);
81 }
82 
CreateSandboxNameGroupNode(const char * name)83 static inline SandboxNameGroupNode *CreateSandboxNameGroupNode(const char *name)
84 {
85     return (SandboxNameGroupNode *)CreateSandboxSection(name, sizeof(SandboxNameGroupNode), SANDBOX_TAG_NAME_GROUP);
86 }
87 
CreateSandboxPermissionNode(const char * name)88 static inline SandboxPermissionNode *CreateSandboxPermissionNode(const char *name)
89 {
90     size_t len = sizeof(SandboxPermissionNode);
91     SandboxPermissionNode *node = (SandboxPermissionNode *)CreateSandboxSection(name, len, SANDBOX_TAG_PERMISSION);
92     APPSPAWN_CHECK(node != NULL, return NULL, "Failed to create permission node");
93     node->permissionIndex = 0;
94     return node;
95 }
96 
GetBoolParameter(const char * param,bool value)97 static inline bool GetBoolParameter(const char *param, bool value)
98 {
99     char tmp[32] = {0};  // 32 max
100     int ret = GetParameter(param, "", tmp, sizeof(tmp));
101     APPSPAWN_LOGV("GetBoolParameter key %{public}s ret %{public}d result: %{public}s", param, ret, tmp);
102     if (ret > 0 && strcmp(tmp, "false") == 0) {
103         return false;
104     }
105     if (ret > 0 && strcmp(tmp, "true") == 0) {
106         return true;
107     }
108     return value;
109 }
110 
AppSandboxPidNsIsSupport(void)111 static inline bool AppSandboxPidNsIsSupport(void)
112 {
113     // only set false, return false
114     return GetBoolParameter("const.sandbox.pidns.support", true);
115 }
116 
CheckAppFullMountEnable(void)117 static inline bool CheckAppFullMountEnable(void)
118 {
119     return GetBoolParameter("const.filemanager.full_mount.enable", false);
120 }
121 
GetMountModeFromConfig(const cJSON * config,const char * key,unsigned long def)122 static unsigned long GetMountModeFromConfig(const cJSON *config, const char *key, unsigned long def)
123 {
124     char *value = cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(config, key));
125     if (value == NULL) {
126         return def;
127     }
128     const SandboxFlagInfo *info = GetSandboxFlagInfo(value, MOUNT_MODE_MAP, ARRAY_LENGTH(MOUNT_MODE_MAP));
129     if (info != NULL) {
130         return info->flags;
131     }
132     return def;
133 }
134 
GetNameGroupTypeFromConfig(const cJSON * config,const char * key,unsigned long def)135 static uint32_t GetNameGroupTypeFromConfig(const cJSON *config, const char *key, unsigned long def)
136 {
137     char *value = cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(config, key));
138     if (value == NULL) {
139         return def;
140     }
141     const SandboxFlagInfo *info = GetSandboxFlagInfo(value, NAME_GROUP_TYPE_MAP, ARRAY_LENGTH(NAME_GROUP_TYPE_MAP));
142     if (info != NULL) {
143         return (uint32_t)info->flags;
144     }
145     return def;
146 }
147 
GetSandboxNsFlags(const cJSON * appConfig)148 static uint32_t GetSandboxNsFlags(const cJSON *appConfig)
149 {
150     uint32_t nsFlags = 0;
151     cJSON *obj = cJSON_GetObjectItemCaseSensitive(appConfig, "sandbox-ns-flags");
152     if (obj == NULL || !cJSON_IsArray(obj)) {
153         return nsFlags;
154     }
155     int count = cJSON_GetArraySize(obj);
156     for (int i = 0; i < count; i++) {
157         char *value = cJSON_GetStringValue(cJSON_GetArrayItem(obj, i));
158         const SandboxFlagInfo *info = GetSandboxFlagInfo(value, NAMESPACE_FLAGS_MAP, ARRAY_LENGTH(NAMESPACE_FLAGS_MAP));
159         if (info != NULL) {
160             nsFlags |= info->flags;
161         }
162     }
163     return nsFlags;
164 }
165 
SetMode(const char * str,void * context)166 static int SetMode(const char *str, void *context)
167 {
168     mode_t *mode = (mode_t *)context;
169     *mode |= GetPathMode(str);
170     return 0;
171 }
172 
GetChmodFromJson(const cJSON * config)173 static mode_t GetChmodFromJson(const cJSON *config)
174 {
175     mode_t mode = 0;
176     char *modeStrs = GetStringFromJsonObj(config, "dest-mode");
177     if (modeStrs == NULL) {
178         return mode;
179     }
180     (void)StringSplit(modeStrs, "|", (void *)&mode, SetMode);
181     return mode;
182 }
183 
GetFlagIndexFromJson(const cJSON * config)184 static uint32_t GetFlagIndexFromJson(const cJSON *config)
185 {
186     char *flagStr = GetStringFromJsonObj(config, "name");
187     if (flagStr == NULL) {
188         return 0;
189     }
190     const SandboxFlagInfo *info = GetSandboxFlagInfo(flagStr, FLAGE_POINT_MAP, ARRAY_LENGTH(FLAGE_POINT_MAP));
191     if (info != NULL) {
192         return info->flags;
193     }
194     return 0;
195 }
196 
FillPathDemandInfo(const cJSON * config,PathMountNode * sandboxNode)197 static void FillPathDemandInfo(const cJSON *config, PathMountNode *sandboxNode)
198 {
199     APPSPAWN_CHECK_ONLY_EXPER(config != NULL, return);
200     sandboxNode->demandInfo->uid = GetIntValueFromJsonObj(config, "uid", -1);
201     sandboxNode->demandInfo->gid = GetIntValueFromJsonObj(config, "gid", -1);
202     sandboxNode->demandInfo->mode = GetIntValueFromJsonObj(config, "ugo", -1);
203 }
204 
DecodeMountPathConfig(const SandboxSection * section,const cJSON * config,uint32_t type)205 static PathMountNode *DecodeMountPathConfig(const SandboxSection *section, const cJSON *config, uint32_t type)
206 {
207     char *srcPath = GetStringFromJsonObj(config, "src-path");
208     char *dstPath = GetStringFromJsonObj(config, "sandbox-path");
209     if (srcPath == NULL || dstPath == NULL) {
210         return NULL;
211     }
212     PathMountNode *tmp = GetPathMountNode(section, type, srcPath, dstPath);
213     if (tmp != NULL) { // 删除老的节点,保存新的节点
214         DeleteSandboxMountNode((SandboxMountNode *)tmp);
215         APPSPAWN_LOGW("path %{public}s %{public}s repeat config, delete old", srcPath, dstPath);
216     }
217 
218     cJSON *demandInfo = cJSON_GetObjectItemCaseSensitive(config, "create-on-demand");
219     PathMountNode *sandboxNode = CreatePathMountNode(type, demandInfo != NULL);
220     APPSPAWN_CHECK_ONLY_EXPER(sandboxNode != NULL, return NULL);
221     sandboxNode->createDemand = demandInfo != NULL;
222     sandboxNode->source = strdup(srcPath);
223     sandboxNode->target = strdup(dstPath);
224 
225     sandboxNode->destMode = GetChmodFromJson(config);
226     sandboxNode->mountSharedFlag = GetBoolValueFromJsonObj(config, "mount-shared-flag", false);
227     sandboxNode->checkErrorFlag = GetBoolValueFromJsonObj(config, "check-action-status", false);
228 
229     sandboxNode->category = GetMountCategory(GetStringFromJsonObj(config, "category"));
230     const char *value = GetStringFromJsonObj(config, "app-apl-name");
231     if (value != NULL) {
232         sandboxNode->appAplName = strdup(value);
233     }
234     FillPathDemandInfo(demandInfo, sandboxNode);
235 
236     if (sandboxNode->source == NULL || sandboxNode->target == NULL) {
237         APPSPAWN_LOGE("Failed to get sourc or target path");
238         DeleteSandboxMountNode((SandboxMountNode *)sandboxNode);
239         return NULL;
240     }
241     return sandboxNode;
242 }
243 
ParseMountPathsConfig(AppSpawnSandboxCfg * sandbox,const cJSON * mountConfigs,SandboxSection * section,uint32_t type)244 static int ParseMountPathsConfig(AppSpawnSandboxCfg *sandbox,
245     const cJSON *mountConfigs, SandboxSection *section, uint32_t type)
246 {
247     APPSPAWN_CHECK_ONLY_EXPER(mountConfigs != NULL && cJSON_IsArray(mountConfigs), return -1);
248 
249     uint32_t mountPointSize = cJSON_GetArraySize(mountConfigs);
250     for (uint32_t i = 0; i < mountPointSize; i++) {
251         cJSON *mntJson = cJSON_GetArrayItem(mountConfigs, i);
252         if (mntJson == NULL) {
253             continue;
254         }
255         PathMountNode *sandboxNode = DecodeMountPathConfig(section, mntJson, type);
256         APPSPAWN_CHECK_ONLY_EXPER(sandboxNode != NULL, continue);
257         AddSandboxMountNode(&sandboxNode->sandboxNode, section);
258     }
259     return 0;
260 }
261 
DecodeSymbolLinksConfig(const SandboxSection * section,const cJSON * config)262 static SymbolLinkNode *DecodeSymbolLinksConfig(const SandboxSection *section, const cJSON *config)
263 {
264     const char *target = GetStringFromJsonObj(config, "target-name");
265     const char *linkName = GetStringFromJsonObj(config, "link-name");
266     if (target == NULL || linkName == NULL) {
267         return NULL;
268     }
269 
270     SymbolLinkNode *tmp = GetSymbolLinkNode(section, target, linkName);
271     if (tmp != NULL) { // 删除老的节点,保存新的节点
272         DeleteSandboxMountNode((SandboxMountNode *)tmp);
273         APPSPAWN_LOGW("SymbolLink %{public}s %{public}s repeat config, delete old", target, linkName);
274     }
275 
276     SymbolLinkNode *node = CreateSymbolLinkNode();
277     APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return NULL);
278     node->destMode = GetChmodFromJson(config);
279     node->checkErrorFlag = GetBoolValueFromJsonObj(config, "check-action-status", false);
280     node->target = strdup(target);
281     node->linkName = strdup(linkName);
282     if (node->target == NULL || node->linkName == NULL) {
283         APPSPAWN_LOGE("Failed to get sourc or target path");
284         DeleteSandboxMountNode((SandboxMountNode *)node);
285         return NULL;
286     }
287     return node;
288 }
289 
ParseSymbolLinksConfig(AppSpawnSandboxCfg * sandbox,const cJSON * symbolLinkConfigs,SandboxSection * section)290 static int ParseSymbolLinksConfig(AppSpawnSandboxCfg *sandbox, const cJSON *symbolLinkConfigs, SandboxSection *section)
291 {
292     APPSPAWN_CHECK_ONLY_EXPER(symbolLinkConfigs != NULL && cJSON_IsArray(symbolLinkConfigs), return -1);
293     uint32_t symlinkPointSize = cJSON_GetArraySize(symbolLinkConfigs);
294     for (uint32_t i = 0; i < symlinkPointSize; i++) {
295         cJSON *symConfig = cJSON_GetArrayItem(symbolLinkConfigs, i);
296         if (symConfig == NULL) {
297             continue;
298         }
299         SymbolLinkNode *node = DecodeSymbolLinksConfig(section, symConfig);
300         APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return -1);
301         AddSandboxMountNode(&node->sandboxNode, section);
302     }
303     return 0;
304 }
305 
ParseGidTableConfig(AppSpawnSandboxCfg * sandbox,const cJSON * configs,SandboxSection * section)306 static int ParseGidTableConfig(AppSpawnSandboxCfg *sandbox, const cJSON *configs, SandboxSection *section)
307 {
308     APPSPAWN_CHECK(cJSON_IsArray(configs), return 0, "json is not array.");
309     uint32_t arrayLen = (uint32_t)cJSON_GetArraySize(configs);
310     APPSPAWN_CHECK_ONLY_EXPER(arrayLen > 0, return 0);
311     APPSPAWN_CHECK(arrayLen < APP_MAX_GIDS, arrayLen = APP_MAX_GIDS, "More gid in gids json.");
312 
313     // 配置存在,以后面的配置为准
314     if (section->gidTable) {
315         free(section->gidTable);
316         section->gidTable = NULL;
317         section->gidCount = 0;
318     }
319     section->gidTable = (gid_t *)calloc(1, sizeof(gid_t) * arrayLen);
320     APPSPAWN_CHECK(section->gidTable != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to alloc memory.");
321 
322     for (uint32_t i = 0; i < arrayLen; i++) {
323         cJSON *item = cJSON_GetArrayItem(configs, i);
324         gid_t gid = 0;
325         if (cJSON_IsNumber(item)) {
326             gid = (gid_t)cJSON_GetNumberValue(item);
327         } else {
328             char *value = cJSON_GetStringValue(item);
329             gid = DecodeGid(value);
330         }
331         if (gid <= 0) {
332             continue;
333         }
334         section->gidTable[section->gidCount++] = gid;
335     }
336     return 0;
337 }
338 
ParseMountGroupsConfig(AppSpawnSandboxCfg * sandbox,const cJSON * groupConfig,SandboxSection * section)339 static int ParseMountGroupsConfig(AppSpawnSandboxCfg *sandbox, const cJSON *groupConfig, SandboxSection *section)
340 {
341     APPSPAWN_CHECK(cJSON_IsArray(groupConfig),
342         return APPSPAWN_SANDBOX_INVALID, "Invalid mount-groups config %{public}s", section->name);
343 
344     // 合并name-group
345     uint32_t count = (uint32_t)cJSON_GetArraySize(groupConfig);
346     APPSPAWN_LOGV("mount-group in section %{public}s  %{public}u", section->name, count);
347     APPSPAWN_CHECK_ONLY_EXPER(count > 0, return 0);
348     count += section->number;
349     SandboxMountNode **nameGroups = (SandboxMountNode **)calloc(1, sizeof(SandboxMountNode *) * count);
350     APPSPAWN_CHECK(nameGroups != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to alloc memory for group name");
351 
352     uint32_t j = 0;
353     uint32_t number = 0;
354     for (j = 0; j < section->number; j++) { // copy old
355         if (section->nameGroups[j] == NULL) {
356             continue;
357         }
358         nameGroups[number++] = section->nameGroups[j];
359     }
360 
361     SandboxNameGroupNode *mountNode = NULL;
362     for (uint32_t i = 0; i < count; i++) {
363         nameGroups[number] = NULL;
364 
365         char *name = cJSON_GetStringValue(cJSON_GetArrayItem(groupConfig, i));
366         mountNode = (SandboxNameGroupNode *)GetSandboxSection(&sandbox->nameGroupsQueue, name);
367         if (mountNode == NULL) {
368             APPSPAWN_LOGE("Can not find name-group %{public}s", name);
369             continue;
370         }
371         // check type
372         if (strcmp(section->name, "system-const") == 0 && mountNode->destType != SANDBOX_TAG_SYSTEM_CONST) {
373             APPSPAWN_LOGE("Invalid name-group %{public}s", name);
374             continue;
375         }
376         // 过滤重复的节点
377         for (j = 0; j < section->number; j++) {
378             if (section->nameGroups[j] != NULL && section->nameGroups[j] == (SandboxMountNode *)mountNode) {
379                 APPSPAWN_LOGE("Name-group %{public}s bas been set", name);
380                 break;
381             }
382         }
383         if (j < section->number) {
384             continue;
385         }
386         nameGroups[number++] = (SandboxMountNode *)mountNode;
387         APPSPAWN_LOGV("Name-group %{public}d %{public}s set", section->number, name);
388     }
389     if (section->nameGroups != NULL) {
390         free(section->nameGroups);
391     }
392     section->nameGroups = nameGroups;
393     section->number = number;
394     APPSPAWN_LOGV("mount-group in section %{public}s  %{public}u", section->name, section->number);
395     return 0;
396 }
397 
ParseBaseConfig(AppSpawnSandboxCfg * sandbox,SandboxSection * section,const cJSON * configs)398 static int ParseBaseConfig(AppSpawnSandboxCfg *sandbox, SandboxSection *section, const cJSON *configs)
399 {
400     APPSPAWN_CHECK_ONLY_EXPER(configs != NULL, return 0);
401     APPSPAWN_CHECK(cJSON_IsObject(configs),
402         return APPSPAWN_SANDBOX_INVALID, "Invalid config %{public}s", section->name);
403     APPSPAWN_LOGV("Parse sandbox %{public}s", section->name);
404     // "sandbox-switch": "ON", default sandbox switch is on
405     section->sandboxSwitch = GetBoolValueFromJsonObj(configs, "sandbox-switch", true);
406     // "sandbox-shared"
407     section->sandboxShared = GetBoolValueFromJsonObj(configs, "sandbox-shared", false);
408 
409     int ret = 0;
410     cJSON *gidTabJson = cJSON_GetObjectItemCaseSensitive(configs, "gids");
411     if (gidTabJson) {
412         ret = ParseGidTableConfig(sandbox, gidTabJson, section);
413         APPSPAWN_CHECK(ret == 0, return ret, "Parse gids for %{public}s", section->name);
414     }
415     cJSON *pathConfigs = cJSON_GetObjectItemCaseSensitive(configs, "mount-paths");
416     if (pathConfigs != NULL) {  // mount-paths
417         ret = ParseMountPathsConfig(sandbox, pathConfigs, section, SANDBOX_TAG_MOUNT_PATH);
418         APPSPAWN_CHECK(ret == 0, return ret, "Parse mount-paths for %{public}s", section->name);
419     }
420     pathConfigs = cJSON_GetObjectItemCaseSensitive(configs, "mount-files");
421     if (pathConfigs != NULL) {  // mount-files
422         ret = ParseMountPathsConfig(sandbox, pathConfigs, section, SANDBOX_TAG_MOUNT_FILE);
423         APPSPAWN_CHECK(ret == 0, return ret, "Parse mount-paths for %{public}s", section->name);
424     }
425     pathConfigs = cJSON_GetObjectItemCaseSensitive(configs, "symbol-links");
426     if (pathConfigs != NULL) {  // symbol-links
427         ret = ParseSymbolLinksConfig(sandbox, pathConfigs, section);
428         APPSPAWN_CHECK(ret == 0, return ret, "Parse symbol-links for %{public}s", section->name);
429     }
430     cJSON *groupConfig = cJSON_GetObjectItemCaseSensitive(configs, "mount-groups");
431     if (groupConfig != NULL) {
432         ret = ParseMountGroupsConfig(sandbox, groupConfig, section);
433         APPSPAWN_CHECK(ret == 0, return ret, "Parse mount-groups for %{public}s", section->name);
434     }
435     return 0;
436 }
437 
ParsePackageNameConfig(AppSpawnSandboxCfg * sandbox,const char * name,const cJSON * packageNameConfigs)438 static int ParsePackageNameConfig(AppSpawnSandboxCfg *sandbox, const char *name, const cJSON *packageNameConfigs)
439 {
440     APPSPAWN_LOGV("Parse package-name config %{public}s", name);
441     SandboxPackageNameNode *node = (SandboxPackageNameNode *)GetSandboxSection(&sandbox->packageNameQueue, name);
442     if (node == NULL) {
443         node = CreateSandboxPackageNameNode(name);
444     }
445     APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return -1);
446 
447     int ret = ParseBaseConfig(sandbox, &node->section, packageNameConfigs);
448     if (ret != 0) {
449         DeleteSandboxSection((SandboxSection *)node);
450         return ret;
451     }
452     // success, insert section
453     AddSandboxSection(&node->section, &sandbox->packageNameQueue);
454     return 0;
455 }
456 
ParseSpawnFlagsConfig(AppSpawnSandboxCfg * sandbox,const char * name,const cJSON * flagsConfig)457 static int ParseSpawnFlagsConfig(AppSpawnSandboxCfg *sandbox, const char *name, const cJSON *flagsConfig)
458 {
459     uint32_t flagIndex = GetFlagIndexFromJson(flagsConfig);
460     APPSPAWN_LOGV("Parse spawn-flags config %{public}s flagIndex %{public}u", name, flagIndex);
461     SandboxFlagsNode *node = (SandboxFlagsNode *)GetSandboxSection(&sandbox->spawnFlagsQueue, name);
462     if (node == NULL) {
463         node = CreateSandboxFlagsNode(name);
464     }
465     APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return -1);
466     node->flagIndex = flagIndex;
467 
468     int ret = ParseBaseConfig(sandbox, &node->section, flagsConfig);
469     if (ret != 0) {
470         DeleteSandboxSection((SandboxSection *)node);
471         return ret;
472     }
473     // success, insert section
474     AddSandboxSection(&node->section, &sandbox->spawnFlagsQueue);
475     return 0;
476 }
477 
ParsePermissionConfig(AppSpawnSandboxCfg * sandbox,const char * name,const cJSON * permissionConfig)478 static int ParsePermissionConfig(AppSpawnSandboxCfg *sandbox, const char *name, const cJSON *permissionConfig)
479 {
480     APPSPAWN_LOGV("Parse permission config %{public}s", name);
481     SandboxPermissionNode *node = (SandboxPermissionNode *)GetSandboxSection(&sandbox->permissionQueue, name);
482     if (node == NULL) {
483         node = CreateSandboxPermissionNode(name);
484     }
485     APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return -1);
486 
487     int ret = ParseBaseConfig(sandbox, &node->section, permissionConfig);
488     if (ret != 0) {
489         DeleteSandboxSection((SandboxSection *)node);
490         return ret;
491     }
492     // success, insert section
493     AddSandboxSection(&node->section, &sandbox->permissionQueue);
494     return 0;
495 }
496 
ParseNameGroup(AppSpawnSandboxCfg * sandbox,const cJSON * groupConfig)497 static SandboxNameGroupNode *ParseNameGroup(AppSpawnSandboxCfg *sandbox, const cJSON *groupConfig)
498 {
499     char *name = GetStringFromJsonObj(groupConfig, "name");
500     APPSPAWN_CHECK(name != NULL, return NULL, "No name in name group config");
501     APPSPAWN_LOGV("Parse name-group config %{public}s", name);
502     SandboxNameGroupNode *node = (SandboxNameGroupNode *)GetSandboxSection(&sandbox->nameGroupsQueue, name);
503     if (node == NULL) {
504         node = CreateSandboxNameGroupNode(name);
505     }
506     APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return NULL);
507 
508     cJSON *obj = cJSON_GetObjectItemCaseSensitive(groupConfig, "mount-paths-deps");
509     if (obj) {
510         if (node->depNode) { // free repeat
511             DeleteSandboxMountNode((SandboxMountNode *)node->depNode);
512         }
513         node->depNode = DecodeMountPathConfig(NULL, obj, SANDBOX_TAG_MOUNT_PATH);
514         if (node->depNode == NULL) {
515             DeleteSandboxSection((SandboxSection *)node);
516             return NULL;
517         }
518         // "deps-mode": "not-exists"
519         node->depMode = GetMountModeFromConfig(groupConfig, "deps-mode", MOUNT_MODE_ALWAYS);
520     }
521 
522     int ret = ParseBaseConfig(sandbox, &node->section, groupConfig);
523     if (ret != 0) {
524         DeleteSandboxSection((SandboxSection *)node);
525         return NULL;
526     }
527     // "type": "system-const",
528     // "caps": ["shared"],
529     node->destType = GetNameGroupTypeFromConfig(groupConfig, "type", SANDBOX_TAG_INVALID);
530     // success, insert section
531     AddSandboxSection(&node->section, &sandbox->nameGroupsQueue);
532     return node;
533 }
534 
ParseNameGroupsConfig(AppSpawnSandboxCfg * sandbox,const cJSON * root)535 static int ParseNameGroupsConfig(AppSpawnSandboxCfg *sandbox, const cJSON *root)
536 {
537     APPSPAWN_CHECK(root != NULL, return APPSPAWN_SANDBOX_INVALID, "Invalid config ");
538     cJSON *configs = cJSON_GetObjectItemCaseSensitive(root, "name-groups");
539     APPSPAWN_CHECK_ONLY_EXPER(configs != NULL, return 0);
540     APPSPAWN_CHECK(cJSON_IsArray(configs), return APPSPAWN_SANDBOX_INVALID, "Invalid config ");
541     int count = cJSON_GetArraySize(configs);
542     APPSPAWN_CHECK_ONLY_EXPER(count > 0, return 0);
543 
544     sandbox->depNodeCount = 0;
545     for (int i = 0; i < count; i++) {
546         cJSON *json = cJSON_GetArrayItem(configs, i);
547         if (json == NULL) {
548             continue;
549         }
550         SandboxNameGroupNode *node = ParseNameGroup(sandbox, json);
551         APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return APPSPAWN_SANDBOX_INVALID);
552         if (node->depNode) {
553             sandbox->depNodeCount++;
554         }
555     }
556     APPSPAWN_LOGV("ParseNameGroupsConfig depNodeCount %{public}d", sandbox->depNodeCount);
557     return 0;
558 }
559 
ParseConditionalConfig(AppSpawnSandboxCfg * sandbox,const cJSON * configs,const char * configName,int (* parseConfig)(AppSpawnSandboxCfg * sandbox,const char * name,const cJSON * configs))560 static int ParseConditionalConfig(AppSpawnSandboxCfg *sandbox, const cJSON *configs, const char *configName,
561     int (*parseConfig)(AppSpawnSandboxCfg *sandbox, const char *name, const cJSON *configs))
562 {
563     APPSPAWN_CHECK_ONLY_EXPER(configs != NULL, return 0);
564     APPSPAWN_CHECK(cJSON_IsArray(configs),
565         return APPSPAWN_SANDBOX_INVALID, "Invalid config %{public}s", configName);
566     int ret = 0;
567     int count = cJSON_GetArraySize(configs);
568     for (int i = 0; i < count; i++) {
569         cJSON *json = cJSON_GetArrayItem(configs, i);
570         if (json == NULL) {
571             continue;
572         }
573         char *name = GetStringFromJsonObj(json, "name");
574         if (name == NULL) {
575             APPSPAWN_LOGE("No name in %{public}s configs", configName);
576             continue;
577         }
578         ret = parseConfig(sandbox, name, json);
579         APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
580     }
581     return 0;
582 }
583 
ParseGlobalSandboxConfig(AppSpawnSandboxCfg * sandbox,const cJSON * root)584 static int ParseGlobalSandboxConfig(AppSpawnSandboxCfg *sandbox, const cJSON *root)
585 {
586     cJSON *json = cJSON_GetObjectItemCaseSensitive(root, "global");
587     if (json) {
588         sandbox->sandboxNsFlags = GetSandboxNsFlags(json);
589         char *rootPath = GetStringFromJsonObj(json, "sandbox-root");
590         APPSPAWN_CHECK(rootPath != NULL, return APPSPAWN_SYSTEM_ERROR, "No root path in config");
591         if (sandbox->rootPath) {
592             free(sandbox->rootPath);
593         }
594         sandbox->rootPath = strdup(rootPath);
595         APPSPAWN_CHECK(sandbox->rootPath != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to copy root path");
596         sandbox->topSandboxSwitch = GetBoolValueFromJsonObj(json, "top-sandbox-switch", true);
597     }
598     return 0;
599 }
600 
601 typedef struct TagParseJsonContext {
602     AppSpawnSandboxCfg *sandboxCfg;
603 }ParseJsonContext;
604 
ParseAppSandboxConfig(const cJSON * root,ParseJsonContext * context)605 APPSPAWN_STATIC int ParseAppSandboxConfig(const cJSON *root, ParseJsonContext *context)
606 {
607     APPSPAWN_CHECK(root != NULL && context != NULL && context->sandboxCfg != NULL,
608         return APPSPAWN_SYSTEM_ERROR, "Invalid json");
609     AppSpawnSandboxCfg *sandbox = context->sandboxCfg;
610     int ret = ParseGlobalSandboxConfig(sandbox, root);  // "global":
611     APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return APPSPAWN_SANDBOX_INVALID);
612     ret = ParseNameGroupsConfig(sandbox, root);  // name-groups
613     APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return APPSPAWN_SANDBOX_INVALID);
614 
615     // "required"
616     cJSON *required = cJSON_GetObjectItemCaseSensitive(root, "required");
617     if (required) {
618         cJSON *config = NULL;
619         cJSON_ArrayForEach(config, required)
620         {
621             APPSPAWN_LOGI("Sandbox required config: %{public}s", config->string);
622             SandboxSection *section = GetSandboxSection(&sandbox->requiredQueue, config->string);
623             if (section == NULL) {
624                 section = CreateSandboxSection(config->string, sizeof(SandboxSection), SANDBOX_TAG_REQUIRED);
625             }
626             APPSPAWN_CHECK_ONLY_EXPER(section != NULL, return -1);
627 
628             ret = ParseBaseConfig(sandbox, section, config);
629             if (ret != 0) {
630                 DeleteSandboxSection(section);
631                 return ret;
632             }
633             // success, insert section
634             AddSandboxSection(section, &sandbox->requiredQueue);
635         }
636     }
637 
638     // conditional
639     cJSON *json = cJSON_GetObjectItemCaseSensitive(root, "conditional");
640     if (json != NULL) {
641         // permission
642         cJSON *config = cJSON_GetObjectItemCaseSensitive(json, "permission");
643         ret = ParseConditionalConfig(sandbox, config, "permission", ParsePermissionConfig);
644         APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
645         // spawn-flag
646         config = cJSON_GetObjectItemCaseSensitive(json, "spawn-flag");
647         ret = ParseConditionalConfig(sandbox, config, "spawn-flag", ParseSpawnFlagsConfig);
648         APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
649         // package-name
650         config = cJSON_GetObjectItemCaseSensitive(json, "package-name");
651         ret = ParseConditionalConfig(sandbox, config, "package-name", ParsePackageNameConfig);
652         APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
653     }
654     return ret;
655 }
656 
GetSandboxNameByMode(RunMode mode)657 APPSPAWN_STATIC const char *GetSandboxNameByMode(RunMode mode)
658 {
659     if (mode == MODE_FOR_NATIVE_SPAWN) {
660         return ISOLATED_SANDBOX_FILE_NAME;
661     }
662 
663     return APP_SANDBOX_FILE_NAME;
664 }
665 
LoadAppSandboxConfig(AppSpawnSandboxCfg * sandbox,RunMode mode)666 int LoadAppSandboxConfig(AppSpawnSandboxCfg *sandbox, RunMode mode)
667 {
668     APPSPAWN_CHECK_ONLY_EXPER(sandbox != NULL, return APPSPAWN_ARG_INVALID);
669     const char *sandboxName = GetSandboxNameByMode(mode);
670     if (sandbox->depGroupNodes != NULL) {
671         APPSPAWN_LOGW("Sandbox has been load");
672         return 0;
673     }
674     ParseJsonContext context = {};
675     context.sandboxCfg = sandbox;
676     int ret = ParseJsonConfig("etc/sandbox", sandboxName, ParseAppSandboxConfig, &context);
677     if (ret == APPSPAWN_SANDBOX_NONE) {
678         APPSPAWN_LOGW("No sandbox config");
679         ret = 0;
680     }
681     APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
682     sandbox->pidNamespaceSupport = AppSandboxPidNsIsSupport();
683     sandbox->appFullMountEnable = CheckAppFullMountEnable();
684     APPSPAWN_LOGI("Sandbox pidNamespaceSupport: %{public}d appFullMountEnable: %{public}d",
685         sandbox->pidNamespaceSupport, sandbox->appFullMountEnable);
686 
687     uint32_t depNodeCount = sandbox->depNodeCount;
688     APPSPAWN_CHECK_ONLY_EXPER(depNodeCount > 0, return ret);
689 
690     sandbox->depGroupNodes = (SandboxNameGroupNode **)calloc(1, sizeof(SandboxNameGroupNode *) * depNodeCount);
691     APPSPAWN_CHECK(sandbox->depGroupNodes != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed alloc memory ");
692     sandbox->depNodeCount = 0;
693     ListNode *node = sandbox->nameGroupsQueue.front.next;
694     while (node != &sandbox->nameGroupsQueue.front) {
695         SandboxNameGroupNode *groupNode = (SandboxNameGroupNode *)ListEntry(node, SandboxMountNode, node);
696         if (groupNode->depNode) {
697             sandbox->depGroupNodes[sandbox->depNodeCount++] = groupNode;
698         }
699         node = node->next;
700     }
701     APPSPAWN_LOGI("LoadAppSandboxConfig depNodeCount %{public}d", sandbox->depNodeCount);
702 
703     return 0;
704 }
705