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 <errno.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <sys/ioctl.h>
21 #include "securec.h"
22
23 #include "cJSON.h"
24 #include "appspawn_adapter.h"
25 #include "appspawn_hook.h"
26 #include "appspawn_manager.h"
27 #include "appspawn_utils.h"
28
29 #define APP_ENCAPS "encaps"
30 #define APP_OHOS_ENCAPS_COUNT_KEY "ohos.encaps.count"
31 #define APP_OHOS_ENCAPS_FORK_KEY "ohos.encaps.fork.count"
32
33 #define MSG_EXT_NAME_MAX_DECIMAL 10
34 #define OH_APP_MAX_PIDS_NUM 512
35 #define OH_ENCAPS_PROC_TYPE_BASE 0x18
36 #define OH_ENCAPS_PERMISSION_TYPE_BASE 0x1A
37 #define OH_ENCAPS_MAGIC 'E'
38 #define OH_PROC_HAP 4
39 #define OH_ENCAPS_DEFAULT_FLAG 0
40 #define OH_ENCAPS_DEFAULT_STR ""
41
42 #define SET_ENCAPS_PROC_TYPE_CMD _IOW(OH_ENCAPS_MAGIC, OH_ENCAPS_PROC_TYPE_BASE, uint32_t)
43 #define SET_ENCAPS_PERMISSION_TYPE_CMD _IOW(OH_ENCAPS_MAGIC, OH_ENCAPS_PERMISSION_TYPE_BASE, char *)
44
45 typedef enum {
46 ENCAPS_PROC_TYPE_MODE, // enable the encaps attribute of a process
47 ENCAPS_PERMISSION_TYPE_MODE, // set the encaps permission of a process
48 ENCAPS_MAX_TYPE_MODE
49 } AppSpawnEncapsBaseType;
50
OpenEncapsFile(void)51 static int OpenEncapsFile(void)
52 {
53 int fd = 0;
54 fd = open("dev/encaps", O_RDWR);
55 if (fd < 0) {
56 APPSPAWN_LOGW("Failed to open encaps file errno: %{public}d", errno);
57 }
58 return fd;
59 }
60
WriteEncapsInfo(int fd,AppSpawnEncapsBaseType encapsType,const char * encapsInfo,uint32_t flag)61 static int WriteEncapsInfo(int fd, AppSpawnEncapsBaseType encapsType, const char *encapsInfo, uint32_t flag)
62 {
63 if (encapsInfo == NULL) {
64 return APPSPAWN_ARG_INVALID;
65 }
66 APPSPAWN_LOGV("root object: %{public}s", encapsInfo);
67
68 int ret = 0;
69 switch (encapsType) {
70 case ENCAPS_PROC_TYPE_MODE:
71 ret = ioctl(fd, SET_ENCAPS_PROC_TYPE_CMD, &flag);
72 break;
73 case ENCAPS_PERMISSION_TYPE_MODE:
74 ret = ioctl(fd, SET_ENCAPS_PERMISSION_TYPE_CMD, encapsInfo);
75 break;
76 default:
77 break;
78 }
79 if (ret != 0) {
80 APPSPAWN_LOGE("Encaps the setup failed ret: %{public}d fd: %{public}d maxPid: %{public}s", ret, fd, encapsInfo);
81 return ret;
82 }
83 return 0;
84 }
85
EnableEncapsForProc(int encapsFileFd)86 APPSPAWN_STATIC int EnableEncapsForProc(int encapsFileFd)
87 {
88 uint32_t flag = OH_PROC_HAP;
89 return WriteEncapsInfo(encapsFileFd, ENCAPS_PROC_TYPE_MODE, OH_ENCAPS_DEFAULT_STR, flag);
90 }
91
SpawnGetMaxPids(AppSpawnMgr * content,AppSpawningCtx * property)92 static uint32_t SpawnGetMaxPids(AppSpawnMgr *content, AppSpawningCtx *property)
93 {
94 uint32_t len = 0;
95 char *pidMaxStr = GetAppPropertyExt(property, MSG_EXT_NAME_MAX_CHILD_PROCCESS_MAX, &len);
96 APPSPAWN_CHECK_ONLY_EXPER(pidMaxStr != NULL, return 0);
97 uint32_t maxNum = 0;
98 // string convert to value
99 if (len != 0) {
100 char *endPtr = NULL;
101 maxNum = strtoul(pidMaxStr, &endPtr, MSG_EXT_NAME_MAX_DECIMAL);
102 if (endPtr == pidMaxStr || *endPtr != '\0') {
103 APPSPAWN_LOGW("Failed to convert a character string to a value.(ignore), endPtr: %{public}s", endPtr);
104 return 0;
105 }
106 return maxNum;
107 }
108 return 0;
109 }
110
111 /* set ohos.encaps.fork.count to encaps */
SpawnSetMaxPids(AppSpawnMgr * content,AppSpawningCtx * property,cJSON * encaps)112 static int SpawnSetMaxPids(AppSpawnMgr *content, AppSpawningCtx *property, cJSON *encaps)
113 {
114 uint32_t maxPidCount = 0;
115 if (GetAppSpawnMsgType(property) != MSG_SPAWN_NATIVE_PROCESS) {
116 maxPidCount = SpawnGetMaxPids(content, property);
117 }
118 if (maxPidCount == 0 || maxPidCount > OH_APP_MAX_PIDS_NUM) {
119 APPSPAWN_LOGV("Don't need to set pid max count. Use default pid max");
120 return APPSPAWN_PIDMGR_DEFAULT_PID_MAX;
121 }
122
123 if (cJSON_AddNumberToObject(encaps, APP_OHOS_ENCAPS_FORK_KEY, maxPidCount) == NULL) {
124 APPSPAWN_LOGV("Add number to object failed.(ignore)");
125 return APPSPAWN_PIDMGR_DEFAULT_PID_MAX;
126 }
127
128 return 0;
129 }
130
GetJsonObjFromExtInfo(const AppSpawningCtx * property,const char * name)131 static inline cJSON *GetJsonObjFromExtInfo(const AppSpawningCtx *property, const char *name)
132 {
133 uint32_t size = 0;
134 char *extInfo = (char *)(GetAppSpawnMsgExtInfo(property->message, name, &size));
135 if (size == 0 || extInfo == NULL) {
136 return NULL;
137 }
138 APPSPAWN_LOGV("Get json name %{public}s value %{public}s", name, extInfo);
139 cJSON *extInfoJson = cJSON_Parse(extInfo); // need to free
140 APPSPAWN_CHECK(extInfoJson != NULL, return NULL, "Invalid ext info %{public}s for %{public}s", extInfo, name);
141 return extInfoJson;
142 }
143
AddPermissionArrayToItem(cJSON * encaps,const char * key,cJSON * permissionItemArr)144 APPSPAWN_STATIC int AddPermissionArrayToItem(cJSON *encaps, const char *key, cJSON *permissionItemArr)
145 {
146 cJSON *arrayItem = permissionItemArr->child;
147 cJSON *newArray = cJSON_CreateArray();
148 if (newArray == NULL) {
149 return APPSPAWN_ERROR_UTILS_CREATE_JSON_FAIL;
150 }
151 if (!cJSON_AddItemToObject(encaps, key, newArray)) {
152 cJSON_Delete(newArray);
153 return APPSPAWN_ERROR_UTILS_ADD_JSON_FAIL;
154 }
155
156 while (arrayItem) {
157 cJSON *newItem = NULL;
158 if (cJSON_IsNumber(arrayItem)) {
159 newItem = cJSON_CreateNumber(arrayItem->valueint);
160 } else if (cJSON_IsString(arrayItem)) {
161 newItem = cJSON_CreateString(arrayItem->valuestring);
162 } else if (cJSON_IsBool(arrayItem)) {
163 newItem = cJSON_CreateBool(arrayItem->valueint);
164 }
165
166 if (newItem == NULL || !cJSON_AddItemToArray(newArray, newItem)) {
167 cJSON_Delete(newItem);
168 return APPSPAWN_ERROR_UTILS_ADD_JSON_FAIL;
169 }
170 arrayItem = arrayItem->next;
171 }
172
173 return 0;
174 }
175
AddPermissionItemToEncaps(cJSON * encaps,cJSON * permissionItem)176 APPSPAWN_STATIC int AddPermissionItemToEncaps(cJSON *encaps, cJSON *permissionItem)
177 {
178 const char *key = permissionItem->string;
179 if (cJSON_IsNumber(permissionItem)) {
180 if (!cJSON_AddNumberToObject(encaps, key, permissionItem->valueint)) {
181 return APPSPAWN_ERROR_UTILS_ADD_JSON_FAIL;
182 }
183 } else if (cJSON_IsString(permissionItem)) {
184 if (!cJSON_AddStringToObject(encaps, key, permissionItem->valuestring)) {
185 return APPSPAWN_ERROR_UTILS_ADD_JSON_FAIL;
186 }
187 } else if (cJSON_IsBool(permissionItem)) {
188 if (!cJSON_AddBoolToObject(encaps, key, permissionItem->valueint)) {
189 return APPSPAWN_ERROR_UTILS_ADD_JSON_FAIL;
190 }
191 } else if (cJSON_IsArray(permissionItem)) {
192 if (AddPermissionArrayToItem(encaps, key, permissionItem) != 0) {
193 return APPSPAWN_ERROR_UTILS_ADD_JSON_FAIL;
194 }
195 }
196
197 return 0;
198 }
199
AddPermissionToEncaps(cJSON * extInfoJson,cJSON * encaps,uint32_t * permissionCount)200 APPSPAWN_STATIC int AddPermissionToEncaps(cJSON *extInfoJson, cJSON *encaps, uint32_t *permissionCount)
201 {
202 // Get ohos.encaps.count
203 cJSON *countJson = cJSON_GetObjectItem(extInfoJson, "ohos.encaps.count");
204 int encapsCount = 0;
205 if (cJSON_IsNumber(countJson)) {
206 encapsCount = countJson->valueint;
207 }
208
209 // Check input count and permissions size
210 cJSON *permissions = cJSON_GetObjectItemCaseSensitive(extInfoJson, "permissions");
211 int count = cJSON_GetArraySize(permissions);
212 if (encapsCount != count) {
213 APPSPAWN_LOGE("Invalid args, encaps count: %{public}d, permission count: %{public}d", encapsCount, count);
214 return APPSPAWN_ARG_INVALID;
215 }
216
217 // If permissionName and permissionValue are obtained, they need to be written
218 // in the {"permissionName1":"permissionValue1", "permissionName2":"permissionValue2", ...} in the encaps.
219 for (int i = 0; i < count; i++) {
220 // get single permission, such as {"permissionName1":"permissionValue1"}
221 cJSON *permission = cJSON_GetArrayItem(permissions, i);
222 if (permission == NULL) {
223 APPSPAWN_LOGE("encaps get single permission failed.");
224 return APPSPAWN_ERROR_UTILS_DECODE_JSON_FAIL;
225 }
226
227 // only one object in {}. So we only need to get first object.
228 // such as key:"permissionName1", value:"permissionValue1"
229 cJSON *permissionItem = permission->child;
230 if (permissionItem == NULL) {
231 APPSPAWN_LOGE("encaps get permission item failed.");
232 return APPSPAWN_ERROR_UTILS_DECODE_JSON_FAIL;
233 }
234
235 if (AddPermissionItemToEncaps(encaps, permissionItem) != 0) {
236 APPSPAWN_LOGV("Add permission to object failed.(ignore)");
237 return APPSPAWN_ERROR_UTILS_ADD_JSON_FAIL;
238 }
239 }
240 *permissionCount += count;
241
242 return 0;
243 }
244
SpawnSetPermissions(AppSpawnMgr * content,AppSpawningCtx * property,cJSON * encaps,uint32_t * count)245 static int SpawnSetPermissions(AppSpawnMgr *content, AppSpawningCtx *property, cJSON *encaps, uint32_t *count)
246 {
247 cJSON *extInfoJson = GetJsonObjFromExtInfo(property, MSG_EXT_NAME_JIT_PERMISSIONS);
248 if (extInfoJson == NULL) {
249 return APPSPAWN_ARG_INVALID;
250 }
251
252 int ret = AddPermissionToEncaps(extInfoJson, encaps, count);
253 if (ret != 0) {
254 APPSPAWN_LOGW("Add permission to object failed.(ignore), ret: %{public}d", ret);
255 }
256
257 cJSON_Delete(extInfoJson);
258 return ret;
259 }
260
AddMembersToEncaps(AppSpawnMgr * content,AppSpawningCtx * property,cJSON * encaps)261 static int AddMembersToEncaps(AppSpawnMgr *content, AppSpawningCtx *property, cJSON *encaps)
262 {
263 uint32_t encapsPermissionCount = 0;
264 // need set ohos.encaps.count to encaps firstly
265 if (cJSON_AddNumberToObject(encaps, APP_OHOS_ENCAPS_COUNT_KEY, encapsPermissionCount) == NULL) {
266 APPSPAWN_LOGV("Set ohos.encaps.count to object failed.(ignore)");
267 return APPSPAWN_ERROR_UTILS_ADD_JSON_FAIL;
268 }
269
270 int ret = SpawnSetMaxPids(content, property, encaps);
271 if (ret != 0) {
272 APPSPAWN_LOGV("Can't set max pids to encaps object.(ignore), ret: %{public}d", ret);
273 } else {
274 encapsPermissionCount += 1;
275 }
276
277 uint32_t count = 0;
278 ret = SpawnSetPermissions(content, property, encaps, &count);
279 if (ret != 0) {
280 APPSPAWN_LOGV("Can't set JIT permission to encaps object.(ignore), ret: %{public}d", ret);
281 } else {
282 encapsPermissionCount += count;
283 }
284
285 if (encapsPermissionCount == 0) {
286 return APPSPAWN_ERROR_UTILS_ADD_JSON_FAIL; // Don't need set permission
287 }
288
289 cJSON *encapsCountItem = cJSON_GetObjectItem(encaps, APP_OHOS_ENCAPS_COUNT_KEY);
290 if (encapsCountItem != NULL) {
291 cJSON_SetNumberValue(encapsCountItem, encapsPermissionCount);
292 }
293
294 return 0;
295 }
296
SpawnBuildEncaps(AppSpawnMgr * content,AppSpawningCtx * property,char ** encapsInfoStr)297 static int SpawnBuildEncaps(AppSpawnMgr *content, AppSpawningCtx *property, char **encapsInfoStr)
298 {
299 // Create root object
300 cJSON *root = cJSON_CreateObject();
301 if (root == NULL) {
302 return APPSPAWN_ERROR_UTILS_CREATE_JSON_FAIL;
303 }
304
305 // Create encaps object
306 cJSON *encaps = cJSON_CreateObject();
307 if (encaps == NULL) {
308 cJSON_Delete(root);
309 return APPSPAWN_ERROR_UTILS_CREATE_JSON_FAIL;
310 }
311
312 int ret = AddMembersToEncaps(content, property, encaps);
313 if (ret != 0) {
314 APPSPAWN_LOGW("Add members to encaps object failed.(ignore), ret: %{public}d", ret);
315 cJSON_Delete(root);
316 cJSON_Delete(encaps);
317 return ret;
318 }
319
320 if (cJSON_AddItemToObject(root, APP_ENCAPS, encaps) != true) { // add encaps object to root
321 cJSON_Delete(root);
322 cJSON_Delete(encaps);
323 APPSPAWN_LOGW("Add encaps object to root failed.(ignore)");
324 return APPSPAWN_ERROR_UTILS_ADD_JSON_FAIL;
325 }
326
327 *encapsInfoStr = cJSON_PrintUnformatted(root); // need to free
328 if (*encapsInfoStr == NULL) {
329 cJSON_Delete(root);
330 return APPSPAWN_ERROR_UTILS_DECODE_JSON_FAIL;
331 }
332
333 cJSON_Delete(root);
334 return 0;
335 }
336
SpawnSetEncapsPermissions(AppSpawnMgr * content,AppSpawningCtx * property)337 APPSPAWN_STATIC int SpawnSetEncapsPermissions(AppSpawnMgr *content, AppSpawningCtx *property)
338 {
339 if (content == NULL || property == NULL) {
340 return APPSPAWN_ARG_INVALID;
341 }
342
343 // The trustlist is used to control not appspawn or nativespawn
344 if (!(IsAppSpawnMode(content) || IsNativeSpawnMode(content))) {
345 return 0;
346 }
347
348 int encapsFileFd = OpenEncapsFile();
349 if (encapsFileFd <= 0) {
350 return 0; // Not support encaps ability
351 }
352
353 int ret = EnableEncapsForProc(encapsFileFd);
354 if (ret != 0) {
355 close(encapsFileFd);
356 return 0; // Can't enable encaps ability
357 }
358
359 char *encapsInfoStr = NULL;
360 ret = SpawnBuildEncaps(content, property, &encapsInfoStr);
361 if (ret != 0) {
362 close(encapsFileFd);
363 APPSPAWN_LOGW("Build encaps object failed, ret: %{public}d", ret);
364 return 0; // Can't set permission encpas ability
365 }
366
367 (void)WriteEncapsInfo(encapsFileFd, ENCAPS_PERMISSION_TYPE_MODE, encapsInfoStr, OH_ENCAPS_DEFAULT_FLAG);
368
369 if (encapsInfoStr != NULL) {
370 free(encapsInfoStr);
371 }
372 close(encapsFileFd);
373
374 return 0;
375 }
376
MODULE_CONSTRUCTOR(void)377 MODULE_CONSTRUCTOR(void)
378 {
379 AddAppSpawnHook(STAGE_CHILD_EXECUTE, HOOK_PRIO_COMMON, SpawnSetEncapsPermissions);
380 }