• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }