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