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
44namespace {
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
61APPSPAWN_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
78APPSPAWN_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
87APPSPAWN_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
96APPSPAWN_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
156static 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
167MODULE_CONSTRUCTOR(void)
168{
169    APPSPAWN_LOGI("Load nweb module ...");
170    AddPreloadHook(HOOK_PRIO_HIGHEST, PreLoadNwebSpawn);
171}
172