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 <algorithm>
17 #include <cerrno>
18 #include <ctime>
19 #include <dlfcn.h>
20 #include <map>
21 #include <mutex>
22 #include <string>
23 
24 #ifdef __MUSL__
25 #include <cerrno>
26 #include <dlfcn_ext.h>
27 #include <sys/mman.h>
28 #endif
29 
30 #include "appspawn_hook.h"
31 #include "appspawn_manager.h"
32 #include "appspawn_utils.h"
33 
34 #ifdef WITH_SECCOMP
35 #include "seccomp_policy.h"
36 #endif
37 
38 #ifndef APPSPAWN_TEST
39 #define APPSPAWN_STATIC static
40 #else
41 #define APPSPAWN_STATIC
42 #endif
43 
44 namespace {
45 #if defined(webview_arm64)
46     const std::string ARK_WEB_CORE_HAP_LIB_PATH =
47         "/data/storage/el1/bundle/arkwebcore/libs/arm64";
48 #elif defined(webview_x86_64)
49     const std::string ARK_WEB_CORE_HAP_LIB_PATH =
50         "/data/storage/el1/bundle/arkwebcore/libs/x86_64";
51 #else
52     const std::string ARK_WEB_CORE_HAP_LIB_PATH =
53         "/data/storage/el1/bundle/arkwebcore/libs/arm";
54 #endif
55     const std::string ARK_WEB_ENGINE_LIB_NAME = "libarkweb_engine.so";
56     const std::string ARK_WEB_RENDER_LIB_NAME = "libarkweb_render.so";
57     const std::string WEB_ENGINE_LIB_NAME = "libweb_engine.so";
58     const std::string WEB_RENDER_LIB_NAME = "libnweb_render.so";
59 }  // namespace
60 
SetSeccompPolicyForRenderer(void *nwebRenderHandle)61 APPSPAWN_STATIC bool SetSeccompPolicyForRenderer(void *nwebRenderHandle)
62 {
63 #ifdef WITH_SECCOMP
64     if (IsEnableSeccomp()) {
65         using SeccompFuncType = bool (*)(void);
66         SeccompFuncType funcSetRendererSeccompPolicy =
67                 reinterpret_cast<SeccompFuncType>(dlsym(nwebRenderHandle, "SetRendererSeccompPolicy"));
68         if (funcSetRendererSeccompPolicy != nullptr && funcSetRendererSeccompPolicy()) {
69             return true;
70         }
71         APPSPAWN_LOGE("SetRendererSeccompPolicy dlsym errno: %{public}d", errno);
72         return false;
73     }
74 #endif
75     return true;
76 }
77 
GetArkWebEngineLibName()78 APPSPAWN_STATIC std::string GetArkWebEngineLibName()
79 {
80     std::string arkWebEngineLibPath = ARK_WEB_CORE_HAP_LIB_PATH + "/"
81             + ARK_WEB_ENGINE_LIB_NAME;
82     bool isArkWebEngineLibPathExist = access(arkWebEngineLibPath.c_str(), F_OK) == 0;
83     return isArkWebEngineLibPathExist ?
84             ARK_WEB_ENGINE_LIB_NAME : WEB_ENGINE_LIB_NAME;
85 }
86 
GetArkWebRenderLibName()87 APPSPAWN_STATIC std::string GetArkWebRenderLibName()
88 {
89     std::string arkWebRenderLibPath = ARK_WEB_CORE_HAP_LIB_PATH + "/"
90             + ARK_WEB_RENDER_LIB_NAME;
91     bool isArkWebRenderLibPathExist = access(arkWebRenderLibPath.c_str(), F_OK) == 0;
92     return isArkWebRenderLibPathExist ?
93             ARK_WEB_RENDER_LIB_NAME : WEB_RENDER_LIB_NAME;
94 }
95 
RunChildProcessor(AppSpawnContent *content, AppSpawnClient *client)96 APPSPAWN_STATIC int RunChildProcessor(AppSpawnContent *content, AppSpawnClient *client)
97 {
98     EnableCache();
99     uint32_t len = 0;
100     char *renderCmd = reinterpret_cast<char *>(GetAppPropertyExt(
101         reinterpret_cast<AppSpawningCtx *>(client), MSG_EXT_NAME_RENDER_CMD, &len));
102     APPSPAWN_CHECK_ONLY_EXPER(renderCmd != nullptr, return -1);
103     std::string renderStr(renderCmd);
104     void *webEngineHandle = nullptr;
105     void *nwebRenderHandle = nullptr;
106 
107     const std::string& libPath = ARK_WEB_CORE_HAP_LIB_PATH;
108     const std::string engineLibName = GetArkWebEngineLibName();
109     const std::string renderLibName = GetArkWebRenderLibName();
110 
111 #ifdef __MUSL__
112     Dl_namespace dlns;
113     dlns_init(&dlns, "nweb_ns");
114     dlns_create(&dlns, libPath.c_str());
115     // preload libweb_engine
116     webEngineHandle =
117         dlopen_ns(&dlns, engineLibName.c_str(), RTLD_NOW | RTLD_GLOBAL);
118     // load libnweb_render
119     nwebRenderHandle =
120         dlopen_ns(&dlns, renderLibName.c_str(), RTLD_NOW | RTLD_GLOBAL);
121 #else
122     // preload libweb_engine
123     const std::string engineLibPath = libPath + "/" + engineLibName;
124     webEngineHandle = dlopen(engineLibPath.c_str(), RTLD_NOW | RTLD_GLOBAL);
125 
126     // load libnweb_render
127     const std::string renderLibPath = libPath + "/" + renderLibName;
128     nwebRenderHandle = dlopen(renderLibPath.c_str(), RTLD_NOW | RTLD_GLOBAL);
129 #endif
130     if (webEngineHandle == nullptr) {
131         APPSPAWN_LOGE("Fail to dlopen libweb_engine.so, errno: %{public}d", errno);
132     }
133     if (nwebRenderHandle == nullptr) {
134         APPSPAWN_LOGE("Fail to dlopen libnweb_render.so, errno: %{public}d", errno);
135         return -1;
136     }
137 
138     std::string processType = reinterpret_cast<char *>(GetAppPropertyExt(
139         reinterpret_cast<AppSpawningCtx *>(client), MSG_EXT_NAME_PROCESS_TYPE, &len));
140     if (processType == "render" && !SetSeccompPolicyForRenderer(nwebRenderHandle)) {
141         return -1;
142     }
143     using FuncType = void (*)(const char *cmd);
144 
145     FuncType funcNWebRenderMain = reinterpret_cast<FuncType>(dlsym(nwebRenderHandle, "NWebRenderMain"));
146     if (funcNWebRenderMain == nullptr) {
147         APPSPAWN_LOGE("webviewspawn dlsym errno: %{public}d", errno);
148         return -1;
149     }
150     AppSpawnEnvClear(content, client);
151     APPSPAWN_LOGI("RunChildProcessorNweb %{public}s", renderStr.c_str());
152     funcNWebRenderMain(renderStr.c_str());
153     return 0;
154 }
155 
PreLoadNwebSpawn(AppSpawnMgr *content)156 static int PreLoadNwebSpawn(AppSpawnMgr *content)
157 {
158     APPSPAWN_LOGI("PreLoadNwebSpawn %{public}d", IsNWebSpawnMode(content));
159     if (!IsNWebSpawnMode(content)) {
160         return 0;
161     }
162     // register
163     RegChildLooper(&content->content, RunChildProcessor);
164     return 0;
165 }
166 
MODULE_CONSTRUCTOR(void)167 MODULE_CONSTRUCTOR(void)
168 {
169     APPSPAWN_LOGI("Load nweb module ...");
170     AddPreloadHook(HOOK_PRIO_HIGHEST, PreLoadNwebSpawn);
171 }
172