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 "appspawn_adapter.h"
17 
18 #include "access_token.h"
19 #include "appspawn_hook.h"
20 #include "appspawn_manager.h"
21 #include "appspawn_utils.h"
22 #include "cJSON.h"
23 #include "token_setproc.h"
24 #include "tokenid_kit.h"
25 #include "securec.h"
26 
27 #ifdef WITH_SELINUX
28 #include "hap_restorecon.h"
29 #include "selinux/selinux.h"
30 #endif
31 #ifdef WITH_SECCOMP
32 #include "seccomp_policy.h"
33 #include <sys/prctl.h>
34 #endif
35 #define MSG_EXT_NAME_PROCESS_TYPE "ProcessType"
36 #define NWEBSPAWN_SERVER_NAME "nwebspawn"
37 #define MAX_USERID_LEN  32
38 using namespace OHOS::Security::AccessToken;
39 
SetAppAccessToken(const AppSpawnMgr * content,const AppSpawningCtx * property)40 int SetAppAccessToken(const AppSpawnMgr *content, const AppSpawningCtx *property)
41 {
42     int32_t ret = 0;
43     uint64_t tokenId = 0;
44     AppSpawnMsgAccessToken *tokenInfo =
45         reinterpret_cast<AppSpawnMsgAccessToken *>(GetAppProperty(property, TLV_ACCESS_TOKEN_INFO));
46     APPSPAWN_CHECK(tokenInfo != NULL, return APPSPAWN_MSG_INVALID,
47         "No access token in msg %{public}s", GetProcessName(property));
48 
49     if (IsNWebSpawnMode(content) || IsIsolatedNativeSpawnMode(content, property)) {
50         TokenIdKit tokenIdKit;
51         tokenId = tokenIdKit.GetRenderTokenID(tokenInfo->accessTokenIdEx);
52     } else {
53         tokenId = tokenInfo->accessTokenIdEx;
54     }
55     ret = SetSelfTokenID(tokenId);
56     APPSPAWN_CHECK(ret == 0, return APPSPAWN_ACCESS_TOKEN_INVALID,
57         "set access token id failed, ret: %{public}d %{public}s", ret, GetProcessName(property));
58     APPSPAWN_LOGV("SetAppAccessToken success for %{public}s", GetProcessName(property));
59     return 0;
60 }
61 
SetSelinuxConNweb(const AppSpawnMgr * content,const AppSpawningCtx * property)62 int SetSelinuxConNweb(const AppSpawnMgr *content, const AppSpawningCtx *property)
63 {
64 #if defined(WITH_SELINUX) && !defined(APPSPAWN_TEST)
65     uint32_t len = 0;
66     std::string processType =
67         reinterpret_cast<char *>(GetAppPropertyExt(property, MSG_EXT_NAME_PROCESS_TYPE, &len));
68     int32_t ret;
69     if (processType == "render") {
70         ret = setcon("u:r:isolated_render:s0");
71     } else {
72         ret = setcon("u:r:isolated_gpu:s0");
73     }
74     APPSPAWN_CHECK_ONLY_LOG(ret == 0, "Setcon failed, errno: %{public}d", errno);
75 #endif
76     return 0;
77 }
78 
SetSelinuxCon(const AppSpawnMgr * content,const AppSpawningCtx * property)79 int SetSelinuxCon(const AppSpawnMgr *content, const AppSpawningCtx *property)
80 {
81 #ifdef WITH_SELINUX
82     APPSPAWN_LOGV("SetSelinuxCon IsDeveloperModeOn %{public}d", IsDeveloperModeOn(property));
83     if (GetAppSpawnMsgType(property) == MSG_SPAWN_NATIVE_PROCESS) {
84         if (!IsDeveloperModeOn(property)) {
85             APPSPAWN_LOGE("Denied Launching a native process: not in developer mode");
86             return APPSPAWN_NATIVE_NOT_SUPPORT;
87         }
88         return 0;
89     }
90     if (IsNWebSpawnMode(content)) {
91 #ifndef APPSPAWN_TEST
92         return SetSelinuxConNweb(content, property);
93 #else
94         return 0;
95 #endif
96     } else if (IsIsolatedNativeSpawnMode(content, property)) {
97         return setcon("u:r:isolated_render:s0");
98     }
99     AppSpawnMsgDomainInfo *msgDomainInfo =
100         reinterpret_cast<AppSpawnMsgDomainInfo *>(GetAppProperty(property, TLV_DOMAIN_INFO));
101     APPSPAWN_CHECK(msgDomainInfo != NULL, return APPSPAWN_TLV_NONE,
102         "No domain info in req form %{public}s", GetProcessName(property));
103     HapContext hapContext;
104     HapDomainInfo hapDomainInfo;
105     hapDomainInfo.apl = msgDomainInfo->apl;
106     hapDomainInfo.packageName = GetBundleName(property);
107     hapDomainInfo.hapFlags = msgDomainInfo->hapFlags;
108     if (CheckAppMsgFlagsSet(property, APP_FLAGS_DEBUGGABLE)) {
109         hapDomainInfo.hapFlags |= SELINUX_HAP_DEBUGGABLE;
110     }
111     if (CheckAppMsgFlagsSet(property, APP_FLAGS_DLP_MANAGER)) {
112         hapDomainInfo.hapFlags |= SELINUX_HAP_DLP;
113     }
114     if (CheckAppMsgFlagsSet(property, APP_FLAGS_ISOLATED_SANDBOX)) {
115         hapDomainInfo.hapFlags |= 0x08;
116     }
117     int32_t ret = hapContext.HapDomainSetcontext(hapDomainInfo);
118     if (CheckAppMsgFlagsSet(property, APP_FLAGS_ASANENABLED)) {
119         ret = 0;
120     }
121     APPSPAWN_CHECK(ret == 0, return APPSPAWN_ACCESS_TOKEN_INVALID,
122         "Set domain context failed, ret: %{public}d %{public}s", ret, GetProcessName(property));
123     APPSPAWN_LOGV("SetSelinuxCon success for %{public}s", GetProcessName(property));
124 #endif
125     return 0;
126 }
127 
SetUidGidFilter(const AppSpawnMgr * content)128 int SetUidGidFilter(const AppSpawnMgr *content)
129 {
130 #ifdef WITH_SECCOMP
131     bool ret = false;
132     if (IsNWebSpawnMode(content)) {
133         if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
134             APPSPAWN_LOGE("Failed to set no new privs");
135         }
136         ret = SetSeccompPolicyWithName(INDIVIDUAL, NWEBSPAWN_NAME);
137     } else {
138         ret = SetSeccompPolicyWithName(INDIVIDUAL, APPSPAWN_NAME);
139     }
140     if (!ret) {
141         APPSPAWN_LOGE("Failed to set APPSPAWN seccomp filter and exit");
142         _exit(0x7f);
143     }
144     APPSPAWN_LOGV("SetUidGidFilter success");
145 #endif
146     return 0;
147 }
148 
SetSeccompFilter(const AppSpawnMgr * content,const AppSpawningCtx * property)149 int SetSeccompFilter(const AppSpawnMgr *content, const AppSpawningCtx *property)
150 {
151 #ifdef WITH_SECCOMP
152     APPSPAWN_CHECK(property != nullptr, return 0, "property is NULL");
153     const char *appName = APP_NAME;
154     SeccompFilterType type = APP;
155 
156     if (IsNWebSpawnMode(content)) {
157         uint32_t len = 0;
158         std::string processType =
159             reinterpret_cast<char *>(GetAppPropertyExt(property, MSG_EXT_NAME_PROCESS_TYPE, &len));
160         if (processType == "render") {
161             return 0;
162         }
163     }
164 
165     if (CheckAppSpawnMsgFlag(property->message, TLV_MSG_FLAGS, APP_FLAGS_ISOLATED_SANDBOX) != 0) {
166         appName = IMF_EXTENTOIN_NAME;
167     }
168 
169     if (!SetSeccompPolicyWithName(type, appName)) {
170         APPSPAWN_LOGE("Failed to set %{public}s seccomp filter and exit %{public}d", appName, errno);
171         return -EINVAL;
172     }
173     APPSPAWN_LOGV("SetSeccompFilter success for %{public}s", GetProcessName(property));
174 #endif
175     return 0;
176 }
177 
SetInternetPermission(const AppSpawningCtx * property)178 int SetInternetPermission(const AppSpawningCtx *property)
179 {
180     AppSpawnMsgInternetInfo *info =
181         reinterpret_cast<AppSpawnMsgInternetInfo *>(GetAppProperty(property, TLV_INTERNET_INFO));
182     APPSPAWN_CHECK(info != NULL, return 0,
183         "No tlv internet permission info in req form %{public}s", GetProcessName(property));
184     APPSPAWN_LOGV("Set internet permission %{public}d %{public}d", info->setAllowInternet, info->allowInternet);
185     if (info->setAllowInternet == 1 && info->allowInternet == 0) {
186         DisallowInternet();
187     }
188     return 0;
189 }
190 
InitAppCommonEnv(const AppSpawningCtx * property)191 APPSPAWN_STATIC void InitAppCommonEnv(const AppSpawningCtx *property)
192 {
193     AppDacInfo *appInfo = reinterpret_cast<AppDacInfo *>(GetAppProperty(property, TLV_DAC_INFO));
194     if (appInfo == NULL) {
195         return;
196     }
197     const uint32_t userId = appInfo->uid / UID_BASE;
198     char user[MAX_USERID_LEN] = {0};
199     int len = sprintf_s(user, MAX_USERID_LEN, "%u", userId);
200     APPSPAWN_CHECK(len > 0, return, "Failed to format userid: %{public}u", userId);
201     int ret = setenv("USER", user, 1);
202     APPSPAWN_CHECK(ret == 0, return, "setenv failed, userid:%{public}u, errno: %{public}d", userId, errno);
203 }
204 
SetEnvInfo(const AppSpawnMgr * content,const AppSpawningCtx * property)205 int32_t SetEnvInfo(const AppSpawnMgr *content, const AppSpawningCtx *property)
206 {
207     InitAppCommonEnv(property);
208 
209     uint32_t size = 0;
210     char *envStr = reinterpret_cast<char *>(GetAppPropertyExt(property, "AppEnv", &size));
211     if (size == 0 || envStr == NULL) {
212         return 0;
213     }
214     int ret = 0;
215     cJSON *root = cJSON_Parse(envStr);
216     APPSPAWN_CHECK(root != nullptr, return -1, "SetEnvInfo: json parse failed %{public}s", envStr);
217     cJSON *config = nullptr;
218     cJSON_ArrayForEach(config, root) {
219         const char *name = config->string;
220         const char *value = cJSON_GetStringValue(config);
221         APPSPAWN_LOGV("SetEnvInfo name: %{public}s value: %{public}s", name, value);
222         ret = setenv(name, value, 1);
223         APPSPAWN_CHECK(ret == 0, break, "setenv failed, errno: %{public}d", errno);
224     }
225     cJSON_Delete(root);
226     APPSPAWN_LOGV("SetEnvInfo success");
227     return ret;
228 }
229