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