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
40static const SandboxFlagInfo NAMESPACE_FLAGS_MAP[] = {
41    {"pid", CLONE_NEWPID}, {"net", CLONE_NEWNET}
42};
43
44static 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
51static const SandboxFlagInfo MOUNT_MODE_MAP[] = {
52    {"not-exists", (unsigned long)MOUNT_MODE_NOT_EXIST},
53    {"always", (unsigned long)MOUNT_MODE_ALWAYS}
54};
55
56static 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
61static 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
67static inline SymbolLinkNode *CreateSymbolLinkNode(void)
68{
69    return (SymbolLinkNode *)CreateSandboxMountNode(sizeof(SymbolLinkNode), SANDBOX_TAG_SYMLINK);
70}
71
72static inline SandboxPackageNameNode *CreateSandboxPackageNameNode(const char *name)
73{
74    return (SandboxPackageNameNode *)CreateSandboxSection(name,
75        sizeof(SandboxPackageNameNode), SANDBOX_TAG_PACKAGE_NAME);
76}
77
78static inline SandboxFlagsNode *CreateSandboxFlagsNode(const char *name)
79{
80    return (SandboxFlagsNode *)CreateSandboxSection(name, sizeof(SandboxFlagsNode), SANDBOX_TAG_SPAWN_FLAGS);
81}
82
83static inline SandboxNameGroupNode *CreateSandboxNameGroupNode(const char *name)
84{
85    return (SandboxNameGroupNode *)CreateSandboxSection(name, sizeof(SandboxNameGroupNode), SANDBOX_TAG_NAME_GROUP);
86}
87
88static 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
97static 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
111static inline bool AppSandboxPidNsIsSupport(void)
112{
113    // only set false, return false
114    return GetBoolParameter("const.sandbox.pidns.support", true);
115}
116
117static inline bool CheckAppFullMountEnable(void)
118{
119    return GetBoolParameter("const.filemanager.full_mount.enable", false);
120}
121
122APPSPAWN_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
135static 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
148static 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
166static int SetMode(const char *str, void *context)
167{
168    mode_t *mode = (mode_t *)context;
169    *mode |= GetPathMode(str);
170    return 0;
171}
172
173static 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
184APPSPAWN_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
197static 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
205static 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
213    PathMountNode *tmp = GetPathMountNode(section, type, srcPath, dstPath);
214    if (tmp != NULL) { // 删除老的节点,保存新的节点
215        DeleteSandboxMountNode((SandboxMountNode *)tmp);
216        APPSPAWN_LOGW("path %{public}s %{public}s repeat config, delete old", srcPath, dstPath);
217    }
218
219    cJSON *demandInfo = cJSON_GetObjectItemCaseSensitive(config, "create-on-demand");
220    PathMountNode *sandboxNode = CreatePathMountNode(type, demandInfo != NULL);
221    APPSPAWN_CHECK_ONLY_EXPER(sandboxNode != NULL, return NULL);
222    sandboxNode->createDemand = demandInfo != NULL;
223    sandboxNode->source = strdup(srcPath);
224    sandboxNode->target = strdup(dstPath);
225
226    sandboxNode->destMode = GetChmodFromJson(config);
227    sandboxNode->mountSharedFlag = GetBoolValueFromJsonObj(config, "mount-shared-flag", false);
228    sandboxNode->checkErrorFlag = GetBoolValueFromJsonObj(config, "check-action-status", false);
229
230    sandboxNode->category = GetMountCategory(GetStringFromJsonObj(config, "category"));
231    const char *value = GetStringFromJsonObj(config, "app-apl-name");
232    if (value != NULL) {
233        sandboxNode->appAplName = strdup(value);
234    }
235    FillPathDemandInfo(demandInfo, sandboxNode);
236
237    if (sandboxNode->source == NULL || sandboxNode->target == NULL) {
238        APPSPAWN_LOGE("Failed to get sourc or target path");
239        DeleteSandboxMountNode((SandboxMountNode *)sandboxNode);
240        return NULL;
241    }
242    return sandboxNode;
243}
244
245APPSPAWN_STATIC int ParseMountPathsConfig(AppSpawnSandboxCfg *sandbox,
246    const cJSON *mountConfigs, SandboxSection *section, uint32_t type)
247{
248    APPSPAWN_CHECK_ONLY_EXPER(mountConfigs != NULL && cJSON_IsArray(mountConfigs), return -1);
249
250    uint32_t mountPointSize = cJSON_GetArraySize(mountConfigs);
251    for (uint32_t i = 0; i < mountPointSize; i++) {
252        cJSON *mntJson = cJSON_GetArrayItem(mountConfigs, i);
253        if (mntJson == NULL) {
254            continue;
255        }
256        PathMountNode *sandboxNode = DecodeMountPathConfig(section, mntJson, type);
257        APPSPAWN_CHECK_ONLY_EXPER(sandboxNode != NULL, continue);
258        AddSandboxMountNode(&sandboxNode->sandboxNode, section);
259    }
260    return 0;
261}
262
263static SymbolLinkNode *DecodeSymbolLinksConfig(const SandboxSection *section, const cJSON *config)
264{
265    const char *target = GetStringFromJsonObj(config, "target-name");
266    const char *linkName = GetStringFromJsonObj(config, "link-name");
267    if (target == NULL || linkName == NULL) {
268        return NULL;
269    }
270
271    SymbolLinkNode *tmp = GetSymbolLinkNode(section, target, linkName);
272    if (tmp != NULL) { // 删除老的节点,保存新的节点
273        DeleteSandboxMountNode((SandboxMountNode *)tmp);
274        APPSPAWN_LOGW("SymbolLink %{public}s %{public}s repeat config, delete old", target, linkName);
275    }
276
277    SymbolLinkNode *node = CreateSymbolLinkNode();
278    APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return NULL);
279    node->destMode = GetChmodFromJson(config);
280    node->checkErrorFlag = GetBoolValueFromJsonObj(config, "check-action-status", false);
281    node->target = strdup(target);
282    node->linkName = strdup(linkName);
283    if (node->target == NULL || node->linkName == NULL) {
284        APPSPAWN_LOGE("Failed to get sourc or target path");
285        DeleteSandboxMountNode((SandboxMountNode *)node);
286        return NULL;
287    }
288    return node;
289}
290
291APPSPAWN_STATIC int ParseSymbolLinksConfig(AppSpawnSandboxCfg *sandbox, const cJSON *symbolLinkConfigs,
292    SandboxSection *section)
293{
294    APPSPAWN_CHECK_ONLY_EXPER(symbolLinkConfigs != NULL && cJSON_IsArray(symbolLinkConfigs), return -1);
295    uint32_t symlinkPointSize = cJSON_GetArraySize(symbolLinkConfigs);
296    for (uint32_t i = 0; i < symlinkPointSize; i++) {
297        cJSON *symConfig = cJSON_GetArrayItem(symbolLinkConfigs, i);
298        if (symConfig == NULL) {
299            continue;
300        }
301        SymbolLinkNode *node = DecodeSymbolLinksConfig(section, symConfig);
302        APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return -1);
303        AddSandboxMountNode(&node->sandboxNode, section);
304    }
305    return 0;
306}
307
308APPSPAWN_STATIC int ParseGidTableConfig(AppSpawnSandboxCfg *sandbox, const cJSON *configs, SandboxSection *section)
309{
310    APPSPAWN_CHECK(cJSON_IsArray(configs), return 0, "json is not array.");
311    uint32_t arrayLen = (uint32_t)cJSON_GetArraySize(configs);
312    APPSPAWN_CHECK_ONLY_EXPER(arrayLen > 0, return 0);
313    APPSPAWN_CHECK(arrayLen < APP_MAX_GIDS, arrayLen = APP_MAX_GIDS, "More gid in gids json.");
314
315    // 配置存在,以后面的配置为准
316    if (section->gidTable) {
317        free(section->gidTable);
318        section->gidTable = NULL;
319        section->gidCount = 0;
320    }
321    section->gidTable = (gid_t *)calloc(1, sizeof(gid_t) * arrayLen);
322    APPSPAWN_CHECK(section->gidTable != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to alloc memory.");
323
324    for (uint32_t i = 0; i < arrayLen; i++) {
325        cJSON *item = cJSON_GetArrayItem(configs, i);
326        gid_t gid = 0;
327        if (cJSON_IsNumber(item)) {
328            gid = (gid_t)cJSON_GetNumberValue(item);
329        } else {
330            char *value = cJSON_GetStringValue(item);
331            gid = DecodeGid(value);
332        }
333        if (gid <= 0) {
334            continue;
335        }
336        section->gidTable[section->gidCount++] = gid;
337    }
338    return 0;
339}
340
341static int ParseMountGroupsConfig(AppSpawnSandboxCfg *sandbox, const cJSON *groupConfig, SandboxSection *section)
342{
343    APPSPAWN_CHECK(cJSON_IsArray(groupConfig),
344        return APPSPAWN_SANDBOX_INVALID, "Invalid mount-groups config %{public}s", section->name);
345
346    // 合并name-group
347    uint32_t count = (uint32_t)cJSON_GetArraySize(groupConfig);
348    APPSPAWN_LOGV("mount-group in section %{public}s  %{public}u", section->name, count);
349    APPSPAWN_CHECK_ONLY_EXPER(count > 0, return 0);
350    count += section->number;
351    SandboxMountNode **nameGroups = (SandboxMountNode **)calloc(1, sizeof(SandboxMountNode *) * count);
352    APPSPAWN_CHECK(nameGroups != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to alloc memory for group name");
353
354    uint32_t j = 0;
355    uint32_t number = 0;
356    for (j = 0; j < section->number; j++) { // copy old
357        if (section->nameGroups[j] == NULL) {
358            continue;
359        }
360        nameGroups[number++] = section->nameGroups[j];
361    }
362
363    SandboxNameGroupNode *mountNode = NULL;
364    for (uint32_t i = 0; i < count; i++) {
365        nameGroups[number] = NULL;
366
367        char *name = cJSON_GetStringValue(cJSON_GetArrayItem(groupConfig, i));
368        mountNode = (SandboxNameGroupNode *)GetSandboxSection(&sandbox->nameGroupsQueue, name);
369        if (mountNode == NULL) {
370            APPSPAWN_LOGE("Can not find name-group %{public}s", name);
371            continue;
372        }
373        // check type
374        if (strcmp(section->name, "system-const") == 0 && mountNode->destType != SANDBOX_TAG_SYSTEM_CONST) {
375            APPSPAWN_LOGE("Invalid name-group %{public}s", name);
376            continue;
377        }
378        // 过滤重复的节点
379        for (j = 0; j < section->number; j++) {
380            if (section->nameGroups[j] != NULL && section->nameGroups[j] == (SandboxMountNode *)mountNode) {
381                APPSPAWN_LOGE("Name-group %{public}s bas been set", name);
382                break;
383            }
384        }
385        if (j < section->number) {
386            continue;
387        }
388        nameGroups[number++] = (SandboxMountNode *)mountNode;
389        APPSPAWN_LOGV("Name-group %{public}d %{public}s set", section->number, name);
390    }
391    if (section->nameGroups != NULL) {
392        free(section->nameGroups);
393    }
394    section->nameGroups = nameGroups;
395    section->number = number;
396    APPSPAWN_LOGV("mount-group in section %{public}s  %{public}u", section->name, section->number);
397    return 0;
398}
399
400static int ParseBaseConfig(AppSpawnSandboxCfg *sandbox, SandboxSection *section, const cJSON *configs)
401{
402    APPSPAWN_CHECK_ONLY_EXPER(configs != NULL, return 0);
403    APPSPAWN_CHECK(cJSON_IsObject(configs),
404        return APPSPAWN_SANDBOX_INVALID, "Invalid config %{public}s", section->name);
405    APPSPAWN_LOGV("Parse sandbox %{public}s", section->name);
406
407    // "sandbox-switch": "ON", default sandbox switch is on
408    section->sandboxSwitch = GetBoolValueFromJsonObj(configs, "sandbox-switch", true);
409    // "sandbox-shared"
410    section->sandboxShared = GetBoolValueFromJsonObj(configs, "sandbox-shared", false);
411
412    int ret = 0;
413    cJSON *gidTabJson = cJSON_GetObjectItemCaseSensitive(configs, "gids");
414    if (gidTabJson) {
415        ret = ParseGidTableConfig(sandbox, gidTabJson, section);
416        APPSPAWN_CHECK(ret == 0, return ret, "Parse gids for %{public}s", section->name);
417    }
418
419    cJSON *pathConfigs = cJSON_GetObjectItemCaseSensitive(configs, "mount-paths");
420    if (pathConfigs != NULL) {  // mount-paths
421        ret = ParseMountPathsConfig(sandbox, pathConfigs, section, SANDBOX_TAG_MOUNT_PATH);
422        APPSPAWN_CHECK(ret == 0, return ret, "Parse mount-paths for %{public}s", section->name);
423    }
424
425    pathConfigs = cJSON_GetObjectItemCaseSensitive(configs, "mount-files");
426    if (pathConfigs != NULL) {  // mount-files
427        ret = ParseMountPathsConfig(sandbox, pathConfigs, section, SANDBOX_TAG_MOUNT_FILE);
428        APPSPAWN_CHECK(ret == 0, return ret, "Parse mount-paths for %{public}s", section->name);
429    }
430
431    pathConfigs = cJSON_GetObjectItemCaseSensitive(configs, "symbol-links");
432    if (pathConfigs != NULL) {  // symbol-links
433        ret = ParseSymbolLinksConfig(sandbox, pathConfigs, section);
434        APPSPAWN_CHECK(ret == 0, return ret, "Parse symbol-links for %{public}s", section->name);
435    }
436
437    cJSON *groupConfig = cJSON_GetObjectItemCaseSensitive(configs, "mount-groups");
438    if (groupConfig != NULL) {
439        ret = ParseMountGroupsConfig(sandbox, groupConfig, section);
440        APPSPAWN_CHECK(ret == 0, return ret, "Parse mount-groups for %{public}s", section->name);
441    }
442    return 0;
443}
444
445static int ParsePackageNameConfig(AppSpawnSandboxCfg *sandbox, const char *name, const cJSON *packageNameConfigs)
446{
447    APPSPAWN_LOGV("Parse package-name config %{public}s", name);
448    SandboxPackageNameNode *node = (SandboxPackageNameNode *)GetSandboxSection(&sandbox->packageNameQueue, name);
449    if (node == NULL) {
450        node = CreateSandboxPackageNameNode(name);
451    }
452    APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return -1);
453
454    int ret = ParseBaseConfig(sandbox, &node->section, packageNameConfigs);
455    if (ret != 0) {
456        DeleteSandboxSection((SandboxSection *)node);
457        return ret;
458    }
459    // success, insert section
460    AddSandboxSection(&node->section, &sandbox->packageNameQueue);
461    return 0;
462}
463
464static int ParseSpawnFlagsConfig(AppSpawnSandboxCfg *sandbox, const char *name, const cJSON *flagsConfig)
465{
466    uint32_t flagIndex = GetFlagIndexFromJson(flagsConfig);
467    APPSPAWN_LOGV("Parse spawn-flags config %{public}s flagIndex %{public}u", name, flagIndex);
468    SandboxFlagsNode *node = (SandboxFlagsNode *)GetSandboxSection(&sandbox->spawnFlagsQueue, name);
469    if (node == NULL) {
470        node = CreateSandboxFlagsNode(name);
471    }
472    APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return -1);
473    node->flagIndex = flagIndex;
474
475    int ret = ParseBaseConfig(sandbox, &node->section, flagsConfig);
476    if (ret != 0) {
477        DeleteSandboxSection((SandboxSection *)node);
478        return ret;
479    }
480    // success, insert section
481    AddSandboxSection(&node->section, &sandbox->spawnFlagsQueue);
482    return 0;
483}
484
485static int ParsePermissionConfig(AppSpawnSandboxCfg *sandbox, const char *name, const cJSON *permissionConfig)
486{
487    APPSPAWN_LOGV("Parse permission config %{public}s", name);
488    SandboxPermissionNode *node = (SandboxPermissionNode *)GetSandboxSection(&sandbox->permissionQueue, name);
489    if (node == NULL) {
490        node = CreateSandboxPermissionNode(name);
491    }
492    APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return -1);
493
494    int ret = ParseBaseConfig(sandbox, &node->section, permissionConfig);
495    if (ret != 0) {
496        DeleteSandboxSection((SandboxSection *)node);
497        return ret;
498    }
499    // success, insert section
500    AddSandboxSection(&node->section, &sandbox->permissionQueue);
501    return 0;
502}
503
504static SandboxNameGroupNode *ParseNameGroup(AppSpawnSandboxCfg *sandbox, const cJSON *groupConfig)
505{
506    char *name = GetStringFromJsonObj(groupConfig, "name");
507    APPSPAWN_CHECK(name != NULL, return NULL, "No name in name group config");
508    APPSPAWN_LOGV("Parse name-group config %{public}s", name);
509    SandboxNameGroupNode *node = (SandboxNameGroupNode *)GetSandboxSection(&sandbox->nameGroupsQueue, name);
510    if (node == NULL) {
511        node = CreateSandboxNameGroupNode(name);
512    }
513    APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return NULL);
514
515    cJSON *obj = cJSON_GetObjectItemCaseSensitive(groupConfig, "mount-paths-deps");
516    if (obj) {
517        if (node->depNode) { // free repeat
518            DeleteSandboxMountNode((SandboxMountNode *)node->depNode);
519        }
520        node->depNode = DecodeMountPathConfig(NULL, obj, SANDBOX_TAG_MOUNT_PATH);
521        if (node->depNode == NULL) {
522            DeleteSandboxSection((SandboxSection *)node);
523            return NULL;
524        }
525        // "deps-mode": "not-exists"
526        node->depMode = GetMountModeFromConfig(groupConfig, "deps-mode", MOUNT_MODE_ALWAYS);
527    }
528
529    int ret = ParseBaseConfig(sandbox, &node->section, groupConfig);
530    if (ret != 0) {
531        DeleteSandboxSection((SandboxSection *)node);
532        return NULL;
533    }
534    // "type": "system-const",
535    // "caps": ["shared"],
536    node->destType = GetNameGroupTypeFromConfig(groupConfig, "type", SANDBOX_TAG_INVALID);
537    node->depMounted = 0;
538    // success, insert section
539    AddSandboxSection(&node->section, &sandbox->nameGroupsQueue);
540    return node;
541}
542
543static int ParseNameGroupsConfig(AppSpawnSandboxCfg *sandbox, const cJSON *root)
544{
545    APPSPAWN_CHECK(root != NULL, return APPSPAWN_SANDBOX_INVALID, "Invalid config ");
546    cJSON *configs = cJSON_GetObjectItemCaseSensitive(root, "name-groups");
547    APPSPAWN_CHECK_ONLY_EXPER(configs != NULL, return 0);
548    APPSPAWN_CHECK(cJSON_IsArray(configs), return APPSPAWN_SANDBOX_INVALID, "Invalid config ");
549    int count = cJSON_GetArraySize(configs);
550    APPSPAWN_CHECK_ONLY_EXPER(count > 0, return 0);
551
552    sandbox->depNodeCount = 0;
553    for (int i = 0; i < count; i++) {
554        cJSON *json = cJSON_GetArrayItem(configs, i);
555        if (json == NULL) {
556            continue;
557        }
558        SandboxNameGroupNode *node = ParseNameGroup(sandbox, json);
559        APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return APPSPAWN_SANDBOX_INVALID);
560        if (node->depNode) {
561            sandbox->depNodeCount++;
562        }
563    }
564    APPSPAWN_LOGV("ParseNameGroupsConfig depNodeCount %{public}d", sandbox->depNodeCount);
565    return 0;
566}
567
568static int ParseConditionalConfig(AppSpawnSandboxCfg *sandbox, const cJSON *configs, const char *configName,
569    int (*parseConfig)(AppSpawnSandboxCfg *sandbox, const char *name, const cJSON *configs))
570{
571    APPSPAWN_CHECK_ONLY_EXPER(configs != NULL, return 0);
572    APPSPAWN_CHECK(cJSON_IsArray(configs),
573        return APPSPAWN_SANDBOX_INVALID, "Invalid config %{public}s", configName);
574    int ret = 0;
575    int count = cJSON_GetArraySize(configs);
576    for (int i = 0; i < count; i++) {
577        cJSON *json = cJSON_GetArrayItem(configs, i);
578        if (json == NULL) {
579            continue;
580        }
581        char *name = GetStringFromJsonObj(json, "name");
582        if (name == NULL) {
583            APPSPAWN_LOGE("No name in %{public}s configs", configName);
584            continue;
585        }
586        ret = parseConfig(sandbox, name, json);
587        APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
588    }
589    return 0;
590}
591
592static int ParseGlobalSandboxConfig(AppSpawnSandboxCfg *sandbox, const cJSON *root)
593{
594    cJSON *json = cJSON_GetObjectItemCaseSensitive(root, "global");
595    if (json) {
596        sandbox->sandboxNsFlags = GetSandboxNsFlags(json);
597        char *rootPath = GetStringFromJsonObj(json, "sandbox-root");
598        APPSPAWN_CHECK(rootPath != NULL, return APPSPAWN_SYSTEM_ERROR, "No root path in config");
599        if (sandbox->rootPath) {
600            free(sandbox->rootPath);
601        }
602        sandbox->rootPath = strdup(rootPath);
603        APPSPAWN_CHECK(sandbox->rootPath != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to copy root path");
604        sandbox->topSandboxSwitch = GetBoolValueFromJsonObj(json, "top-sandbox-switch", true);
605    }
606    return 0;
607}
608
609typedef struct TagParseJsonContext {
610    AppSpawnSandboxCfg *sandboxCfg;
611}ParseJsonContext;
612
613APPSPAWN_STATIC int ParseAppSandboxConfig(const cJSON *root, ParseJsonContext *context)
614{
615    APPSPAWN_CHECK(root != NULL && context != NULL && context->sandboxCfg != NULL,
616        return APPSPAWN_SYSTEM_ERROR, "Invalid json");
617    AppSpawnSandboxCfg *sandbox = context->sandboxCfg;
618    int ret = ParseGlobalSandboxConfig(sandbox, root);  // "global":
619    APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return APPSPAWN_SANDBOX_INVALID);
620    ret = ParseNameGroupsConfig(sandbox, root);  // name-groups
621    APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return APPSPAWN_SANDBOX_INVALID);
622
623    // "required"
624    cJSON *required = cJSON_GetObjectItemCaseSensitive(root, "required");
625    if (required) {
626        cJSON *config = NULL;
627        cJSON_ArrayForEach(config, required)
628        {
629            APPSPAWN_LOGI("Sandbox required config: %{public}s", config->string);
630            SandboxSection *section = GetSandboxSection(&sandbox->requiredQueue, config->string);
631            if (section == NULL) {
632                section = CreateSandboxSection(config->string, sizeof(SandboxSection), SANDBOX_TAG_REQUIRED);
633            }
634            APPSPAWN_CHECK_ONLY_EXPER(section != NULL, return -1);
635
636            ret = ParseBaseConfig(sandbox, section, config);
637            if (ret != 0) {
638                DeleteSandboxSection(section);
639                return ret;
640            }
641            // success, insert section
642            AddSandboxSection(section, &sandbox->requiredQueue);
643        }
644    }
645
646    // conditional
647    cJSON *json = cJSON_GetObjectItemCaseSensitive(root, "conditional");
648    if (json != NULL) {
649        // permission
650        cJSON *config = cJSON_GetObjectItemCaseSensitive(json, "permission");
651        ret = ParseConditionalConfig(sandbox, config, "permission", ParsePermissionConfig);
652        APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
653        // spawn-flag
654        config = cJSON_GetObjectItemCaseSensitive(json, "spawn-flag");
655        ret = ParseConditionalConfig(sandbox, config, "spawn-flag", ParseSpawnFlagsConfig);
656        APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
657        // package-name
658        config = cJSON_GetObjectItemCaseSensitive(json, "package-name");
659        ret = ParseConditionalConfig(sandbox, config, "package-name", ParsePackageNameConfig);
660        APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
661    }
662    return ret;
663}
664
665APPSPAWN_STATIC const char *GetSandboxNameByMode(RunMode mode)
666{
667    if (mode == MODE_FOR_NATIVE_SPAWN) {
668        return ISOLATED_SANDBOX_FILE_NAME;
669    }
670    if (mode == MODE_FOR_NWEB_SPAWN || mode == MODE_FOR_NWEB_COLD_RUN) {
671        return WEB_SANDBOX_FILE_NAME;
672    }
673    return APP_SANDBOX_FILE_NAME;
674}
675
676int LoadAppSandboxConfig(AppSpawnSandboxCfg *sandbox, RunMode mode)
677{
678    APPSPAWN_CHECK_ONLY_EXPER(sandbox != NULL, return APPSPAWN_ARG_INVALID);
679    const char *sandboxName = GetSandboxNameByMode(mode);
680    if (sandbox->depGroupNodes != NULL) {
681        APPSPAWN_LOGW("Sandbox has been load");
682        return 0;
683    }
684    ParseJsonContext context = {};
685    context.sandboxCfg = sandbox;
686    int ret = ParseJsonConfig("etc/sandbox", sandboxName, ParseAppSandboxConfig, &context);
687    if (ret == APPSPAWN_SANDBOX_NONE) {
688        APPSPAWN_LOGW("No sandbox config");
689        ret = 0;
690    }
691    APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
692    sandbox->pidNamespaceSupport = AppSandboxPidNsIsSupport();
693    sandbox->appFullMountEnable = CheckAppFullMountEnable();
694    APPSPAWN_LOGI("Sandbox pidNamespaceSupport: %{public}d appFullMountEnable: %{public}d",
695        sandbox->pidNamespaceSupport, sandbox->appFullMountEnable);
696
697    uint32_t depNodeCount = sandbox->depNodeCount;
698    APPSPAWN_CHECK_ONLY_EXPER(depNodeCount > 0, return ret);
699
700    sandbox->depGroupNodes = (SandboxNameGroupNode **)calloc(1, sizeof(SandboxNameGroupNode *) * depNodeCount);
701    APPSPAWN_CHECK(sandbox->depGroupNodes != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed alloc memory ");
702    sandbox->depNodeCount = 0;
703    ListNode *node = sandbox->nameGroupsQueue.front.next;
704    while (node != &sandbox->nameGroupsQueue.front) {
705        SandboxNameGroupNode *groupNode = (SandboxNameGroupNode *)ListEntry(node, SandboxMountNode, node);
706        if (groupNode->depNode) {
707            sandbox->depGroupNodes[sandbox->depNodeCount++] = groupNode;
708        }
709        node = node->next;
710    }
711    APPSPAWN_LOGI("LoadAppSandboxConfig depNodeCount %{public}d", sandbox->depNodeCount);
712
713    return 0;
714}
715