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 }