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