• 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 
AddJITPermissionToEncaps(cJSON * extInfoJson,cJSON * encaps,uint32_t * permissionCount)144 static int AddJITPermissionToEncaps(cJSON *extInfoJson, cJSON *encaps, uint32_t *permissionCount)
145 {
146     // Get ohos.encaps.count
147     cJSON *countJson = cJSON_GetObjectItem(extInfoJson, "ohos.encaps.count");
148     int encapsCount = 0;
149     if (cJSON_IsNumber(countJson)) {
150         encapsCount = countJson->valueint;
151     }
152 
153     // Check input count and permissions size
154     cJSON *permissions = cJSON_GetObjectItemCaseSensitive(extInfoJson, "permissions");
155     int count = cJSON_GetArraySize(permissions);
156     if (encapsCount != count) {
157         APPSPAWN_LOGE("Invalid args, encaps count: %{public}d, permission count: %{public}d", encapsCount, count);
158         return APPSPAWN_ARG_INVALID;
159     }
160 
161     // If permissionName is obtained, it needs to be written in the format of ["permissionName: 1"] in the encaps
162     for (int i = 0; i < count; i++) {
163         char *permissionName = cJSON_GetStringValue(cJSON_GetArrayItem(permissions, i));
164         if (cJSON_AddNumberToObject(encaps, permissionName, 1) == NULL) {
165             APPSPAWN_LOGV("Add permission to object failed.(ignore)");
166             return APPSPAWN_ERROR_UTILS_ADD_JSON_FAIL;
167         }
168     }
169     *permissionCount += count;
170 
171     return 0;
172 }
173 
SpawnSetJITPermissions(AppSpawnMgr * content,AppSpawningCtx * property,cJSON * encaps,uint32_t * count)174 static int SpawnSetJITPermissions(AppSpawnMgr *content, AppSpawningCtx *property, cJSON *encaps, uint32_t *count)
175 {
176     cJSON *extInfoJson = GetJsonObjFromExtInfo(property, MSG_EXT_NAME_JIT_PERMISSIONS);
177     if (extInfoJson == NULL) {
178         return APPSPAWN_ARG_INVALID;
179     }
180 
181     int ret = AddJITPermissionToEncaps(extInfoJson, encaps, count);
182     if (ret != 0) {
183         APPSPAWN_LOGW("Add permission to object failed.(ignore), ret: %{public}d", ret);
184     }
185 
186     cJSON_Delete(extInfoJson);
187     return ret;
188 }
189 
AddMembersToEncaps(AppSpawnMgr * content,AppSpawningCtx * property,cJSON * encaps)190 static int AddMembersToEncaps(AppSpawnMgr *content, AppSpawningCtx *property, cJSON *encaps)
191 {
192     uint32_t encapsPermissionCount = 0;
193     // need set ohos.encaps.count to encaps firstly
194     if (cJSON_AddNumberToObject(encaps, APP_OHOS_ENCAPS_COUNT_KEY, encapsPermissionCount) == NULL) {
195         APPSPAWN_LOGV("Set ohos.encaps.count to object failed.(ignore)");
196         return APPSPAWN_ERROR_UTILS_ADD_JSON_FAIL;
197     }
198 
199     int ret = SpawnSetMaxPids(content, property, encaps);
200     if (ret != 0) {
201         APPSPAWN_LOGV("Can't set max pids to encaps object.(ignore), ret: %{public}d", ret);
202     } else {
203         encapsPermissionCount += 1;
204     }
205 
206     uint32_t count = 0;
207     ret = SpawnSetJITPermissions(content, property, encaps, &count);
208     if (ret != 0) {
209         APPSPAWN_LOGV("Can't set JIT permission to encaps object.(ignore), ret: %{public}d", ret);
210     } else {
211         encapsPermissionCount += count;
212     }
213 
214     if (encapsPermissionCount == 0) {
215         return APPSPAWN_ERROR_UTILS_ADD_JSON_FAIL; // Don't need set permission
216     }
217 
218     cJSON *encapsCountItem = cJSON_GetObjectItem(encaps, APP_OHOS_ENCAPS_COUNT_KEY);
219     if (encapsCountItem != NULL) {
220         cJSON_SetNumberValue(encapsCountItem, encapsPermissionCount);
221     }
222 
223     return 0;
224 }
225 
SpawnBuildEncaps(AppSpawnMgr * content,AppSpawningCtx * property,char ** encapsInfoStr)226 static int SpawnBuildEncaps(AppSpawnMgr *content, AppSpawningCtx *property, char **encapsInfoStr)
227 {
228     // Create root object
229     cJSON *root = cJSON_CreateObject();
230     if (root == NULL) {
231         return APPSPAWN_ERROR_UTILS_CREATE_JSON_FAIL;
232     }
233 
234     // Create encaps object
235     cJSON *encaps = cJSON_CreateObject();
236     if (encaps == NULL) {
237         cJSON_Delete(root);
238         return APPSPAWN_ERROR_UTILS_CREATE_JSON_FAIL;
239     }
240 
241     int ret = AddMembersToEncaps(content, property, encaps);
242     if (ret != 0) {
243         APPSPAWN_LOGW("Add members to encaps object failed.(ignore), ret: %{public}d", ret);
244         cJSON_Delete(root);
245         cJSON_Delete(encaps);
246         return ret;
247     }
248 
249     if (cJSON_AddItemToObject(root, APP_ENCAPS, encaps) != true) {   // add encaps object to root
250         cJSON_Delete(root);
251         cJSON_Delete(encaps);
252         APPSPAWN_LOGW("Add encaps object to root failed.(ignore)");
253         return APPSPAWN_ERROR_UTILS_ADD_JSON_FAIL;
254     }
255 
256     *encapsInfoStr = cJSON_PrintUnformatted(root);       // need to  free
257     if (*encapsInfoStr == NULL) {
258         cJSON_Delete(root);
259         return APPSPAWN_ERROR_UTILS_DECODE_JSON_FAIL;
260     }
261 
262     cJSON_Delete(root);
263     return 0;
264 }
265 
SpawnSetEncapsPermissions(AppSpawnMgr * content,AppSpawningCtx * property)266 APPSPAWN_STATIC int SpawnSetEncapsPermissions(AppSpawnMgr *content, AppSpawningCtx *property)
267 {
268     if (content == NULL || property == NULL) {
269         return APPSPAWN_ARG_INVALID;
270     }
271 
272     // The trustlist is used to control not appspawn
273     if (!IsAppSpawnMode(content)) {
274         return 0;
275     }
276 
277     int encapsFileFd = OpenEncapsFile();
278     if (encapsFileFd <= 0) {
279         return 0;         // Not support encaps ability
280     }
281 
282     int ret = EnableEncapsForProc(encapsFileFd);
283     if (ret != 0) {
284         close(encapsFileFd);
285         return 0;         // Can't enable encaps ability
286     }
287 
288     char *encapsInfoStr = NULL;
289     ret = SpawnBuildEncaps(content, property, &encapsInfoStr);
290     if (ret != 0) {
291         close(encapsFileFd);
292         APPSPAWN_LOGW("Build encaps object failed, ret: %{public}d", ret);
293         return 0;        // Can't set permission encpas ability
294     }
295 
296     (void)WriteEncapsInfo(encapsFileFd, ENCAPS_PERMISSION_TYPE_MODE, encapsInfoStr, OH_ENCAPS_DEFAULT_FLAG);
297 
298     if (encapsInfoStr != NULL) {
299         free(encapsInfoStr);
300     }
301     close(encapsFileFd);
302 
303     return 0;
304 }
305 
MODULE_CONSTRUCTOR(void)306 MODULE_CONSTRUCTOR(void)
307 {
308     AddAppSpawnHook(STAGE_CHILD_EXECUTE, HOOK_PRIO_COMMON, SpawnSetEncapsPermissions);
309 }