• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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 
16 #include <cerrno>
17 #include <sys/mount.h>
18 #include <vector>
19 #include <cstring>
20 #include <fstream>
21 #include <sstream>
22 #include <algorithm>
23 #include <regex>
24 #include <map>
25 #include "securec.h"
26 
27 #include "sandbox_shared_mount.h"
28 #include "appspawn_mount_permission.h"
29 #include "appspawn_utils.h"
30 #include "parameter.h"
31 
32 #define USER_ID_SIZE 16
33 #define DIR_MODE 0711
34 #define LOCK_STATUS_SIZE 16
35 
36 #define DATA_GROUP_SOCKET_TYPE    "DataGroup"
37 #define GROUPLIST_KEY_DATAGROUPID "dataGroupId"
38 #define GROUPLIST_KEY_GID         "gid"
39 #define GROUPLIST_KEY_DIR         "dir"
40 #define GROUPLIST_KEY_UUID        "uuid"
41 
42 static const MountSharedTemplate MOUNT_SHARED_MAP[] = {
43     {"/data/storage/el2", nullptr},
44     {"/data/storage/el3", nullptr},
45     {"/data/storage/el4", nullptr},
46     {"/data/storage/el5", "ohos.permission.PROTECT_SCREEN_LOCK_DATA"},
47 };
48 
49 static const DataGroupSandboxPathTemplate DATA_GROUP_SANDBOX_PATH_MAP[] = {
50     {"el2", EL2, "/data/storage/el2/group/", nullptr},
51     {"el3", EL3, "/data/storage/el3/group/", nullptr},
52     {"el4", EL4, "/data/storage/el4/group/", nullptr},
53     {"el5", EL5, "/data/storage/el5/group/", "ohos.permission.PROTECT_SCREEN_LOCK_DATA"},
54 };
55 
56 static std::map<std::string, int> g_mountInfoMap;
57 
GetElxInfoFromDir(const char * path)58 int GetElxInfoFromDir(const char *path)
59 {
60     int ret = ELX_MAX;
61     if (path == nullptr) {
62         return ret;
63     }
64     uint32_t count = ARRAY_LENGTH(DATA_GROUP_SANDBOX_PATH_MAP);
65     for (uint32_t i = 0; i < count; ++i) {
66         if (strstr(path, DATA_GROUP_SANDBOX_PATH_MAP[i].elxName) != nullptr) {
67             return DATA_GROUP_SANDBOX_PATH_MAP[i].category;
68         }
69     }
70     APPSPAWN_LOGE("Get elx info from dir failed, path %{public}s", path);
71     return ret;
72 }
73 
GetDataGroupArgTemplate(uint32_t category)74 const DataGroupSandboxPathTemplate *GetDataGroupArgTemplate(uint32_t category)
75 {
76     uint32_t count = ARRAY_LENGTH(DATA_GROUP_SANDBOX_PATH_MAP);
77     if (category > count) {
78         APPSPAWN_LOGE("category %{public}d is out of range", category);
79         return nullptr;
80     }
81     for (uint32_t i = 0; i < count; ++i) {
82         if (DATA_GROUP_SANDBOX_PATH_MAP[i].category == category) {
83             return &DATA_GROUP_SANDBOX_PATH_MAP[i];
84         }
85     }
86     return nullptr;
87 }
88 
IsValidDataGroupItem(cJSON * item)89 bool IsValidDataGroupItem(cJSON *item)
90 {
91     // Check if the item contains the specified key and if the value corresponding to the key is a string
92     cJSON *datagroupId = cJSON_GetObjectItem(item, GROUPLIST_KEY_DATAGROUPID);
93     cJSON *gid = cJSON_GetObjectItem(item, GROUPLIST_KEY_GID);
94     cJSON *dir = cJSON_GetObjectItem(item, GROUPLIST_KEY_DIR);
95     cJSON *uuid = cJSON_GetObjectItem(item, GROUPLIST_KEY_UUID);
96 
97     if (datagroupId && cJSON_IsString(datagroupId) &&
98         gid && cJSON_IsString(gid) &&
99         dir && cJSON_IsString(dir) &&
100         uuid && cJSON_IsString(uuid)) {
101         return true;
102     }
103     return false;
104 }
105 
GetEl1BundleMountCount(void)106 void *GetEl1BundleMountCount(void)
107 {
108     return static_cast<void*>(&g_mountInfoMap);
109 }
110 
111 #ifndef APPSPAWN_SANDBOX_NEW
IsUnlockStatus(uint32_t uid)112 static bool IsUnlockStatus(uint32_t uid)
113 {
114     const int userIdBase = UID_BASE;
115     uid = uid / userIdBase;
116     if (uid == 0) {
117         return true;
118     }
119     std::string lockStatusParam = "startup.appspawn.lockstatus_" + std::to_string(uid);
120     char userLockStatus[LOCK_STATUS_SIZE] = {0};
121     int ret = GetParameter(lockStatusParam.c_str(), "1", userLockStatus, sizeof(userLockStatus));
122     APPSPAWN_LOGI("lockStatus %{public}u %{public}s", uid, userLockStatus);
123     if (ret > 0 && (strcmp(userLockStatus, "0") == 0)) {   // 0:unlock status 1:lock status
124         return true;
125     }
126     return false;
127 }
128 
DoSharedMount(const SharedMountArgs * arg)129 static int DoSharedMount(const SharedMountArgs *arg)
130 {
131     if (arg == nullptr || arg->srcPath == nullptr || arg->destPath == nullptr) {
132         APPSPAWN_LOGE("Invalid arg");
133         return APPSPAWN_ARG_INVALID;
134     }
135 
136     APPSPAWN_LOGV("Mount arg: '%{public}s' '%{public}s' %{public}lu '%{public}s' %{public}s => %{public}s",
137                   arg->fsType, arg->mountSharedFlag == MS_SHARED ? "MS_SHARED" : "MS_SLAVE",
138                   arg->mountFlags, arg->options, arg->srcPath, arg->destPath);
139 
140     int ret = mount(arg->srcPath, arg->destPath, arg->fsType, arg->mountFlags, arg->options);
141     if (ret != 0) {
142         APPSPAWN_LOGE("mount %{public}s to %{public}s failed, errno %{public}d",
143                       arg->srcPath, arg->destPath, errno);
144         return ret;
145     }
146     ret = mount(nullptr, arg->destPath, nullptr, arg->mountSharedFlag, nullptr);
147     if (ret != 0) {
148         APPSPAWN_LOGE("mount path %{public}s to shared failed, errno %{public}d", arg->destPath, errno);
149         return ret;
150     }
151     APPSPAWN_LOGI("mount path %{public}s to shared success", arg->destPath);
152     return 0;
153 }
154 
SetSandboxPathShared(const std::string & sandboxPath)155 static bool SetSandboxPathShared(const std::string &sandboxPath)
156 {
157     int ret = mount(nullptr, sandboxPath.c_str(), nullptr, MS_SHARED, nullptr);
158     if (ret != 0) {
159         APPSPAWN_LOGW("Need to mount %{public}s to shared, errno %{public}d", sandboxPath.c_str(), errno);
160         return false;
161     }
162     return true;
163 }
164 
MountEl1Bundle(const AppSpawningCtx * property,const AppDacInfo * info,const char * varBundleName)165 static int MountEl1Bundle(const AppSpawningCtx *property, const AppDacInfo *info, const char *varBundleName)
166 {
167     /* /data/app/el1/bundle/public/<bundleName> */
168     AppSpawnMsgBundleInfo *bundleInfo =
169         reinterpret_cast<AppSpawnMsgBundleInfo *>(GetAppProperty(property, TLV_BUNDLE_INFO));
170     if (bundleInfo == nullptr) {
171         return APPSPAWN_SANDBOX_INVALID;
172     }
173     char sourcePath[PATH_MAX_LEN] = {0};
174     int ret = snprintf_s(sourcePath, PATH_MAX_LEN, PATH_MAX_LEN - 1, "/data/app/el1/bundle/public/%s",
175                          bundleInfo->bundleName);
176     if (ret <= 0) {
177         APPSPAWN_LOGE("snprintf data/app/el1/bundle/public/%{public}s failed, errno %{public}d",
178                       bundleInfo->bundleName, errno);
179         return APPSPAWN_ERROR_UTILS_MEM_FAIL;
180     }
181 
182     /* /mnt/sandbox/<currentUserId>/<varBundleName>/data/storage/el1/bundle */
183     char targetPath[PATH_MAX_LEN] = {0};
184     ret = snprintf_s(targetPath, PATH_MAX_LEN, PATH_MAX_LEN - 1, "/mnt/sandbox/%u/%s/data/storage/el1/bundle",
185                      info->uid/ UID_BASE, varBundleName);
186     if (ret <= 0) {
187         APPSPAWN_LOGE("snprintf el1 bundle sandbox path failed, errno %{public}d", errno);
188         return APPSPAWN_ERROR_UTILS_MEM_FAIL;
189     }
190 
191     ret = MakeDirRec(targetPath, DIR_MODE, 1);
192     if (ret != 0) {
193         APPSPAWN_LOGE("mkdir %{public}s failed, errno %{public}d", targetPath, errno);
194         return APPSPAWN_SANDBOX_ERROR_MKDIR_FAIL;
195     }
196 
197     ret = umount2(targetPath, MNT_DETACH);
198     if (ret != 0) {
199         APPSPAWN_LOGW("umount2 %{public}s failed, errno %{public}d", targetPath, errno);
200     }
201 
202     SharedMountArgs arg = {
203         .srcPath = sourcePath,
204         .destPath = targetPath,
205         .fsType = nullptr,
206         .mountFlags = MS_BIND | MS_REC,
207         .options = nullptr,
208         .mountSharedFlag = MS_SHARED
209     };
210     ret = DoSharedMount(&arg);
211     if (ret != 0) {
212         APPSPAWN_LOGE("mount %{public}s shared failed, ret %{public}d", targetPath, ret);
213     }
214     std::string key = std::to_string(info->uid / UID_BASE) + "-" + std::string(varBundleName);
215     g_mountInfoMap[key]++;
216     return ret;
217 }
218 
MountWithFileMgr(const AppSpawningCtx * property,const AppDacInfo * info,const char * varBundleName)219 static int MountWithFileMgr(const AppSpawningCtx *property, const AppDacInfo *info, const char *varBundleName)
220 {
221     /* /mnt/user/<currentUserId>/nosharefs/docs */
222     char nosharefsDocsDir[PATH_MAX_LEN] = {0};
223     int ret = snprintf_s(nosharefsDocsDir, PATH_MAX_LEN, PATH_MAX_LEN - 1, "/mnt/user/%u/nosharefs/docs",
224                          info->uid / UID_BASE);
225     if (ret <= 0) {
226         APPSPAWN_LOGE("snprintf nosharefsDocsDir failed, errno %{public}d", errno);
227         return APPSPAWN_ERROR_UTILS_MEM_FAIL;
228     }
229 
230     /* /mnt/sandbox/<currentUser/<varBundleName>/storage/Users */
231     char storageUserPath[PATH_MAX_LEN] = {0};
232     ret = snprintf_s(storageUserPath, PATH_MAX_LEN, PATH_MAX_LEN - 1, "/mnt/sandbox/%u/%s/storage/Users",
233                      info->uid / UID_BASE, varBundleName);
234     if (ret <= 0) {
235         APPSPAWN_LOGE("snprintf storageUserPath failed, errno %{public}d", errno);
236         return APPSPAWN_ERROR_UTILS_MEM_FAIL;
237     }
238 
239     // Check whether the directory is a shared mount point
240     if (SetSandboxPathShared(storageUserPath)) {
241         APPSPAWN_LOGV("shared mountpoint is exist");
242         return 0;
243     }
244 
245     ret = MakeDirRec(storageUserPath, DIR_MODE, 1);
246     if (ret != 0) {
247         APPSPAWN_LOGE("mkdir %{public}s failed, errno %{public}d", storageUserPath, errno);
248         return APPSPAWN_SANDBOX_ERROR_MKDIR_FAIL;
249     }
250 
251     SharedMountArgs arg = {
252         .srcPath = nosharefsDocsDir,
253         .destPath = storageUserPath,
254         .fsType = nullptr,
255         .mountFlags = MS_BIND | MS_REC,
256         .options = nullptr,
257         .mountSharedFlag = MS_SHARED
258     };
259     ret = DoSharedMount(&arg);
260     if (ret != 0) {
261         APPSPAWN_LOGE("mount %{public}s shared failed, ret %{public}d", storageUserPath, ret);
262     }
263     return ret;
264 }
265 
MountWithOther(const AppSpawningCtx * property,const AppDacInfo * info,const char * varBundleName)266 static int MountWithOther(const AppSpawningCtx *property, const AppDacInfo *info, const char *varBundleName)
267 {
268     /* /mnt/user/<currentUserId>/sharefs/docs */
269     char sharefsDocsDir[PATH_MAX_LEN] = {0};
270     int ret = snprintf_s(sharefsDocsDir, PATH_MAX_LEN, PATH_MAX_LEN - 1, "/mnt/user/%u/sharefs/docs",
271                          info->uid / UID_BASE);
272     if (ret <= 0) {
273         APPSPAWN_LOGE("snprintf sharefsDocsDir failed, errno %{public}d", errno);
274         return APPSPAWN_ERROR_UTILS_MEM_FAIL;
275     }
276 
277     /* /mnt/sandbox/<currentUser/<varBundleName>/storage/Users */
278     char storageUserPath[PATH_MAX_LEN] = {0};
279     ret = snprintf_s(storageUserPath, PATH_MAX_LEN, PATH_MAX_LEN - 1, "/mnt/sandbox/%u/%s/storage/Users",
280                      info->uid / UID_BASE, varBundleName);
281     if (ret <= 0) {
282         APPSPAWN_LOGE("snprintf storageUserPath failed, errno %{public}d", errno);
283         return APPSPAWN_ERROR_UTILS_MEM_FAIL;
284     }
285 
286     // Check whether the directory is a shared mount point
287     if (SetSandboxPathShared(storageUserPath)) {
288         APPSPAWN_LOGV("shared mountpoint is exist");
289         return 0;
290     }
291 
292     ret = MakeDirRec(storageUserPath, DIR_MODE, 1);
293     if (ret != 0) {
294         APPSPAWN_LOGE("mkdir %{public}s failed, errno %{public}d", storageUserPath, errno);
295         return APPSPAWN_SANDBOX_ERROR_MKDIR_FAIL;
296     }
297 
298     char options[PATH_MAX_LEN] = {0};
299     ret = snprintf_s(options, PATH_MAX_LEN, PATH_MAX_LEN - 1, "override_support_delete,user_id=%u",
300                      info->uid / UID_BASE);
301     if (ret <= 0) {
302         APPSPAWN_LOGE("snprintf options failed, errno %{public}d", errno);
303         return APPSPAWN_ERROR_UTILS_MEM_FAIL;
304     }
305 #ifdef APPSPAWN_SUPPORT_NOSHAREFS
306     SharedMountArgs arg = {
307         .srcPath = sharefsDocsDir,
308         .destPath = storageUserPath,
309         .fsType = nullptr,
310         .mountFlags = MS_BIND | MS_REC,
311         .options = nullptr,
312         .mountSharedFlag = MS_SHARED
313     };
314 #else
315     SharedMountArgs arg = {
316         .srcPath = sharefsDocsDir,
317         .destPath = storageUserPath,
318         .fsType = "sharefs",
319         .mountFlags = MS_NODEV,
320         .options = options,
321         .mountSharedFlag = MS_SHARED
322     };
323 #endif
324     ret = DoSharedMount(&arg);
325     if (ret != 0) {
326         APPSPAWN_LOGE("mount %{public}s shared failed, ret %{public}d", storageUserPath, ret);
327     }
328     return ret;
329 }
330 
MountStorageUsers(const AppSpawningCtx * property,const AppDacInfo * info,const char * varBundleName)331 static void MountStorageUsers(const AppSpawningCtx *property, const AppDacInfo *info, const char *varBundleName)
332 {
333     int ret = 0;
334     int index = GetPermissionIndex(nullptr, "ohos.permission.FILE_ACCESS_MANAGER");
335     int checkRes = CheckAppPermissionFlagSet(property, static_cast<uint32_t>(index));
336     if (checkRes == 0) {
337         /* mount /mnt/user/<currentUserId>/sharefs/docs to /mnt/sandbox/<currentUserId>/<varBundleName>/storage/Users */
338         ret = MountWithOther(property, info, varBundleName);
339     } else {
340         /* mount /mnt/user/<currentUserId>/nosharefs/docs to /mnt/sandbox/<currentUserId>/<varBundleName>/storage/Users
341          */
342         ret = MountWithFileMgr(property, info, varBundleName);
343     }
344     if (ret != 0) {
345         APPSPAWN_LOGE("Update %{public}s storage dir failed, ret %{public}d",
346                       checkRes == 0 ? "sharefs dir" : "no sharefs dir", ret);
347     } else {
348         APPSPAWN_LOGI("Update %{public}s storage dir success", checkRes == 0 ? "sharefs dir" : "no sharefs dir");
349     }
350 }
351 
MountSharedMapItem(const AppSpawningCtx * property,const AppDacInfo * info,const char * varBundleName,const char * sandboxPathItem)352 static int MountSharedMapItem(const AppSpawningCtx *property, const AppDacInfo *info, const char *varBundleName,
353                               const char *sandboxPathItem)
354 {
355     /* /mnt/sandbox/<currentUserId>/<varBundleName>/data/storage/el<x> */
356     char sandboxPath[PATH_MAX_LEN] = {0};
357     int ret = snprintf_s(sandboxPath, PATH_MAX_LEN, PATH_MAX_LEN - 1, "/mnt/sandbox/%u/%s%s",
358                          info->uid / UID_BASE, varBundleName, sandboxPathItem);
359     if (ret <= 0) {
360         APPSPAWN_LOGE("snprintf sandboxPath failed, errno %{public}d", errno);
361         return APPSPAWN_ERROR_UTILS_MEM_FAIL;
362     }
363 
364     // Check whether the directory is a shared mount point
365     if (SetSandboxPathShared(sandboxPath)) {
366         APPSPAWN_LOGV("shared mountpoint is exist");
367         return 0;
368     }
369 
370     ret = MakeDirRec(sandboxPath, DIR_MODE, 1);
371     if (ret != 0) {
372         APPSPAWN_LOGE("mkdir %{public}s failed, errno %{public}d", sandboxPath, errno);
373         return APPSPAWN_SANDBOX_ERROR_MKDIR_FAIL;
374     }
375 
376     SharedMountArgs arg = {
377         .srcPath = sandboxPath,
378         .destPath = sandboxPath,
379         .fsType = nullptr,
380         .mountFlags = MS_BIND | MS_REC,
381         .options = nullptr,
382         .mountSharedFlag = MS_SHARED
383     };
384     ret = DoSharedMount(&arg);
385     if (ret != 0) {
386         APPSPAWN_LOGE("mount %{public}s shared failed, ret %{public}d", sandboxPath, ret);
387     }
388     return ret;
389 }
390 
MountSharedMap(const AppSpawningCtx * property,const AppDacInfo * info,const char * varBundleName)391 static void MountSharedMap(const AppSpawningCtx *property, const AppDacInfo *info, const char *varBundleName)
392 {
393     int length = sizeof(MOUNT_SHARED_MAP) / sizeof(MOUNT_SHARED_MAP[0]);
394     for (int i = 0; i < length; i++) {
395         if (MOUNT_SHARED_MAP[i].permission == nullptr) {
396             MountSharedMapItem(property, info, varBundleName, MOUNT_SHARED_MAP[i].sandboxPath);
397         } else {
398             int index = GetPermissionIndex(nullptr, MOUNT_SHARED_MAP[i].permission);
399             APPSPAWN_LOGV("mount dir on lock mountPermissionFlags %{public}d", index);
400             if (CheckAppPermissionFlagSet(property, static_cast<uint32_t>(index))) {
401                 MountSharedMapItem(property, info, varBundleName, MOUNT_SHARED_MAP[i].sandboxPath);
402             }
403         }
404     }
405     APPSPAWN_LOGI("mount shared map success");
406 }
407 
CheckPath(const std::string & name)408 static inline bool CheckPath(const std::string& name)
409 {
410     return !name.empty() && name != "." && name != ".." && name.find("/") == std::string::npos;
411 }
412 
DataGroupCtxNodeCompare(ListNode * node,void * data)413 static int DataGroupCtxNodeCompare(ListNode *node, void *data)
414 {
415     DataGroupCtx *existingNode = (DataGroupCtx *)ListEntry(node, DataGroupCtx, node);
416     DataGroupCtx *newNode = (DataGroupCtx *)data;
417     if (existingNode == nullptr || newNode == nullptr) {
418         APPSPAWN_LOGE("Invalid param");
419         return APPSPAWN_ARG_INVALID;
420     }
421 
422     // compare src path and sandbox path
423     bool isSrcPathEqual = (strcmp(existingNode->srcPath.path, newNode->srcPath.path) == 0);
424     bool isDestPathEqual = (strcmp(existingNode->destPath.path, newNode->destPath.path) == 0);
425 
426     return (isSrcPathEqual && isDestPathEqual) ? 0 : 1;
427 }
428 
AddDataGroupItemToQueue(AppSpawnMgr * content,const std::string & srcPath,const std::string & destPath,const std::string & dataGroupUuid)429 static int AddDataGroupItemToQueue(AppSpawnMgr *content, const std::string &srcPath, const std::string &destPath,
430                                    const std::string &dataGroupUuid)
431 {
432     DataGroupCtx *dataGroupNode = (DataGroupCtx *)calloc(1, sizeof(DataGroupCtx));
433     APPSPAWN_CHECK(dataGroupNode != nullptr, return APPSPAWN_ERROR_UTILS_MEM_FAIL, "Calloc dataGroupNode failed");
434     if (strcpy_s(dataGroupNode->srcPath.path, PATH_MAX_LEN - 1, srcPath.c_str()) != EOK ||
435         strcpy_s(dataGroupNode->destPath.path, PATH_MAX_LEN - 1, destPath.c_str()) != EOK ||
436         strcpy_s(dataGroupNode->dataGroupUuid, UUID_MAX_LEN, dataGroupUuid.c_str()) != EOK) {
437         APPSPAWN_LOGE("strcpy dataGroupNode->srcPath failed");
438         free(dataGroupNode);
439         return APPSPAWN_ERROR_UTILS_MEM_FAIL;
440     }
441     dataGroupNode->srcPath.pathLen = strlen(dataGroupNode->srcPath.path);
442     dataGroupNode->destPath.pathLen = strlen(dataGroupNode->destPath.path);
443     ListNode *node = OH_ListFind(&content->dataGroupCtxQueue, (void *)dataGroupNode, DataGroupCtxNodeCompare);
444     if (node != nullptr) {
445         APPSPAWN_LOGI("DataGroupCtxNode %{public}s is exist", dataGroupNode->srcPath.path);
446         free(dataGroupNode);
447         dataGroupNode = nullptr;
448         return 0;
449     }
450     OH_ListInit(&dataGroupNode->node);
451     OH_ListAddTail(&content->dataGroupCtxQueue, &dataGroupNode->node);
452     return 0;
453 }
454 
DumpDataGroupCtxQueue(const ListNode * front)455 static void DumpDataGroupCtxQueue(const ListNode *front)
456 {
457     if (front == nullptr) {
458         return;
459     }
460 
461     uint32_t count = 0;
462     ListNode *node = front->next;
463     while (node != front) {
464         DataGroupCtx *dataGroupNode = (DataGroupCtx *)ListEntry(node, DataGroupCtx, node);
465         count++;
466         APPSPAWN_LOGV("      ************************************** %{public}d", count);
467         APPSPAWN_LOGV("      srcPath: %{public}s", dataGroupNode->srcPath.path);
468         APPSPAWN_LOGV("      destPath: %{public}s", dataGroupNode->destPath.path);
469         APPSPAWN_LOGV("      uuid: %{public}s", dataGroupNode->dataGroupUuid);
470         node = node->next;
471     }
472 }
473 
GetJsonObjFromExtInfo(const AppSpawningCtx * property,const char * name)474 static inline cJSON *GetJsonObjFromExtInfo(const AppSpawningCtx *property, const char *name)
475 {
476     uint32_t size = 0;
477     char *extInfo = (char *)(GetAppSpawnMsgExtInfo(property->message, name, &size));
478     if (size == 0 || extInfo == nullptr) {
479         return nullptr;
480     }
481     APPSPAWN_LOGV("Get json name %{public}s value %{public}s", name, extInfo);
482     cJSON *extInfoJson = cJSON_Parse(extInfo);    // need to free
483     APPSPAWN_CHECK(extInfoJson != nullptr, return nullptr, "Invalid ext info %{public}s for %{public}s", extInfo, name);
484     return extInfoJson;
485 }
486 
ParseDataGroupList(AppSpawnMgr * content,const AppSpawningCtx * property,AppDacInfo * info,const char * varBundleName)487 static int ParseDataGroupList(AppSpawnMgr *content, const AppSpawningCtx *property, AppDacInfo *info,
488                               const char *varBundleName)
489 {
490     int ret = 0;
491     cJSON *dataGroupList = GetJsonObjFromExtInfo(property, DATA_GROUP_SOCKET_TYPE);
492     APPSPAWN_CHECK(dataGroupList != nullptr, return APPSPAWN_ARG_INVALID, "dataGroupList is empty");
493     APPSPAWN_CHECK(cJSON_IsArray(dataGroupList), cJSON_Delete(dataGroupList);
494         return APPSPAWN_ARG_INVALID, "dataGroupList is not Array");
495 
496     // Iterate through the array (assuming groups is an array)
497     cJSON *item = nullptr;
498     cJSON_ArrayForEach(item, dataGroupList) {
499         // Check if the item is valid
500         APPSPAWN_CHECK((item != nullptr && IsValidDataGroupItem(item)), break,
501                        "Element is not a valid data group item");
502 
503         cJSON *dirItem = cJSON_GetObjectItemCaseSensitive(item, "dir");
504         cJSON *uuidItem = cJSON_GetObjectItemCaseSensitive(item, "uuid");
505         if (dirItem == nullptr || !cJSON_IsString(dirItem) || uuidItem == nullptr || !cJSON_IsString(uuidItem)) {
506             APPSPAWN_LOGE("Data group element is invalid");
507             break;
508         }
509 
510         const char *srcPath = dirItem->valuestring;
511         APPSPAWN_CHECK(!CheckPath(srcPath), break, "src path %{public}s is invalid", srcPath);
512 
513         int elxValue = GetElxInfoFromDir(srcPath);
514         APPSPAWN_CHECK((elxValue >= EL2 && elxValue < ELX_MAX), break, "Get elx value failed");
515 
516         const DataGroupSandboxPathTemplate *templateItem = GetDataGroupArgTemplate(elxValue);
517         APPSPAWN_CHECK(templateItem != nullptr, break, "Get data group arg template failed");
518 
519         // If permission isn't null, need check permission flag
520         if (templateItem->permission != nullptr) {
521             int index = GetPermissionIndex(nullptr, templateItem->permission);
522             APPSPAWN_LOGV("mount dir no lock mount permission flag %{public}d", index);
523             if (CheckAppPermissionFlagSet(property, static_cast<uint32_t>(index)) == 0) {
524                 continue;
525             }
526         }
527         // sandboxPath: /mnt/sandbox/<currentUserId>/<varBundleName>/data/storage/el<x>/group
528         std::string sandboxPath = "/mnt/sandbox/" + std::to_string(info->uid / UID_BASE) + "/" + varBundleName
529                                  + templateItem->sandboxPath;
530 
531         ret = AddDataGroupItemToQueue(content, srcPath, sandboxPath, uuidItem->valuestring);
532         if (ret != 0) {
533             APPSPAWN_LOGE("Add datagroup item to dataGroupCtxQueue failed, el%{public}d", elxValue);
534             OH_ListRemoveAll(&content->dataGroupCtxQueue, nullptr);
535             break;
536         }
537     }
538     cJSON_Delete(dataGroupList);
539 
540     DumpDataGroupCtxQueue(&content->dataGroupCtxQueue);
541     return ret;
542 }
543 
UpdateDataGroupDirs(AppSpawnMgr * content)544 int UpdateDataGroupDirs(AppSpawnMgr *content)
545 {
546     if (content == nullptr) {
547         return APPSPAWN_ARG_INVALID;
548     }
549 
550     ListNode *node = content->dataGroupCtxQueue.next;
551     while (node != &content->dataGroupCtxQueue) {
552         DataGroupCtx *dataGroupNode = (DataGroupCtx *)ListEntry(node, DataGroupCtx, node);
553         char sandboxPath[PATH_MAX_LEN] = {0};
554         int ret = snprintf_s(sandboxPath, PATH_MAX_LEN, PATH_MAX_LEN - 1, "%s%s", dataGroupNode->destPath.path,
555                              dataGroupNode->dataGroupUuid);
556         if (ret <= 0) {
557             APPSPAWN_LOGE("snprintf_s sandboxPath: %{public}s failed, errno %{public}d",
558                           dataGroupNode->destPath.path, errno);
559             return APPSPAWN_ERROR_UTILS_MEM_FAIL;
560         }
561 
562         SharedMountArgs args = {
563             .srcPath = dataGroupNode->srcPath.path,
564             .destPath = sandboxPath,
565             .fsType = nullptr,
566             .mountFlags = MS_BIND | MS_REC,
567             .options = nullptr,
568             .mountSharedFlag = MS_SHARED
569         };
570         ret = DoSharedMount(&args);
571         if (ret != 0) {
572             APPSPAWN_LOGE("Shared mount %{public}s to %{public}s failed, errno %{public}d", args.srcPath,
573                           sandboxPath, ret);
574         }
575         node = node->next;
576     }
577     OH_ListRemoveAll(&content->dataGroupCtxQueue, nullptr);
578     return 0;
579 }
580 
ReplaceVarBundleName(const AppSpawningCtx * property)581 static std::string ReplaceVarBundleName(const AppSpawningCtx *property)
582 {
583     AppSpawnMsgBundleInfo *bundleInfo =
584         reinterpret_cast<AppSpawnMsgBundleInfo *>(GetAppProperty(property, TLV_BUNDLE_INFO));
585     if (bundleInfo == nullptr) {
586         return "";
587     }
588 
589     std::string tmpBundlePath = bundleInfo->bundleName;
590     std::ostringstream variablePackageName;
591     if (CheckAppSpawnMsgFlag(property->message, TLV_MSG_FLAGS, APP_FLAGS_CLONE_ENABLE)) {
592         variablePackageName << "+clone-" << bundleInfo->bundleIndex << "+" << bundleInfo->bundleName;
593         tmpBundlePath = variablePackageName.str();
594     }
595     return tmpBundlePath;
596 }
597 
MountDirToShared(AppSpawnMgr * content,const AppSpawningCtx * property)598 static void MountDirToShared(AppSpawnMgr *content, const AppSpawningCtx *property)
599 {
600     if (property == nullptr) {
601         return;
602     }
603 
604     AppDacInfo *info = reinterpret_cast<AppDacInfo *>(GetAppProperty(property, TLV_DAC_INFO));
605     std::string varBundleName = ReplaceVarBundleName(property);
606     if (info == nullptr || varBundleName == "") {
607         APPSPAWN_LOGE("Invalid app dac info or varBundleName");
608         return;
609     }
610 
611     MountEl1Bundle(property, info, varBundleName.c_str());
612 
613     if (IsUnlockStatus(info->uid)) {
614         SetAppSpawnMsgFlag(property->message, TLV_MSG_FLAGS, APP_FLAGS_UNLOCKED_STATUS);
615         return;
616     }
617 
618     MountSharedMap(property, info, varBundleName.c_str());
619     MountStorageUsers(property, info, varBundleName.c_str());
620     ParseDataGroupList(content, property, info, varBundleName.c_str());
621 
622     std::string lockSbxPathStamp = "/mnt/sandbox/" + std::to_string(info->uid / UID_BASE) + "/";
623     lockSbxPathStamp += CheckAppMsgFlagsSet(property, APP_FLAGS_ISOLATED_SANDBOX_TYPE) ? "isolated/" : "";
624     lockSbxPathStamp += varBundleName;
625     lockSbxPathStamp += "_locked";
626     int ret = MakeDirRec(lockSbxPathStamp.c_str(), DIR_MODE, 1);
627     if (ret != 0) {
628         APPSPAWN_LOGE("mkdir %{public}s failed, errno %{public}d", lockSbxPathStamp.c_str(), errno);
629     }
630 }
631 #endif
632 
MountToShared(AppSpawnMgr * content,const AppSpawningCtx * property)633 int MountToShared(AppSpawnMgr *content, const AppSpawningCtx *property)
634 {
635 #ifndef APPSPAWN_SANDBOX_NEW
636     // mount dynamic directory to shared
637     MountDirToShared(content, property);
638 #endif
639     return 0;
640 }
641 
MODULE_CONSTRUCTOR(void)642 MODULE_CONSTRUCTOR(void)
643 {
644 #ifndef APPSPAWN_SANDBOX_NEW
645     (void)AddServerStageHook(STAGE_SERVER_LOCK, HOOK_PRIO_COMMON, UpdateDataGroupDirs);
646 #endif
647 }
648