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 {"PREINSTALLED_HAP", (unsigned long)APP_FLAGS_PRE_INSTALLED_HAP},
50 {"CUSTOM_SANDBOX_HAP", (unsigned long)APP_FLAGS_CUSTOM_SANDBOX}
51 };
52
53 static const SandboxFlagInfo MOUNT_MODE_MAP[] = {
54 {"not-exists", (unsigned long)MOUNT_MODE_NOT_EXIST},
55 {"always", (unsigned long)MOUNT_MODE_ALWAYS}
56 };
57
58 static const SandboxFlagInfo NAME_GROUP_TYPE_MAP[] = {
59 {"system-const", (unsigned long)SANDBOX_TAG_SYSTEM_CONST},
60 {"app-variable", (unsigned long)SANDBOX_TAG_APP_VARIABLE}
61 };
62
CreatePathMountNode(uint32_t type,uint32_t hasDemandInfo)63 static inline PathMountNode *CreatePathMountNode(uint32_t type, uint32_t hasDemandInfo)
64 {
65 uint32_t len = hasDemandInfo ? sizeof(PathDemandInfo) : 0;
66 return (PathMountNode *)CreateSandboxMountNode(sizeof(PathMountNode) + len, type);
67 }
68
CreateSymbolLinkNode(void)69 static inline SymbolLinkNode *CreateSymbolLinkNode(void)
70 {
71 return (SymbolLinkNode *)CreateSandboxMountNode(sizeof(SymbolLinkNode), SANDBOX_TAG_SYMLINK);
72 }
73
CreateSandboxPackageNameNode(const char * name)74 static inline SandboxPackageNameNode *CreateSandboxPackageNameNode(const char *name)
75 {
76 return (SandboxPackageNameNode *)CreateSandboxSection(name,
77 sizeof(SandboxPackageNameNode), SANDBOX_TAG_PACKAGE_NAME);
78 }
79
CreateSandboxFlagsNode(const char * name)80 static inline SandboxFlagsNode *CreateSandboxFlagsNode(const char *name)
81 {
82 return (SandboxFlagsNode *)CreateSandboxSection(name, sizeof(SandboxFlagsNode), SANDBOX_TAG_SPAWN_FLAGS);
83 }
84
CreateSandboxNameGroupNode(const char * name)85 static inline SandboxNameGroupNode *CreateSandboxNameGroupNode(const char *name)
86 {
87 return (SandboxNameGroupNode *)CreateSandboxSection(name, sizeof(SandboxNameGroupNode), SANDBOX_TAG_NAME_GROUP);
88 }
89
CreateSandboxPermissionNode(const char * name)90 static inline SandboxPermissionNode *CreateSandboxPermissionNode(const char *name)
91 {
92 size_t len = sizeof(SandboxPermissionNode);
93 SandboxPermissionNode *node = (SandboxPermissionNode *)CreateSandboxSection(name, len, SANDBOX_TAG_PERMISSION);
94 APPSPAWN_CHECK(node != NULL, return NULL, "Failed to create permission node");
95 node->permissionIndex = 0;
96 return node;
97 }
98
GetBoolParameter(const char * param,bool value)99 static inline bool GetBoolParameter(const char *param, bool value)
100 {
101 char tmp[32] = {0}; // 32 max
102 int ret = GetParameter(param, "", tmp, sizeof(tmp));
103 APPSPAWN_LOGV("GetBoolParameter key %{public}s ret %{public}d result: %{public}s", param, ret, tmp);
104 if (ret > 0 && strcmp(tmp, "false") == 0) {
105 return false;
106 }
107 if (ret > 0 && strcmp(tmp, "true") == 0) {
108 return true;
109 }
110 return value;
111 }
112
AppSandboxPidNsIsSupport(void)113 static inline bool AppSandboxPidNsIsSupport(void)
114 {
115 // only set false, return false
116 return GetBoolParameter("const.sandbox.pidns.support", true);
117 }
118
CheckAppFullMountEnable(void)119 static inline bool CheckAppFullMountEnable(void)
120 {
121 return GetBoolParameter("const.filemanager.full_mount.enable", false);
122 }
123
GetMountModeFromConfig(const cJSON * config,const char * key,unsigned long def)124 APPSPAWN_STATIC unsigned long GetMountModeFromConfig(const cJSON *config, const char *key, unsigned long def)
125 {
126 char *value = cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(config, key));
127 if (value == NULL) {
128 return def;
129 }
130 const SandboxFlagInfo *info = GetSandboxFlagInfo(value, MOUNT_MODE_MAP, ARRAY_LENGTH(MOUNT_MODE_MAP));
131 if (info != NULL) {
132 return info->flags;
133 }
134 return def;
135 }
136
GetNameGroupTypeFromConfig(const cJSON * config,const char * key,unsigned long def)137 static uint32_t GetNameGroupTypeFromConfig(const cJSON *config, const char *key, unsigned long def)
138 {
139 char *value = cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(config, key));
140 if (value == NULL) {
141 return def;
142 }
143 const SandboxFlagInfo *info = GetSandboxFlagInfo(value, NAME_GROUP_TYPE_MAP, ARRAY_LENGTH(NAME_GROUP_TYPE_MAP));
144 if (info != NULL) {
145 return (uint32_t)info->flags;
146 }
147 return def;
148 }
149
GetSandboxNsFlags(const cJSON * appConfig)150 static uint32_t GetSandboxNsFlags(const cJSON *appConfig)
151 {
152 uint32_t nsFlags = 0;
153 cJSON *obj = cJSON_GetObjectItemCaseSensitive(appConfig, "sandbox-ns-flags");
154 if (obj == NULL || !cJSON_IsArray(obj)) {
155 return nsFlags;
156 }
157 int count = cJSON_GetArraySize(obj);
158 for (int i = 0; i < count; i++) {
159 char *value = cJSON_GetStringValue(cJSON_GetArrayItem(obj, i));
160 const SandboxFlagInfo *info = GetSandboxFlagInfo(value, NAMESPACE_FLAGS_MAP, ARRAY_LENGTH(NAMESPACE_FLAGS_MAP));
161 if (info != NULL) {
162 nsFlags |= info->flags;
163 }
164 }
165 return nsFlags;
166 }
167
SetMode(const char * str,void * context)168 static int SetMode(const char *str, void *context)
169 {
170 mode_t *mode = (mode_t *)context;
171 *mode |= GetPathMode(str);
172 return 0;
173 }
174
GetChmodFromJson(const cJSON * config)175 static mode_t GetChmodFromJson(const cJSON *config)
176 {
177 mode_t mode = 0;
178 char *modeStrs = GetStringFromJsonObj(config, "dest-mode");
179 if (modeStrs == NULL) {
180 return mode;
181 }
182 (void)StringSplit(modeStrs, "|", (void *)&mode, SetMode);
183 return mode;
184 }
185
GetFlagIndexFromJson(const cJSON * config)186 APPSPAWN_STATIC uint32_t GetFlagIndexFromJson(const cJSON *config)
187 {
188 char *flagStr = GetStringFromJsonObj(config, "name");
189 if (flagStr == NULL) {
190 return 0;
191 }
192 const SandboxFlagInfo *info = GetSandboxFlagInfo(flagStr, FLAGE_POINT_MAP, ARRAY_LENGTH(FLAGE_POINT_MAP));
193 if (info != NULL) {
194 return info->flags;
195 }
196 return 0;
197 }
198
FillPathDemandInfo(const cJSON * config,PathMountNode * sandboxNode)199 static void FillPathDemandInfo(const cJSON *config, PathMountNode *sandboxNode)
200 {
201 APPSPAWN_CHECK_ONLY_EXPER(config != NULL, return);
202 sandboxNode->demandInfo->uid = GetIntValueFromJsonObj(config, "uid", -1);
203 sandboxNode->demandInfo->gid = GetIntValueFromJsonObj(config, "gid", -1);
204 sandboxNode->demandInfo->mode = GetIntValueFromJsonObj(config, "ugo", -1);
205 }
206
DecodeDecPolicyPaths(const cJSON * config,PathMountNode * sandboxNode)207 static int32_t DecodeDecPolicyPaths(const cJSON *config, PathMountNode *sandboxNode)
208 {
209 if (config == NULL || sandboxNode == NULL) {
210 return APPSPAWN_ARG_INVALID;
211 }
212
213 sandboxNode->decPolicyPaths.decPathCount = 0;
214 sandboxNode->decPolicyPaths.decPath = NULL;
215
216 cJSON *pathArray = cJSON_GetObjectItemCaseSensitive(config, "dec-paths");
217 if (pathArray == NULL || !cJSON_IsArray(pathArray)) {
218 return 0;
219 }
220
221 int pathCount = cJSON_GetArraySize(pathArray);
222 if (pathCount == 0) {
223 return 0;
224 }
225 size_t decPathSize = pathCount * sizeof(char *);
226 sandboxNode->decPolicyPaths.decPath = (char **)malloc(decPathSize);
227 if (sandboxNode->decPolicyPaths.decPath == NULL) {
228 return APPSPAWN_ERROR_UTILS_MEM_FAIL;
229 }
230
231 for (int i = 0; i < pathCount; i++) {
232 cJSON *pathItem = cJSON_GetArrayItem(pathArray, i);
233 if (!cJSON_IsString(pathItem)) {
234 APPSPAWN_LOGE("path parse failed");
235 goto ERROR;
236 }
237 sandboxNode->decPolicyPaths.decPath[i] = strdup(pathItem->valuestring);
238 if (sandboxNode->decPolicyPaths.decPath[i] == NULL) {
239 goto ERROR;
240 }
241 sandboxNode->decPolicyPaths.decPathCount++;
242 }
243 return 0;
244
245 ERROR:
246 for (int i = 0; i < pathCount; i++) {
247 if (sandboxNode->decPolicyPaths.decPath[i] != NULL) {
248 free(sandboxNode->decPolicyPaths.decPath[i]);
249 sandboxNode->decPolicyPaths.decPath[i] = NULL;
250 }
251 }
252 sandboxNode->decPolicyPaths.decPathCount = 0;
253 free(sandboxNode->decPolicyPaths.decPath);
254 sandboxNode->decPolicyPaths.decPath = NULL;
255 return -1;
256 }
257
DecodeMountPathConfig(const SandboxSection * section,const cJSON * config,uint32_t type)258 static PathMountNode *DecodeMountPathConfig(const SandboxSection *section, const cJSON *config, uint32_t type)
259 {
260 char *srcPath = GetStringFromJsonObj(config, "src-path");
261 char *dstPath = GetStringFromJsonObj(config, "sandbox-path");
262 if (srcPath == NULL || dstPath == NULL) {
263 return NULL;
264 }
265
266 PathMountNode *tmp = GetPathMountNode(section, type, srcPath, dstPath);
267 if (tmp != NULL) { // 删除老的节点,保存新的节点
268 DeleteSandboxMountNode((SandboxMountNode *)tmp);
269 APPSPAWN_LOGW("path %{public}s %{public}s repeat config, delete old", srcPath, dstPath);
270 }
271
272 cJSON *demandInfo = cJSON_GetObjectItemCaseSensitive(config, "create-on-demand");
273 PathMountNode *sandboxNode = CreatePathMountNode(type, demandInfo != NULL);
274 APPSPAWN_CHECK_ONLY_EXPER(sandboxNode != NULL, return NULL);
275 sandboxNode->createDemand = demandInfo != NULL;
276 sandboxNode->source = strdup(srcPath);
277 sandboxNode->target = strdup(dstPath);
278
279 sandboxNode->destMode = GetChmodFromJson(config);
280 sandboxNode->mountSharedFlag = GetBoolValueFromJsonObj(config, "mount-shared-flag", false);
281 sandboxNode->checkErrorFlag = GetBoolValueFromJsonObj(config, "check-action-status", false);
282 sandboxNode->createSandboxPath = GetBoolValueFromJsonObj(config, "create-sandbox-path", true);
283 sandboxNode->category = GetMountCategory(GetStringFromJsonObj(config, "category"));
284 const char *value = GetStringFromJsonObj(config, "app-apl-name");
285 if (value != NULL) {
286 sandboxNode->appAplName = strdup(value);
287 }
288 FillPathDemandInfo(demandInfo, sandboxNode);
289
290 int ret = DecodeDecPolicyPaths(config, sandboxNode);
291 if (ret != 0) {
292 APPSPAWN_LOGE("DecodeDecPolicyPaths failed %{public}d", ret);
293 }
294
295 if (sandboxNode->source == NULL || sandboxNode->target == NULL) {
296 APPSPAWN_LOGE("Failed to get sourc or target path");
297 DeleteSandboxMountNode((SandboxMountNode *)sandboxNode);
298 return NULL;
299 }
300 return sandboxNode;
301 }
302
ParseMountPathsConfig(AppSpawnSandboxCfg * sandbox,const cJSON * mountConfigs,SandboxSection * section,uint32_t type)303 APPSPAWN_STATIC int ParseMountPathsConfig(AppSpawnSandboxCfg *sandbox,
304 const cJSON *mountConfigs, SandboxSection *section, uint32_t type)
305 {
306 APPSPAWN_CHECK_ONLY_EXPER(mountConfigs != NULL && cJSON_IsArray(mountConfigs), return -1);
307
308 uint32_t mountPointSize = cJSON_GetArraySize(mountConfigs);
309 for (uint32_t i = 0; i < mountPointSize; i++) {
310 cJSON *mntJson = cJSON_GetArrayItem(mountConfigs, i);
311 if (mntJson == NULL) {
312 continue;
313 }
314 PathMountNode *sandboxNode = DecodeMountPathConfig(section, mntJson, type);
315 APPSPAWN_CHECK_ONLY_EXPER(sandboxNode != NULL, continue);
316 AddSandboxMountNode(&sandboxNode->sandboxNode, section);
317 }
318 return 0;
319 }
320
DecodeSymbolLinksConfig(const SandboxSection * section,const cJSON * config)321 static SymbolLinkNode *DecodeSymbolLinksConfig(const SandboxSection *section, const cJSON *config)
322 {
323 const char *target = GetStringFromJsonObj(config, "target-name");
324 const char *linkName = GetStringFromJsonObj(config, "link-name");
325 if (target == NULL || linkName == NULL) {
326 return NULL;
327 }
328
329 SymbolLinkNode *tmp = GetSymbolLinkNode(section, target, linkName);
330 if (tmp != NULL) { // 删除老的节点,保存新的节点
331 DeleteSandboxMountNode((SandboxMountNode *)tmp);
332 APPSPAWN_LOGW("SymbolLink %{public}s %{public}s repeat config, delete old", target, linkName);
333 }
334
335 SymbolLinkNode *node = CreateSymbolLinkNode();
336 APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return NULL);
337 node->destMode = GetChmodFromJson(config);
338 node->checkErrorFlag = GetBoolValueFromJsonObj(config, "check-action-status", false);
339 node->target = strdup(target);
340 node->linkName = strdup(linkName);
341 if (node->target == NULL || node->linkName == NULL) {
342 APPSPAWN_LOGE("Failed to get sourc or target path");
343 DeleteSandboxMountNode((SandboxMountNode *)node);
344 return NULL;
345 }
346 return node;
347 }
348
ParseSymbolLinksConfig(AppSpawnSandboxCfg * sandbox,const cJSON * symbolLinkConfigs,SandboxSection * section)349 APPSPAWN_STATIC int ParseSymbolLinksConfig(AppSpawnSandboxCfg *sandbox, const cJSON *symbolLinkConfigs,
350 SandboxSection *section)
351 {
352 APPSPAWN_CHECK_ONLY_EXPER(symbolLinkConfigs != NULL && cJSON_IsArray(symbolLinkConfigs), return -1);
353 uint32_t symlinkPointSize = cJSON_GetArraySize(symbolLinkConfigs);
354 for (uint32_t i = 0; i < symlinkPointSize; i++) {
355 cJSON *symConfig = cJSON_GetArrayItem(symbolLinkConfigs, i);
356 if (symConfig == NULL) {
357 continue;
358 }
359 SymbolLinkNode *node = DecodeSymbolLinksConfig(section, symConfig);
360 APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return -1);
361 AddSandboxMountNode(&node->sandboxNode, section);
362 }
363 return 0;
364 }
365
ParseGidTableConfig(AppSpawnSandboxCfg * sandbox,const cJSON * configs,SandboxSection * section)366 APPSPAWN_STATIC int ParseGidTableConfig(AppSpawnSandboxCfg *sandbox, const cJSON *configs, SandboxSection *section)
367 {
368 APPSPAWN_CHECK_LOGV(cJSON_IsArray(configs), return 0, "json is not array.");
369 uint32_t arrayLen = (uint32_t)cJSON_GetArraySize(configs);
370 APPSPAWN_CHECK_ONLY_EXPER(arrayLen > 0, return 0);
371 APPSPAWN_CHECK(arrayLen < APP_MAX_GIDS, arrayLen = APP_MAX_GIDS, "More gid in gids json.");
372
373 // 配置存在,以后面的配置为准
374 if (section->gidTable) {
375 free(section->gidTable);
376 section->gidTable = NULL;
377 section->gidCount = 0;
378 }
379 section->gidTable = (gid_t *)calloc(1, sizeof(gid_t) * arrayLen);
380 APPSPAWN_CHECK(section->gidTable != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to alloc memory.");
381
382 for (uint32_t i = 0; i < arrayLen; i++) {
383 cJSON *item = cJSON_GetArrayItem(configs, i);
384 gid_t gid = 0;
385 if (cJSON_IsNumber(item)) {
386 gid = (gid_t)cJSON_GetNumberValue(item);
387 } else {
388 char *value = cJSON_GetStringValue(item);
389 gid = DecodeGid(value);
390 }
391 if (gid <= 0) {
392 continue;
393 }
394 section->gidTable[section->gidCount++] = gid;
395 }
396 return 0;
397 }
398
ParseMountGroupsConfig(AppSpawnSandboxCfg * sandbox,const cJSON * groupConfig,SandboxSection * section)399 static int ParseMountGroupsConfig(AppSpawnSandboxCfg *sandbox, const cJSON *groupConfig, SandboxSection *section)
400 {
401 APPSPAWN_CHECK(cJSON_IsArray(groupConfig),
402 return APPSPAWN_SANDBOX_INVALID, "Invalid mount-groups config %{public}s", section->name);
403
404 // 合并name-group
405 uint32_t count = (uint32_t)cJSON_GetArraySize(groupConfig);
406 APPSPAWN_LOGV("mount-group in section %{public}s %{public}u", section->name, count);
407 APPSPAWN_CHECK_ONLY_EXPER(count > 0, return 0);
408 count += section->number;
409 SandboxMountNode **nameGroups = (SandboxMountNode **)calloc(1, sizeof(SandboxMountNode *) * count);
410 APPSPAWN_CHECK(nameGroups != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to alloc memory for group name");
411
412 uint32_t j = 0;
413 uint32_t number = 0;
414 for (j = 0; j < section->number; j++) { // copy old
415 if (section->nameGroups[j] == NULL) {
416 continue;
417 }
418 nameGroups[number++] = section->nameGroups[j];
419 }
420
421 SandboxNameGroupNode *mountNode = NULL;
422 for (uint32_t i = 0; i < count; i++) {
423 nameGroups[number] = NULL;
424
425 char *name = cJSON_GetStringValue(cJSON_GetArrayItem(groupConfig, i));
426 mountNode = (SandboxNameGroupNode *)GetSandboxSection(&sandbox->nameGroupsQueue, name);
427 if (mountNode == NULL) {
428 APPSPAWN_LOGE("Can not find name-group %{public}s", name);
429 continue;
430 }
431 // check type
432 if (strcmp(section->name, "system-const") == 0 && mountNode->destType != SANDBOX_TAG_SYSTEM_CONST) {
433 APPSPAWN_LOGE("Invalid name-group %{public}s", name);
434 continue;
435 }
436 // 过滤重复的节点
437 for (j = 0; j < section->number; j++) {
438 if (section->nameGroups[j] != NULL && section->nameGroups[j] == (SandboxMountNode *)mountNode) {
439 APPSPAWN_LOGE("Name-group %{public}s bas been set", name);
440 break;
441 }
442 }
443 if (j < section->number) {
444 continue;
445 }
446 nameGroups[number++] = (SandboxMountNode *)mountNode;
447 APPSPAWN_LOGV("Name-group %{public}d %{public}s set", section->number, name);
448 }
449 if (section->nameGroups != NULL) {
450 free(section->nameGroups);
451 }
452 section->nameGroups = nameGroups;
453 section->number = number;
454 APPSPAWN_LOGV("mount-group in section %{public}s %{public}u", section->name, section->number);
455 return 0;
456 }
457
ParseBaseConfig(AppSpawnSandboxCfg * sandbox,SandboxSection * section,const cJSON * configs)458 static int ParseBaseConfig(AppSpawnSandboxCfg *sandbox, SandboxSection *section, const cJSON *configs)
459 {
460 APPSPAWN_CHECK_ONLY_EXPER(configs != NULL, return 0);
461 APPSPAWN_CHECK(cJSON_IsObject(configs),
462 return APPSPAWN_SANDBOX_INVALID, "Invalid config %{public}s", section->name);
463 APPSPAWN_LOGV("Parse sandbox %{public}s", section->name);
464
465 // "sandbox-switch": "ON", default sandbox switch is on
466 section->sandboxSwitch = GetBoolValueFromJsonObj(configs, "sandbox-switch", true);
467 // "sandbox-shared"
468 section->sandboxShared = GetBoolValueFromJsonObj(configs, "sandbox-shared", false);
469
470 int ret = 0;
471 cJSON *gidTabJson = cJSON_GetObjectItemCaseSensitive(configs, "gids");
472 if (gidTabJson) {
473 ret = ParseGidTableConfig(sandbox, gidTabJson, section);
474 APPSPAWN_CHECK(ret == 0, return ret, "Parse gids for %{public}s", section->name);
475 }
476
477 cJSON *pathConfigs = cJSON_GetObjectItemCaseSensitive(configs, "mount-paths");
478 if (pathConfigs != NULL) { // mount-paths
479 ret = ParseMountPathsConfig(sandbox, pathConfigs, section, SANDBOX_TAG_MOUNT_PATH);
480 APPSPAWN_CHECK(ret == 0, return ret, "Parse mount-paths for %{public}s", section->name);
481 }
482
483 pathConfigs = cJSON_GetObjectItemCaseSensitive(configs, "mount-files");
484 if (pathConfigs != NULL) { // mount-files
485 ret = ParseMountPathsConfig(sandbox, pathConfigs, section, SANDBOX_TAG_MOUNT_FILE);
486 APPSPAWN_CHECK(ret == 0, return ret, "Parse mount-paths for %{public}s", section->name);
487 }
488
489 pathConfigs = cJSON_GetObjectItemCaseSensitive(configs, "symbol-links");
490 if (pathConfigs != NULL) { // symbol-links
491 ret = ParseSymbolLinksConfig(sandbox, pathConfigs, section);
492 APPSPAWN_CHECK(ret == 0, return ret, "Parse symbol-links for %{public}s", section->name);
493 }
494
495 cJSON *groupConfig = cJSON_GetObjectItemCaseSensitive(configs, "mount-groups");
496 if (groupConfig != NULL) {
497 ret = ParseMountGroupsConfig(sandbox, groupConfig, section);
498 APPSPAWN_CHECK(ret == 0, return ret, "Parse mount-groups for %{public}s", section->name);
499 }
500 return 0;
501 }
502
ParsePackageNameConfig(AppSpawnSandboxCfg * sandbox,const char * name,const cJSON * packageNameConfigs)503 static int ParsePackageNameConfig(AppSpawnSandboxCfg *sandbox, const char *name, const cJSON *packageNameConfigs)
504 {
505 APPSPAWN_LOGV("Parse package-name config %{public}s", name);
506 SandboxPackageNameNode *node = (SandboxPackageNameNode *)GetSandboxSection(&sandbox->packageNameQueue, name);
507 if (node == NULL) {
508 node = CreateSandboxPackageNameNode(name);
509 }
510 APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return -1);
511
512 int ret = ParseBaseConfig(sandbox, &node->section, packageNameConfigs);
513 if (ret != 0) {
514 DeleteSandboxSection((SandboxSection *)node);
515 return ret;
516 }
517 // success, insert section
518 AddSandboxSection(&node->section, &sandbox->packageNameQueue);
519 return 0;
520 }
521
ParseSpawnFlagsConfig(AppSpawnSandboxCfg * sandbox,const char * name,const cJSON * flagsConfig)522 static int ParseSpawnFlagsConfig(AppSpawnSandboxCfg *sandbox, const char *name, const cJSON *flagsConfig)
523 {
524 uint32_t flagIndex = GetFlagIndexFromJson(flagsConfig);
525 APPSPAWN_LOGV("Parse spawn-flags config %{public}s flagIndex %{public}u", name, flagIndex);
526 SandboxFlagsNode *node = (SandboxFlagsNode *)GetSandboxSection(&sandbox->spawnFlagsQueue, name);
527 if (node == NULL) {
528 node = CreateSandboxFlagsNode(name);
529 }
530 APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return -1);
531 node->flagIndex = flagIndex;
532
533 int ret = ParseBaseConfig(sandbox, &node->section, flagsConfig);
534 if (ret != 0) {
535 DeleteSandboxSection((SandboxSection *)node);
536 return ret;
537 }
538 // success, insert section
539 AddSandboxSection(&node->section, &sandbox->spawnFlagsQueue);
540 return 0;
541 }
542
ParsePermissionConfig(AppSpawnSandboxCfg * sandbox,const char * name,const cJSON * permissionConfig)543 static int ParsePermissionConfig(AppSpawnSandboxCfg *sandbox, const char *name, const cJSON *permissionConfig)
544 {
545 APPSPAWN_LOGV("Parse permission config %{public}s", name);
546 SandboxPermissionNode *node = (SandboxPermissionNode *)GetSandboxSection(&sandbox->permissionQueue, name);
547 if (node == NULL) {
548 node = CreateSandboxPermissionNode(name);
549 }
550 APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return -1);
551
552 int ret = ParseBaseConfig(sandbox, &node->section, permissionConfig);
553 if (ret != 0) {
554 DeleteSandboxSection((SandboxSection *)node);
555 return ret;
556 }
557 // success, insert section
558 AddSandboxSection(&node->section, &sandbox->permissionQueue);
559 return 0;
560 }
561
AddSpawnerPermissionNode(AppSpawnSandboxCfg * sandbox)562 static int AddSpawnerPermissionNode(AppSpawnSandboxCfg *sandbox)
563 {
564 uint32_t permissionCount = ARRAY_LENGTH(g_spawnerPermissionList);
565 for (uint32_t i = 0; i < permissionCount; i++) {
566 SandboxPermissionNode *node =
567 (SandboxPermissionNode *)GetSandboxSection(&sandbox->permissionQueue, g_spawnerPermissionList[i]);
568 if (node == NULL) {
569 node = CreateSandboxPermissionNode(g_spawnerPermissionList[i]);
570 }
571 APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return -1);
572
573 // success, insert section
574 AddSandboxSection(&node->section, &sandbox->permissionQueue);
575 }
576 return 0;
577 }
578
ParseNameGroup(AppSpawnSandboxCfg * sandbox,const cJSON * groupConfig)579 static SandboxNameGroupNode *ParseNameGroup(AppSpawnSandboxCfg *sandbox, const cJSON *groupConfig)
580 {
581 char *name = GetStringFromJsonObj(groupConfig, "name");
582 APPSPAWN_CHECK(name != NULL, return NULL, "No name in name group config");
583 APPSPAWN_LOGV("Parse name-group config %{public}s", name);
584 SandboxNameGroupNode *node = (SandboxNameGroupNode *)GetSandboxSection(&sandbox->nameGroupsQueue, name);
585 if (node == NULL) {
586 node = CreateSandboxNameGroupNode(name);
587 }
588 APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return NULL);
589
590 cJSON *obj = cJSON_GetObjectItemCaseSensitive(groupConfig, "mount-paths-deps");
591 if (obj) {
592 if (node->depNode) { // free repeat
593 DeleteSandboxMountNode((SandboxMountNode *)node->depNode);
594 }
595 node->depNode = DecodeMountPathConfig(NULL, obj, SANDBOX_TAG_MOUNT_PATH);
596 if (node->depNode == NULL) {
597 DeleteSandboxSection((SandboxSection *)node);
598 return NULL;
599 }
600 // "deps-mode": "not-exists"
601 node->depMode = GetMountModeFromConfig(groupConfig, "deps-mode", MOUNT_MODE_ALWAYS);
602 }
603
604 int ret = ParseBaseConfig(sandbox, &node->section, groupConfig);
605 if (ret != 0) {
606 DeleteSandboxSection((SandboxSection *)node);
607 return NULL;
608 }
609 // "type": "system-const",
610 // "caps": ["shared"],
611 node->destType = GetNameGroupTypeFromConfig(groupConfig, "type", SANDBOX_TAG_INVALID);
612 node->depMounted = 0;
613 // success, insert section
614 AddSandboxSection(&node->section, &sandbox->nameGroupsQueue);
615 return node;
616 }
617
ParseNameGroupsConfig(AppSpawnSandboxCfg * sandbox,const cJSON * root)618 static int ParseNameGroupsConfig(AppSpawnSandboxCfg *sandbox, const cJSON *root)
619 {
620 APPSPAWN_CHECK(root != NULL, return APPSPAWN_SANDBOX_INVALID, "Invalid config ");
621 cJSON *configs = cJSON_GetObjectItemCaseSensitive(root, "name-groups");
622 APPSPAWN_CHECK_ONLY_EXPER(configs != NULL, return 0);
623 APPSPAWN_CHECK(cJSON_IsArray(configs), return APPSPAWN_SANDBOX_INVALID, "Invalid config ");
624 int count = cJSON_GetArraySize(configs);
625 APPSPAWN_CHECK_ONLY_EXPER(count > 0, return 0);
626
627 sandbox->depNodeCount = 0;
628 for (int i = 0; i < count; i++) {
629 cJSON *json = cJSON_GetArrayItem(configs, i);
630 if (json == NULL) {
631 continue;
632 }
633 SandboxNameGroupNode *node = ParseNameGroup(sandbox, json);
634 APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return APPSPAWN_SANDBOX_INVALID);
635 if (node->depNode) {
636 sandbox->depNodeCount++;
637 }
638 }
639 APPSPAWN_LOGV("ParseNameGroupsConfig depNodeCount %{public}d", sandbox->depNodeCount);
640 return 0;
641 }
642
ParseConditionalConfig(AppSpawnSandboxCfg * sandbox,const cJSON * configs,const char * configName,int (* parseConfig)(AppSpawnSandboxCfg * sandbox,const char * name,const cJSON * configs))643 static int ParseConditionalConfig(AppSpawnSandboxCfg *sandbox, const cJSON *configs, const char *configName,
644 int (*parseConfig)(AppSpawnSandboxCfg *sandbox, const char *name, const cJSON *configs))
645 {
646 APPSPAWN_CHECK_ONLY_EXPER(configs != NULL, return 0);
647 APPSPAWN_CHECK(cJSON_IsArray(configs),
648 return APPSPAWN_SANDBOX_INVALID, "Invalid config %{public}s", configName);
649 int ret = 0;
650 int count = cJSON_GetArraySize(configs);
651 for (int i = 0; i < count; i++) {
652 cJSON *json = cJSON_GetArrayItem(configs, i);
653 if (json == NULL) {
654 continue;
655 }
656 char *name = GetStringFromJsonObj(json, "name");
657 if (name == NULL) {
658 APPSPAWN_LOGE("No name in %{public}s configs", configName);
659 continue;
660 }
661 ret = parseConfig(sandbox, name, json);
662 APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
663 }
664 return 0;
665 }
666
ParseGlobalSandboxConfig(AppSpawnSandboxCfg * sandbox,const cJSON * root)667 static int ParseGlobalSandboxConfig(AppSpawnSandboxCfg *sandbox, const cJSON *root)
668 {
669 cJSON *json = cJSON_GetObjectItemCaseSensitive(root, "global");
670 if (json) {
671 sandbox->sandboxNsFlags = GetSandboxNsFlags(json);
672 char *rootPath = GetStringFromJsonObj(json, "sandbox-root");
673 APPSPAWN_CHECK(rootPath != NULL, return APPSPAWN_SYSTEM_ERROR, "No root path in config");
674 if (sandbox->rootPath) {
675 free(sandbox->rootPath);
676 }
677 sandbox->rootPath = strdup(rootPath);
678 APPSPAWN_CHECK(sandbox->rootPath != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to copy root path");
679 sandbox->topSandboxSwitch = GetBoolValueFromJsonObj(json, "top-sandbox-switch", true);
680 }
681 return 0;
682 }
683
684 typedef struct TagParseJsonContext {
685 AppSpawnSandboxCfg *sandboxCfg;
686 }ParseJsonContext;
687
ParseAppSandboxConfig(const cJSON * root,ParseJsonContext * context)688 APPSPAWN_STATIC int ParseAppSandboxConfig(const cJSON *root, ParseJsonContext *context)
689 {
690 APPSPAWN_CHECK(root != NULL && context != NULL && context->sandboxCfg != NULL,
691 return APPSPAWN_SYSTEM_ERROR, "Invalid json");
692 AppSpawnSandboxCfg *sandbox = context->sandboxCfg;
693 int ret = ParseGlobalSandboxConfig(sandbox, root); // "global":
694 APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return APPSPAWN_SANDBOX_INVALID);
695 ret = ParseNameGroupsConfig(sandbox, root); // name-groups
696 APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return APPSPAWN_SANDBOX_INVALID);
697
698 // "required"
699 cJSON *required = cJSON_GetObjectItemCaseSensitive(root, "required");
700 if (required) {
701 cJSON *config = NULL;
702 cJSON_ArrayForEach(config, required)
703 {
704 APPSPAWN_LOGI("Sandbox required config: %{public}s", config->string);
705 SandboxSection *section = GetSandboxSection(&sandbox->requiredQueue, config->string);
706 if (section == NULL) {
707 section = CreateSandboxSection(config->string, sizeof(SandboxSection), SANDBOX_TAG_REQUIRED);
708 }
709 APPSPAWN_CHECK_ONLY_EXPER(section != NULL, return -1);
710
711 ret = ParseBaseConfig(sandbox, section, config);
712 if (ret != 0) {
713 DeleteSandboxSection(section);
714 return ret;
715 }
716 // success, insert section
717 AddSandboxSection(section, &sandbox->requiredQueue);
718 }
719 }
720
721 // conditional
722 cJSON *json = cJSON_GetObjectItemCaseSensitive(root, "conditional");
723 if (json != NULL) {
724 // sandbox permission
725 cJSON *config = cJSON_GetObjectItemCaseSensitive(json, "permission");
726 ret = ParseConditionalConfig(sandbox, config, "permission", ParsePermissionConfig);
727 APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
728 // spawning permission
729 ret = AddSpawnerPermissionNode(sandbox);
730 APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
731 // spawn-flag
732 config = cJSON_GetObjectItemCaseSensitive(json, "spawn-flag");
733 ret = ParseConditionalConfig(sandbox, config, "spawn-flag", ParseSpawnFlagsConfig);
734 APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
735 // package-name
736 config = cJSON_GetObjectItemCaseSensitive(json, "package-name");
737 ret = ParseConditionalConfig(sandbox, config, "package-name", ParsePackageNameConfig);
738 APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
739 }
740 return ret;
741 }
742
GetSandboxNameByType(ExtDataType type)743 APPSPAWN_STATIC const char *GetSandboxNameByType(ExtDataType type)
744 {
745 if (type >= EXT_DATA_COUNT || type < EXT_DATA_APP_SANDBOX) {
746 return NULL;
747 }
748 const char *fileName = NULL;
749 switch (type) {
750 case EXT_DATA_APP_SANDBOX:
751 fileName = APP_SANDBOX_FILE_NAME;
752 break;
753 case EXT_DATA_ISOLATED_SANDBOX:
754 fileName = ISOLATED_SANDBOX_FILE_NAME;
755 break;
756 case EXT_DATA_RENDER_SANDBOX:
757 fileName = RENDER_SANDBOX_FILE_NAME;
758 break;
759 case EXT_DATA_GPU_SANDBOX:
760 fileName = GPU_SANDBOX_FILE_NAME;
761 break;
762 case EXT_DATA_DEBUG_HAP_SANDBOX:
763 fileName = DEBUG_SANDBOX_FILE_NAME;
764 break;
765 default:
766 break;
767 }
768 return fileName;
769 }
770
LoadAppSandboxConfig(AppSpawnSandboxCfg * sandbox,ExtDataType type)771 int LoadAppSandboxConfig(AppSpawnSandboxCfg *sandbox, ExtDataType type)
772 {
773 APPSPAWN_CHECK_ONLY_EXPER(sandbox != NULL, return APPSPAWN_ARG_INVALID);
774 const char *sandboxName = GetSandboxNameByType(type);
775 APPSPAWN_LOGV("Get sandboxName %{public}s by type %{public}d", sandboxName, type);
776 if (sandbox->depGroupNodes != NULL) {
777 APPSPAWN_LOGW("Sandbox has been load");
778 return 0;
779 }
780 ParseJsonContext context = {};
781 context.sandboxCfg = sandbox;
782 (void)ParseJsonConfig("etc/sandbox", sandboxName, ParseAppSandboxConfig, &context);
783 sandbox->pidNamespaceSupport = AppSandboxPidNsIsSupport();
784 sandbox->appFullMountEnable = CheckAppFullMountEnable();
785 APPSPAWN_LOGI("Sandbox pidNamespaceSupport: %{public}d appFullMountEnable: %{public}d",
786 sandbox->pidNamespaceSupport, sandbox->appFullMountEnable);
787
788 uint32_t depNodeCount = sandbox->depNodeCount;
789 APPSPAWN_CHECK_ONLY_EXPER(depNodeCount > 0, return 0);
790
791 sandbox->depGroupNodes = (SandboxNameGroupNode **)calloc(1, sizeof(SandboxNameGroupNode *) * depNodeCount);
792 APPSPAWN_CHECK(sandbox->depGroupNodes != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed alloc memory ");
793 sandbox->depNodeCount = 0;
794 ListNode *node = sandbox->nameGroupsQueue.front.next;
795 while (node != &sandbox->nameGroupsQueue.front) {
796 SandboxNameGroupNode *groupNode = (SandboxNameGroupNode *)ListEntry(node, SandboxMountNode, node);
797 if (groupNode->depNode) {
798 sandbox->depGroupNodes[sandbox->depNodeCount++] = groupNode;
799 }
800 node = node->next;
801 }
802 APPSPAWN_LOGI("LoadAppSandboxConfig depNodeCount %{public}d", sandbox->depNodeCount);
803
804 return 0;
805 }
806