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