• 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 
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 }