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 #include "appspawn_encaps.h"
29
30 #define APP_ENCAPS "encaps"
31 #define APP_OHOS_ENCAPS_COUNT_KEY "ohos.encaps.count"
32 #define APP_OHOS_ENCAPS_FORK_KEY "ohos.encaps.fork.count"
33 #define APP_OHOS_ENCAPS_PERMISSIONS_KEY "permissions"
34
35 #define MSG_EXT_NAME_MAX_DECIMAL 10
36 #define OH_APP_MAX_PIDS_NUM 512
37 #define OH_ENCAPS_PROC_TYPE_BASE 0x18
38 #define OH_ENCAPS_PERMISSION_TYPE_BASE 0x1E
39 #define OH_ENCAPS_MAGIC 'E'
40 #define OH_PROC_HAP 4
41 #define OH_ENCAPS_DEFAULT_FLAG 0
42 #define OH_ENCAPS_DEFAULT_STR ""
43 // permission value max len is 512
44 #define OH_ENCAPS_VALUE_MAX_LEN 512
45 // encapsCount max count is 64
46 #define OH_ENCAPS_MAX_COUNT 64
47
48 #define SET_ENCAPS_PROC_TYPE_CMD _IOW(OH_ENCAPS_MAGIC, OH_ENCAPS_PROC_TYPE_BASE, uint32_t)
49 #define SET_ENCAPS_PERMISSION_TYPE_CMD _IOW(OH_ENCAPS_MAGIC, OH_ENCAPS_PERMISSION_TYPE_BASE, UserEncaps)
50
OpenEncapsFile(void)51 APPSPAWN_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 void * encapsInfo,uint32_t flag)61 APPSPAWN_STATIC int WriteEncapsInfo(int fd, AppSpawnEncapsBaseType encapsType, const void *encapsInfo, uint32_t flag)
62 {
63 if (encapsInfo == NULL) {
64 return APPSPAWN_ARG_INVALID;
65 }
66
67 int ret = 0;
68 switch (encapsType) {
69 case ENCAPS_PROC_TYPE_MODE:
70 ret = ioctl(fd, SET_ENCAPS_PROC_TYPE_CMD, &flag);
71 break;
72 case ENCAPS_PERMISSION_TYPE_MODE:
73 ret = ioctl(fd, SET_ENCAPS_PERMISSION_TYPE_CMD, encapsInfo);
74 break;
75 default:
76 ret = APPSPAWN_ARG_INVALID;
77 break;
78 }
79 if (ret != 0) {
80 APPSPAWN_LOGE("Encaps the setup failed ret: %{public}d fd: %{public}d", ret, fd);
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(AppSpawningCtx * property)92 APPSPAWN_STATIC uint32_t SpawnGetMaxPids(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
GetJsonObjFromExtInfo(const AppSpawningCtx * property,const char * name)111 static inline cJSON *GetJsonObjFromExtInfo(const AppSpawningCtx *property, const char *name)
112 {
113 uint32_t size = 0;
114 char *extInfo = (char *)(GetAppSpawnMsgExtInfo(property->message, name, &size));
115 if (size == 0 || extInfo == NULL) {
116 return NULL;
117 }
118 APPSPAWN_LOGV("Get json name %{public}s value %{public}s", name, extInfo);
119 cJSON *extInfoJson = cJSON_Parse(extInfo); // need to free
120 APPSPAWN_CHECK(extInfoJson != NULL, return NULL, "Invalid ext info %{public}s for %{public}s", extInfo, name);
121 return extInfoJson;
122 }
123
AddPermissionStrToValue(const char * valueStr,UserEncap * encap)124 APPSPAWN_STATIC int AddPermissionStrToValue(const char *valueStr, UserEncap *encap)
125 {
126 APPSPAWN_CHECK(valueStr != NULL, return APPSPAWN_ARG_INVALID, "Invalid string value");
127 uint32_t valueLen = strlen(valueStr) + 1;
128 APPSPAWN_CHECK(valueLen > 1 && valueLen <= OH_ENCAPS_VALUE_MAX_LEN, return APPSPAWN_ARG_INVALID,
129 "String value len is invalied, len: %{public}u", valueLen);
130 char *value = (char *)calloc(1, valueLen);
131 APPSPAWN_CHECK(value != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to calloc value");
132
133 int ret = strcpy_s(value, valueLen, valueStr);
134 APPSPAWN_CHECK(ret == EOK, free(value);
135 return APPSPAWN_SYSTEM_ERROR, "Failed to copy string value");
136
137 encap->value.ptrValue = (void *)value;
138 encap->valueLen = valueLen;
139 encap->type = ENCAPS_CHAR_ARRAY;
140 return 0;
141 }
142
AddPermissionIntArrayToValue(cJSON * arrayItem,UserEncap * encap,uint32_t arraySize)143 APPSPAWN_STATIC int AddPermissionIntArrayToValue(cJSON *arrayItem, UserEncap *encap, uint32_t arraySize)
144 {
145 uint32_t valueLen = sizeof(int) * arraySize;
146 APPSPAWN_CHECK(valueLen <= OH_ENCAPS_VALUE_MAX_LEN, return APPSPAWN_ARG_INVALID,
147 "Int array len too long, len: %{public}u", valueLen);
148 int *value = (int *)calloc(1, valueLen);
149 APPSPAWN_CHECK(value != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to calloc int array value");
150
151 cJSON *arrayItemTemp = arrayItem;
152 for (size_t index = 0; index < arraySize; index++) {
153 if (arrayItemTemp == NULL || !cJSON_IsNumber(arrayItemTemp)) {
154 free(value);
155 APPSPAWN_LOGE("Invalid int array item type");
156 return APPSPAWN_ARG_INVALID;
157 }
158 value[index] = arrayItemTemp->valueint;
159 arrayItemTemp = arrayItemTemp->next;
160 }
161 encap->value.ptrValue = (void *)value;
162 encap->valueLen = valueLen;
163 encap->type = ENCAPS_INT_ARRAY;
164 return 0;
165 }
166
AddPermissionBoolArrayToValue(cJSON * arrayItem,UserEncap * encap,uint32_t arraySize)167 APPSPAWN_STATIC int AddPermissionBoolArrayToValue(cJSON *arrayItem, UserEncap *encap, uint32_t arraySize)
168 {
169 uint32_t valueLen = sizeof(bool) * arraySize;
170 APPSPAWN_CHECK(valueLen <= OH_ENCAPS_VALUE_MAX_LEN, return APPSPAWN_ARG_INVALID,
171 "Bool array len too long, len: %{public}u", valueLen);
172 bool *value = (bool *)calloc(1, valueLen);
173 APPSPAWN_CHECK(value != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to calloc bool array value");
174
175 cJSON *arrayItemTemp = arrayItem;
176 for (size_t index = 0; index < arraySize; index++) {
177 if (arrayItemTemp == NULL || !cJSON_IsBool(arrayItemTemp)) {
178 free(value);
179 APPSPAWN_LOGE("Invalid bool array item type");
180 return APPSPAWN_ARG_INVALID;
181 }
182 value[index] = cJSON_IsTrue(arrayItemTemp) ? true : false;
183 arrayItemTemp = arrayItemTemp->next;
184 }
185 encap->value.ptrValue = (void *)value;
186 encap->valueLen = valueLen;
187 encap->type = ENCAPS_BOOL_ARRAY;
188 return 0;
189 }
190
AddPermissionStrArrayToValue(cJSON * arrayItem,UserEncap * encap)191 APPSPAWN_STATIC int AddPermissionStrArrayToValue(cJSON *arrayItem, UserEncap *encap)
192 {
193 uint32_t valueLen = 0;
194 for (cJSON *arrayItemTemp = arrayItem; arrayItemTemp != NULL; arrayItemTemp = arrayItemTemp->next) {
195 if (!cJSON_IsString(arrayItemTemp) || arrayItemTemp->valuestring == NULL) {
196 APPSPAWN_LOGE("Invalid string array item type");
197 return APPSPAWN_ARG_INVALID;
198 }
199 uint32_t tempLen = strlen(arrayItemTemp->valuestring);
200 APPSPAWN_CHECK(tempLen > 0, return APPSPAWN_ARG_INVALID, "String array value is invalied");
201 valueLen += tempLen + 1;
202 }
203
204 APPSPAWN_CHECK(valueLen > 0 && valueLen <= OH_ENCAPS_VALUE_MAX_LEN, return APPSPAWN_ARG_INVALID,
205 "String array len is invalied, len: %{public}u", valueLen);
206 char *value = (char *)calloc(1, valueLen);
207 APPSPAWN_CHECK(value != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to calloc string array value");
208
209 char *valuePtr = value;
210 for (cJSON *arrayItemTemp = arrayItem; arrayItemTemp != NULL; arrayItemTemp = arrayItemTemp->next) {
211 int len = strlen(arrayItemTemp->valuestring) + 1;
212 int ret = strcpy_s(valuePtr, len, arrayItemTemp->valuestring);
213 APPSPAWN_CHECK(ret == EOK, free(value);
214 return APPSPAWN_SYSTEM_ERROR, "Failed to copy string value");
215 valuePtr += len;
216 }
217 encap->value.ptrValue = (void *)value;
218 encap->valueLen = valueLen;
219 encap->type = ENCAPS_CHAR_ARRAY;
220 return 0;
221 }
222
AddPermissionArrayToValue(cJSON * permissionItemArr,UserEncap * encap)223 APPSPAWN_STATIC int AddPermissionArrayToValue(cJSON *permissionItemArr, UserEncap *encap)
224 {
225 uint32_t arraySize = (uint32_t)cJSON_GetArraySize(permissionItemArr);
226 if (arraySize == 0) {
227 return APPSPAWN_ARG_INVALID;
228 }
229
230 // check first item type
231 cJSON *arrayItem = permissionItemArr->child;
232 if (cJSON_IsNumber(arrayItem)) {
233 if (AddPermissionIntArrayToValue(arrayItem, encap, arraySize) != 0) {
234 return APPSPAWN_ARG_INVALID;
235 }
236 } else if (cJSON_IsString(arrayItem)) {
237 if (AddPermissionStrArrayToValue(arrayItem, encap) != 0) {
238 return APPSPAWN_ARG_INVALID;
239 }
240 } else if (cJSON_IsBool(arrayItem)) {
241 if (AddPermissionBoolArrayToValue(arrayItem, encap, arraySize) != 0) {
242 return APPSPAWN_ARG_INVALID;
243 }
244 } else {
245 APPSPAWN_LOGW("Invalid array item type");
246 return APPSPAWN_ARG_INVALID;
247 }
248
249 return 0;
250 }
251
AddPermissionItemToEncapsInfo(UserEncap * encap,cJSON * permissionItem)252 APPSPAWN_STATIC int AddPermissionItemToEncapsInfo(UserEncap *encap, cJSON *permissionItem)
253 {
254 // copy json key
255 char *key = permissionItem->string;
256 if (key == NULL || strcpy_s(encap->key, OH_ENCAPS_KEY_MAX_LEN, key) != EOK) {
257 APPSPAWN_LOGE("Failed to copy json key");
258 return APPSPAWN_SYSTEM_ERROR;
259 }
260
261 if (cJSON_IsNumber(permissionItem)) {
262 encap->type = ENCAPS_INT;
263 encap->value.intValue = (uint64_t)permissionItem->valueint;
264 encap->valueLen = sizeof(permissionItem->valueint);
265 } else if (cJSON_IsBool(permissionItem)) {
266 encap->type = ENCAPS_BOOL;
267 bool value = cJSON_IsTrue(permissionItem) ? true : false;
268 encap->value.intValue = (uint64_t)value;
269 encap->valueLen = sizeof(value);
270 } else if (cJSON_IsString(permissionItem)) {
271 if (AddPermissionStrToValue(permissionItem->valuestring, encap) != 0) {
272 return APPSPAWN_ARG_INVALID;
273 }
274 } else if (cJSON_IsArray(permissionItem)) {
275 if (AddPermissionArrayToValue(permissionItem, encap) != 0) {
276 return APPSPAWN_ARG_INVALID;
277 }
278 } else {
279 APPSPAWN_LOGW("Invalid permission item type");
280 return APPSPAWN_ARG_INVALID;
281 }
282
283 return 0;
284 }
285
AddMembersToEncapsInfo(cJSON * extInfoJson,UserEncaps * encapsInfo)286 APPSPAWN_STATIC int AddMembersToEncapsInfo(cJSON *extInfoJson, UserEncaps *encapsInfo)
287 {
288 // Get ohos.encaps.count
289 cJSON *countJson = cJSON_GetObjectItem(extInfoJson, APP_OHOS_ENCAPS_COUNT_KEY);
290 APPSPAWN_CHECK(countJson != NULL && cJSON_IsNumber(countJson), return APPSPAWN_ARG_INVALID, "Invalid countJson");
291 int encapsCount = countJson->valueint;
292
293 // Check input count and permissions size
294 cJSON *permissionsJson = cJSON_GetObjectItemCaseSensitive(extInfoJson, APP_OHOS_ENCAPS_PERMISSIONS_KEY);
295 APPSPAWN_CHECK(permissionsJson != NULL && cJSON_IsArray(permissionsJson), return APPSPAWN_ARG_INVALID,
296 "Invalid permissionsJson");
297 int count = cJSON_GetArraySize(permissionsJson);
298 APPSPAWN_CHECK(count > 0 && count <= OH_ENCAPS_MAX_COUNT && encapsCount == count, return APPSPAWN_ARG_INVALID,
299 "Invalid args, encaps count: %{public}d, permission count: %{public}d", encapsCount, count);
300
301 encapsInfo->encap = (UserEncap *)calloc(count + 1, sizeof(UserEncap));
302 APPSPAWN_CHECK(encapsInfo->encap != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to calloc encap");
303
304 for (int i = 0; i < count; i++) {
305 cJSON *permission = cJSON_GetArrayItem(permissionsJson, i);
306 APPSPAWN_CHECK(permission != NULL, return APPSPAWN_ERROR_UTILS_DECODE_JSON_FAIL,
307 "Encaps get single permission failed")
308
309 cJSON *permissionItem = permission->child;
310 APPSPAWN_CHECK(permissionItem != NULL, return APPSPAWN_ERROR_UTILS_DECODE_JSON_FAIL,
311 "Encaps get permission item failed")
312
313 if (AddPermissionItemToEncapsInfo(&encapsInfo->encap[i], permissionItem) != 0) {
314 APPSPAWN_LOGE("Add permission to encap failed");
315 return APPSPAWN_ERROR_UTILS_ADD_JSON_FAIL;
316 }
317 encapsInfo->encapsCount++;
318 }
319
320 return 0;
321 }
322
FreeEncapsInfo(UserEncaps * encapsInfo)323 APPSPAWN_STATIC void FreeEncapsInfo(UserEncaps *encapsInfo)
324 {
325 APPSPAWN_CHECK_ONLY_EXPER(encapsInfo != NULL, return);
326
327 if (encapsInfo->encap != NULL) {
328 for (uint32_t i = 0; i < encapsInfo->encapsCount; i++) {
329 if (encapsInfo->encap[i].type > ENCAPS_AS_ARRAY) {
330 free(encapsInfo->encap[i].value.ptrValue);
331 encapsInfo->encap[i].value.ptrValue = NULL;
332 }
333 }
334 free(encapsInfo->encap);
335 encapsInfo->encap = NULL;
336 }
337 }
338
339 /* set ohos.encaps.fork.count to encaps */
SpawnSetMaxPids(AppSpawningCtx * property,UserEncaps * encapsInfo)340 static int SpawnSetMaxPids(AppSpawningCtx *property, UserEncaps *encapsInfo)
341 {
342 uint32_t maxPidCount = 0;
343 if (GetAppSpawnMsgType(property) != MSG_SPAWN_NATIVE_PROCESS) {
344 maxPidCount = SpawnGetMaxPids(property);
345 }
346
347 APPSPAWN_CHECK(maxPidCount > 0 && maxPidCount < OH_APP_MAX_PIDS_NUM, return 0,
348 "Don't need to set pid max count %{public}u. Use default pid max", maxPidCount);
349 APPSPAWN_CHECK(encapsInfo->encapsCount < OH_ENCAPS_MAX_COUNT,
350 return APPSPAWN_ARG_INVALID, "Encaps count is more than 64, cannot set permissions");
351
352 uint32_t count = encapsInfo->encapsCount;
353 int ret = strcpy_s(encapsInfo->encap[count].key, OH_ENCAPS_KEY_MAX_LEN, APP_OHOS_ENCAPS_FORK_KEY);
354 APPSPAWN_CHECK_ONLY_EXPER(ret == EOK, return APPSPAWN_SYSTEM_ERROR);
355
356 encapsInfo->encap[count].value.intValue = (uint64_t)maxPidCount;
357 encapsInfo->encap[count].valueLen = sizeof(maxPidCount);
358 encapsInfo->encap[count].type = ENCAPS_INT;
359 encapsInfo->encapsCount++;
360 return 0;
361 }
362
SpawnSetPermissions(AppSpawningCtx * property,UserEncaps * encapsInfo)363 APPSPAWN_STATIC int SpawnSetPermissions(AppSpawningCtx *property, UserEncaps *encapsInfo)
364 {
365 // Get Permissions obejct
366 cJSON *extInfoJson = GetJsonObjFromExtInfo(property, MSG_EXT_NAME_JIT_PERMISSIONS);
367 if (extInfoJson == NULL) {
368 APPSPAWN_LOGV("GetJsonObjFromExtInfo failed");
369 return APPSPAWN_ARG_INVALID;
370 }
371
372 int ret = AddMembersToEncapsInfo(extInfoJson, encapsInfo);
373 if (ret != 0) {
374 APPSPAWN_LOGW("Add member to encaps failed, ret: %{public}d", ret);
375 cJSON_Delete(extInfoJson);
376 return ret;
377 }
378
379 ret = SpawnSetMaxPids(property, encapsInfo);
380 APPSPAWN_CHECK(ret == 0, cJSON_Delete(extInfoJson);
381 return ret, "Set max pids count to encaps failed");
382
383 cJSON_Delete(extInfoJson);
384 return 0;
385 }
386
SpawnSetEncapsPermissions(AppSpawnMgr * content,AppSpawningCtx * property)387 APPSPAWN_STATIC int SpawnSetEncapsPermissions(AppSpawnMgr *content, AppSpawningCtx *property)
388 {
389 if (content == NULL || property == NULL) {
390 return APPSPAWN_ARG_INVALID;
391 }
392
393 // The trustlist is used to control not appspawn or nativespawn
394 if (!(IsAppSpawnMode(content) || IsHybridSpawnMode(content) || IsNativeSpawnMode(content))) {
395 return 0;
396 }
397
398 int encapsFileFd = OpenEncapsFile();
399 if (encapsFileFd <= 0) {
400 return 0; // Not support encaps ability
401 }
402
403 int ret = EnableEncapsForProc(encapsFileFd);
404 if (ret != 0) {
405 close(encapsFileFd);
406 return 0; // Can't enable encaps ability
407 }
408
409 UserEncaps encapsInfo = {0};
410 ret = SpawnSetPermissions(property, &encapsInfo);
411 if (ret != 0) {
412 close(encapsFileFd);
413 FreeEncapsInfo(&encapsInfo);
414 APPSPAWN_LOGV("Build encaps info failed, ret: %{public}d", ret);
415 return 0; // Can't set permission encpas ability
416 }
417
418 (void)WriteEncapsInfo(encapsFileFd, ENCAPS_PERMISSION_TYPE_MODE, &encapsInfo, OH_ENCAPS_DEFAULT_FLAG);
419 APPSPAWN_LOGV("Set encaps info finish");
420
421 FreeEncapsInfo(&encapsInfo);
422 close(encapsFileFd);
423
424 return 0;
425 }
426
MODULE_CONSTRUCTOR(void)427 MODULE_CONSTRUCTOR(void)
428 {
429 AddAppSpawnHook(STAGE_CHILD_EXECUTE, HOOK_PRIO_COMMON, SpawnSetEncapsPermissions);
430 }