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 16#include <sys/mount.h> 17#include <sys/stat.h> 18#include <sys/syscall.h> 19#include <sys/types.h> 20 21#include "appspawn_msg.h" 22#include "appspawn_sandbox.h" 23#include "appspawn_utils.h" 24#include "json_utils.h" 25#include "securec.h" 26 27#define SANDBOX_GROUP_PATH "/data/storage/el2/group/" 28#define SANDBOX_INSTALL_PATH "/data/storage/el1/bundle/" 29#define SANDBOX_OVERLAY_PATH "/data/storage/overlay/" 30 31static inline bool CheckPath(const char *name) 32{ 33 return name != NULL && strcmp(name, ".") != 0 && strcmp(name, "..") != 0 && strstr(name, "/") == NULL; 34} 35 36APPSPAWN_STATIC int MountAllHsp(const SandboxContext *context, const cJSON *hsps) 37{ 38 APPSPAWN_CHECK(context != NULL && hsps != NULL, return -1, "Invalid context or hsps"); 39 40 int ret = 0; 41 cJSON *bundles = cJSON_GetObjectItemCaseSensitive(hsps, "bundles"); 42 cJSON *modules = cJSON_GetObjectItemCaseSensitive(hsps, "modules"); 43 cJSON *versions = cJSON_GetObjectItemCaseSensitive(hsps, "versions"); 44 APPSPAWN_CHECK(bundles != NULL && cJSON_IsArray(bundles), return -1, "MountAllHsp: invalid bundles"); 45 APPSPAWN_CHECK(modules != NULL && cJSON_IsArray(modules), return -1, "MountAllHsp: invalid modules"); 46 APPSPAWN_CHECK(versions != NULL && cJSON_IsArray(versions), return -1, "MountAllHsp: invalid versions"); 47 int count = cJSON_GetArraySize(bundles); 48 APPSPAWN_CHECK(count == cJSON_GetArraySize(modules), return -1, "MountAllHsp: sizes are not same"); 49 APPSPAWN_CHECK(count == cJSON_GetArraySize(versions), return -1, "MountAllHsp: sizes are not same"); 50 51 APPSPAWN_LOGI("MountAllHsp app: %{public}s, count: %{public}d", context->bundleName, count); 52 for (int i = 0; i < count; i++) { 53 char *libBundleName = cJSON_GetStringValue(cJSON_GetArrayItem(bundles, i)); 54 char *libModuleName = cJSON_GetStringValue(cJSON_GetArrayItem(modules, i)); 55 char *libVersion = cJSON_GetStringValue(cJSON_GetArrayItem(versions, i)); 56 APPSPAWN_CHECK(CheckPath(libBundleName) && CheckPath(libModuleName) && CheckPath(libVersion), 57 return -1, "MountAllHsp: path error"); 58 59 // src path 60 int len = sprintf_s(context->buffer[0].buffer, context->buffer[0].bufferLen, "%s%s/%s/%s", 61 PHYSICAL_APP_INSTALL_PATH, libBundleName, libVersion, libModuleName); 62 APPSPAWN_CHECK(len > 0, return -1, "Failed to format install path"); 63 // sandbox path 64 len = sprintf_s(context->buffer[1].buffer, context->buffer[1].bufferLen, "%s%s%s/%s", 65 context->rootPath, SANDBOX_INSTALL_PATH, libBundleName, libModuleName); 66 APPSPAWN_CHECK(len > 0, return -1, "Failed to format install path"); 67 68 CreateSandboxDir(context->buffer[1].buffer, FILE_MODE); 69 MountArg mountArg = { 70 context->buffer[0].buffer, context->buffer[1].buffer, NULL, MS_REC | MS_BIND, NULL, MS_SLAVE 71 }; 72 ret = SandboxMountPath(&mountArg); 73 APPSPAWN_CHECK(ret == 0, return ret, "mount library failed %{public}d", ret); 74 } 75 return ret; 76} 77 78static inline char *GetLastPath(const char *libPhysicalPath) 79{ 80 char *tmp = GetLastStr(libPhysicalPath, "/"); 81 return tmp + 1; 82} 83 84APPSPAWN_STATIC int MountAllGroup(const SandboxContext *context, const cJSON *groups) 85{ 86 APPSPAWN_CHECK(context != NULL && groups != NULL, return -1, "Invalid context or group"); 87 mode_t mountFlags = MS_REC | MS_BIND; 88 mode_t mountSharedFlag = MS_SLAVE; 89 if (CheckAppSpawnMsgFlag(context->message, TLV_MSG_FLAGS, APP_FLAGS_ISOLATED_SANDBOX)) { 90 APPSPAWN_LOGV("MountAllGroup falsg is isolated"); 91 mountSharedFlag |= MS_REMOUNT | MS_NODEV | MS_RDONLY | MS_BIND; 92 } 93 int ret = 0; 94 cJSON *dataGroupIds = cJSON_GetObjectItemCaseSensitive(groups, "dataGroupId"); 95 cJSON *gids = cJSON_GetObjectItemCaseSensitive(groups, "gid"); 96 cJSON *dirs = cJSON_GetObjectItemCaseSensitive(groups, "dir"); 97 APPSPAWN_CHECK(dataGroupIds != NULL && cJSON_IsArray(dataGroupIds), 98 return -1, "MountAllGroup: invalid dataGroupIds"); 99 APPSPAWN_CHECK(gids != NULL && cJSON_IsArray(gids), return -1, "MountAllGroup: invalid gids"); 100 APPSPAWN_CHECK(dirs != NULL && cJSON_IsArray(dirs), return -1, "MountAllGroup: invalid dirs"); 101 int count = cJSON_GetArraySize(dataGroupIds); 102 APPSPAWN_CHECK(count == cJSON_GetArraySize(gids), return -1, "MountAllGroup: sizes are not same"); 103 APPSPAWN_CHECK(count == cJSON_GetArraySize(dirs), return -1, "MountAllGroup: sizes are not same"); 104 105 APPSPAWN_LOGI("MountAllGroup: app: %{public}s, count: %{public}d", context->bundleName, count); 106 for (int i = 0; i < count; i++) { 107 cJSON *dirJson = cJSON_GetArrayItem(dirs, i); 108 APPSPAWN_CHECK(dirJson != NULL && cJSON_IsString(dirJson), return -1, "MountAllGroup: invalid dirJson"); 109 const char *libPhysicalPath = cJSON_GetStringValue(dirJson); 110 APPSPAWN_CHECK(!CheckPath(libPhysicalPath), return -1, "MountAllGroup: path error"); 111 112 char *dataGroupUuid = GetLastPath(libPhysicalPath); 113 int len = sprintf_s(context->buffer[0].buffer, context->buffer[0].bufferLen, "%s%s%s", 114 context->rootPath, SANDBOX_GROUP_PATH, dataGroupUuid); 115 APPSPAWN_CHECK(len > 0, return -1, "Failed to format install path"); 116 APPSPAWN_LOGV("MountAllGroup src: '%{public}s' =>'%{public}s'", libPhysicalPath, context->buffer[0].buffer); 117 118 CreateSandboxDir(context->buffer[0].buffer, FILE_MODE); 119 MountArg mountArg = {libPhysicalPath, context->buffer[0].buffer, NULL, mountFlags, NULL, mountSharedFlag}; 120 ret = SandboxMountPath(&mountArg); 121 APPSPAWN_CHECK(ret == 0, return ret, "mount library failed %{public}d", ret); 122 } 123 return ret; 124} 125 126typedef struct { 127 const SandboxContext *sandboxContext; 128 uint32_t srcSetLen; 129 char *mountedSrcSet; 130} OverlayContext; 131 132static int SetOverlayAppPath(const char *hapPath, void *context) 133{ 134 APPSPAWN_LOGV("SetOverlayAppPath '%{public}s'", hapPath); 135 OverlayContext *overlayContext = (OverlayContext *)context; 136 const SandboxContext *sandboxContext = overlayContext->sandboxContext; 137 138 // src path 139 char *tmp = GetLastStr(hapPath, "/"); 140 if (tmp == NULL) { 141 return 0; 142 } 143 int ret = strncpy_s(sandboxContext->buffer[0].buffer, 144 sandboxContext->buffer[0].bufferLen, hapPath, tmp - (char *)hapPath); 145 APPSPAWN_CHECK(ret == 0, return ret, "mount library failed %{public}d", ret); 146 147 if (strstr(overlayContext->mountedSrcSet, sandboxContext->buffer[0].buffer) != NULL) { 148 APPSPAWN_LOGV("%{public}s have mounted before, no need to mount twice.", sandboxContext->buffer[0].buffer); 149 return 0; 150 } 151 ret = strcat_s(overlayContext->mountedSrcSet, overlayContext->srcSetLen, "|"); 152 APPSPAWN_CHECK(ret == 0, return ret, "Fail to add src path to set %{public}s", "|"); 153 ret = strcat_s(overlayContext->mountedSrcSet, overlayContext->srcSetLen, sandboxContext->buffer[0].buffer); 154 APPSPAWN_CHECK(ret == 0, return ret, "Fail to add src path to set %{public}s", sandboxContext->buffer[0].buffer); 155 156 // sandbox path 157 tmp = GetLastStr(sandboxContext->buffer[0].buffer, "/"); 158 if (tmp == NULL) { 159 return 0; 160 } 161 int len = sprintf_s(sandboxContext->buffer[1].buffer, sandboxContext->buffer[1].bufferLen, "%s%s", 162 sandboxContext->rootPath, SANDBOX_OVERLAY_PATH); 163 APPSPAWN_CHECK(len > 0, return -1, "Failed to format install path"); 164 ret = strcat_s(sandboxContext->buffer[1].buffer, sandboxContext->buffer[1].bufferLen - len, tmp + 1); 165 APPSPAWN_CHECK(ret == 0, return ret, "mount library failed %{public}d", ret); 166 APPSPAWN_LOGV("SetOverlayAppPath path: '%{public}s' => '%{public}s'", 167 sandboxContext->buffer[0].buffer, sandboxContext->buffer[1].buffer); 168 169 (void)MakeDirRec(sandboxContext->buffer[1].buffer, FILE_MODE, 1); 170 MountArg mountArg = { 171 sandboxContext->buffer[0].buffer, sandboxContext->buffer[1].buffer, NULL, MS_REC | MS_BIND, NULL, MS_SHARED 172 }; 173 int retMount = SandboxMountPath(&mountArg); 174 if (retMount != 0) { 175 APPSPAWN_LOGE("Fail to mount overlay path, src is %{public}s.", hapPath); 176 ret = retMount; 177 } 178 return ret; 179} 180 181static int SetOverlayAppSandboxConfig(const SandboxContext *context, const char *overlayInfo) 182{ 183 APPSPAWN_CHECK(context != NULL && overlayInfo != NULL, return -1, "Invalid context or overlayInfo"); 184 OverlayContext overlayContext; 185 overlayContext.sandboxContext = context; 186 overlayContext.srcSetLen = strlen(overlayInfo); 187 overlayContext.mountedSrcSet = (char *)calloc(1, overlayContext.srcSetLen + 1); 188 APPSPAWN_CHECK(overlayContext.mountedSrcSet != NULL, return -1, "Failed to create mountedSrcSet"); 189 *(overlayContext.mountedSrcSet + overlayContext.srcSetLen) = '\0'; 190 int ret = StringSplit(overlayInfo, "|", (void *)&overlayContext, SetOverlayAppPath); 191 APPSPAWN_LOGV("overlayContext->mountedSrcSet: '%{public}s'", overlayContext.mountedSrcSet); 192 free(overlayContext.mountedSrcSet); 193 return ret; 194} 195 196static inline cJSON *GetJsonObjFromProperty(const SandboxContext *context, const char *name) 197{ 198 uint32_t size = 0; 199 char *extInfo = (char *)(GetAppSpawnMsgExtInfo(context->message, name, &size)); 200 if (size == 0 || extInfo == NULL) { 201 return NULL; 202 } 203 APPSPAWN_LOGV("Get json name %{public}s value %{public}s", name, extInfo); 204 cJSON *root = cJSON_Parse(extInfo); 205 APPSPAWN_CHECK(root != NULL, return NULL, "Invalid ext info %{public}s for %{public}s", extInfo, name); 206 return root; 207} 208 209static int ProcessHSPListConfig(const SandboxContext *context, const AppSpawnSandboxCfg *appSandBox, const char *name) 210{ 211 cJSON *root = GetJsonObjFromProperty(context, name); 212 APPSPAWN_CHECK_ONLY_EXPER(root != NULL, return 0); 213 int ret = MountAllHsp(context, root); 214 cJSON_Delete(root); 215 return ret; 216} 217 218static int ProcessDataGroupConfig(const SandboxContext *context, const AppSpawnSandboxCfg *appSandBox, const char *name) 219{ 220 cJSON *root = GetJsonObjFromProperty(context, name); 221 APPSPAWN_CHECK_ONLY_EXPER(root != NULL, return 0); 222 int ret = MountAllGroup(context, root); 223 cJSON_Delete(root); 224 return ret; 225} 226 227static int ProcessOverlayAppConfig(const SandboxContext *context, 228 const AppSpawnSandboxCfg *appSandBox, const char *name) 229{ 230 uint32_t size = 0; 231 char *extInfo = (char *)GetAppSpawnMsgExtInfo(context->message, name, &size); 232 if (size == 0 || extInfo == NULL) { 233 return 0; 234 } 235 APPSPAWN_LOGV("ProcessOverlayAppConfig name %{public}s value %{public}s", name, extInfo); 236 return SetOverlayAppSandboxConfig(context, extInfo); 237} 238 239struct ListNode g_sandboxExpandCfgList = {&g_sandboxExpandCfgList, &g_sandboxExpandCfgList}; 240static int AppSandboxExpandAppCfgCompareName(ListNode *node, void *data) 241{ 242 AppSandboxExpandAppCfgNode *varNode = ListEntry(node, AppSandboxExpandAppCfgNode, node); 243 return strncmp((char *)data, varNode->name, strlen(varNode->name)); 244} 245 246static int AppSandboxExpandAppCfgComparePrio(ListNode *node1, ListNode *node2) 247{ 248 AppSandboxExpandAppCfgNode *varNode1 = ListEntry(node1, AppSandboxExpandAppCfgNode, node); 249 AppSandboxExpandAppCfgNode *varNode2 = ListEntry(node2, AppSandboxExpandAppCfgNode, node); 250 return varNode1->prio - varNode2->prio; 251} 252 253static const AppSandboxExpandAppCfgNode *GetAppSandboxExpandAppCfg(const char *name) 254{ 255 ListNode *node = OH_ListFind(&g_sandboxExpandCfgList, (void *)name, AppSandboxExpandAppCfgCompareName); 256 if (node == NULL) { 257 return NULL; 258 } 259 return ListEntry(node, AppSandboxExpandAppCfgNode, node); 260} 261 262int RegisterExpandSandboxCfgHandler(const char *name, int prio, ProcessExpandSandboxCfg handleExpandCfg) 263{ 264 APPSPAWN_CHECK_ONLY_EXPER(name != NULL && handleExpandCfg != NULL, return APPSPAWN_ARG_INVALID); 265 if (GetAppSandboxExpandAppCfg(name) != NULL) { 266 return APPSPAWN_NODE_EXIST; 267 } 268 269 size_t len = APPSPAWN_ALIGN(strlen(name) + 1); 270 AppSandboxExpandAppCfgNode *node = (AppSandboxExpandAppCfgNode *)(malloc(sizeof(AppSandboxExpandAppCfgNode) + len)); 271 APPSPAWN_CHECK(node != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to create sandbox"); 272 // ext data init 273 OH_ListInit(&node->node); 274 node->cfgHandle = handleExpandCfg; 275 node->prio = prio; 276 int ret = strcpy_s(node->name, len, name); 277 APPSPAWN_CHECK(ret == 0, free(node); 278 return -1, "Failed to copy name %{public}s", name); 279 OH_ListAddWithOrder(&g_sandboxExpandCfgList, &node->node, AppSandboxExpandAppCfgComparePrio); 280 return 0; 281} 282 283int ProcessExpandAppSandboxConfig(const SandboxContext *context, const AppSpawnSandboxCfg *appSandBox, const char *name) 284{ 285 APPSPAWN_CHECK_ONLY_EXPER(context != NULL && appSandBox != NULL, return APPSPAWN_ARG_INVALID); 286 APPSPAWN_CHECK_ONLY_EXPER(name != NULL, return APPSPAWN_ARG_INVALID); 287 APPSPAWN_LOGV("ProcessExpandAppSandboxConfig %{public}s.", name); 288 const AppSandboxExpandAppCfgNode *node = GetAppSandboxExpandAppCfg(name); 289 if (node != NULL && node->cfgHandle != NULL) { 290 return node->cfgHandle(context, appSandBox, name); 291 } 292 return 0; 293} 294 295void AddDefaultExpandAppSandboxConfigHandle(void) 296{ 297 RegisterExpandSandboxCfgHandler("HspList", 0, ProcessHSPListConfig); 298 RegisterExpandSandboxCfgHandler("DataGroup", 1, ProcessDataGroupConfig); 299 RegisterExpandSandboxCfgHandler("Overlay", 2, ProcessOverlayAppConfig); // 2 priority 300} 301 302void ClearExpandAppSandboxConfigHandle(void) 303{ 304 OH_ListRemoveAll(&g_sandboxExpandCfgList, NULL); 305} 306