diff --git a/BUILD.gn b/BUILD.gn index cd008d37188383cf28bd0fa3450be4f36d1954cf..91ba73169e396b697822e4b6af57892271cf5ec0 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -178,7 +178,10 @@ ohos_executable("nwebspawn") { "${appspawn_path}/util/src/sandbox_utils.cpp", ] configs = [ ":appspawn_config" ] - deps = [ "${appspawn_path}:nwebspawn_server" ] + deps = [ + "${appspawn_path}:nwebspawn_server", + "${appspawn_path}:webviewchromium_loader", + ] if (build_selinux) { external_deps = [ "selinux:libhap_restorecon" ] @@ -205,3 +208,24 @@ group("nweb") { ] } } + +ohos_shared_library("webviewchromium_loader") { + sources = [ "${appspawn_path}/common/webview_loader.cpp" ] + configs = [ ":appspawn_config" ] + external_deps = [ "init:libbegetutil" ] + + subsystem_name = "${subsystem_name}" + part_name = "${part_name}" +} + +ohos_executable("nweb_shared_relro") { + sources = [ "${appspawn_path}/nweb_shared_relro/main.c" ] + if (target_cpu == "arm64") { + defines = [ "webview_arm64" ] + } + configs = [ ":appspawn_config" ] + deps = [ "${appspawn_path}:webviewchromium_loader" ] + install_enable = true + subsystem_name = "${subsystem_name}" + part_name = "${part_name}" +} diff --git a/adapter/appspawn_nweb.cpp b/adapter/appspawn_nweb.cpp index 5b6772f58b028195b5a84bc2f4f92aacd8a3c2de..f4d8054168a3eb170858c5992de6aac402c04fe7 100644 --- a/adapter/appspawn_nweb.cpp +++ b/adapter/appspawn_nweb.cpp @@ -19,9 +19,11 @@ #include #include #include +#include #include "appspawn_service.h" #include "appspawn_adapter.h" +#include "webview_loader.h" struct RenderProcessNode { RenderProcessNode(time_t now, int exit):recordTime_(now), exitStatus_(exit) {} time_t recordTime_; @@ -38,15 +40,19 @@ void LoadExtendLib(AppSpawnContent *content) { #ifdef webview_arm64 const std::string loadLibDir = "/data/app/el1/bundle/public/com.ohos.nweb/libs/arm64"; + const std::string nweb_relro_path = "/data/misc/shared_relro/libwebviewchromium64.relro"; #else const std::string loadLibDir = "/data/app/el1/bundle/public/com.ohos.nweb/libs/arm"; + const std::string nweb_relro_path = "/data/misc/shared_relro/libwebviewchromium32.relro"; #endif #ifdef __MUSL__ Dl_namespace dlns; dlns_init(&dlns, "nweb_ns"); dlns_create(&dlns, loadLibDir.c_str()); - void *handle = dlopen_ns(&dlns, "libweb_engine.so", RTLD_NOW | RTLD_GLOBAL); + void *handle = + LoadWithRelroFile("libweb_engine.so", nweb_relro_path.c_str(), + "nweb_ns", loadLibDir.c_str()); #else const std::string engineLibDir = loadLibDir + "/libweb_engine.so"; void *handle = dlopen(engineLibDir.c_str(), RTLD_NOW | RTLD_GLOBAL); diff --git a/appdata-sandbox.json b/appdata-sandbox.json index 213f33912086f090f3e20f8e66b97cae58a85ee5..30d68c74cee462b60b2231c9822e7c46dcdba76f 100755 --- a/appdata-sandbox.json +++ b/appdata-sandbox.json @@ -176,6 +176,11 @@ "sandbox-path" : "/data/storage/el1/bundle/ohos.global.systemres.overlay", "sandbox-flags" : [ "bind", "rec" ], "check-action-status": "false" + }, { + "src-path" : "/data/misc", + "sandbox-path" : "/data/storage/el1/bundle/misc", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "false" } ], "flags-point" : [{ diff --git a/appdata-sandbox64.json b/appdata-sandbox64.json index e0ab1a3851673b2c01b1fc13970af47a5124cfd4..322392028ff28ba581ce24035ec5ff2751cf5be8 100644 --- a/appdata-sandbox64.json +++ b/appdata-sandbox64.json @@ -190,6 +190,11 @@ "sandbox-path" : "/data/storage/el1/bundle/ohos.global.systemres.overlay", "sandbox-flags" : [ "bind", "rec" ], "check-action-status": "false" + }, { + "src-path" : "/data/misc", + "sandbox-path" : "/data/storage/el1/bundle/misc", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "false" } ], "flags-point" : [{ diff --git a/common/webview_loader.cpp b/common/webview_loader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8aba69b0af2504b5d71b0cb783e3ba0a44a9ec75 --- /dev/null +++ b/common/webview_loader.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "webview_loader.h" + +#include "beget_ext.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef WEBLOADER_LABEL +#define WEBLOADER_LABEL "WEBLOADER" +#endif +#define WEBLOADER_DOMAIN (BASE_DOMAIN + 0x11) +#define WEBLOADER_LOGI(fmt, ...) \ + STARTUP_LOGI(WEBLOADER_DOMAIN, WEBLOADER_LABEL, fmt, ##__VA_ARGS__) +#define WEBLOADER_LOGE(fmt, ...) \ + STARTUP_LOGE(WEBLOADER_DOMAIN, WEBLOADER_LABEL, fmt, ##__VA_ARGS__) +#define WEBLOADER_LOGV(fmt, ...) \ + STARTUP_LOGV(WEBLOADER_DOMAIN, WEBLOADER_LABEL, fmt, ##__VA_ARGS__) +#define WEBLOADER_LOGW(fmt, ...) \ + STARTUP_LOGW(WEBLOADER_DOMAIN, WEBLOADER_LABEL, fmt, ##__VA_ARGS__) + +void InitAddrAndSize() { + char *vAddr_env = getenv("RELRO_MMAP_LIBWEBENGINE_ADDR"); + unsigned long int nwebAddr = strtoul(vAddr_env, NULL, 10); + gReservedAddress = (void *)nwebAddr; + char *vAddrSize = getenv("RELRO_MMAP_LIBWEBENGINE_SIZE"); + gReservedSize = strtoul(vAddrSize, NULL, 10); + WEBLOADER_LOGE("InitAddrAndSize gReservedAddress=%p size=%d", + gReservedAddress, gReservedSize); +} + +bool CreateRelroFile(const char *lib, const char *relro, const char *ns_name, + const char *ns_path) { + InitAddrAndSize(); + if (unlink(relro) != 0 && errno != ENOENT) { + WEBLOADER_LOGI("CreateRelroFile unlink failed"); + } + + static const char tmpsuffix[] = ".XXXXXX"; + char relro_tmp[strlen(relro) + sizeof(tmpsuffix)]; + strlcpy(relro_tmp, relro, sizeof(relro_tmp)); + strlcat(relro_tmp, tmpsuffix, sizeof(relro_tmp)); + WEBLOADER_LOGI("CreateRelroFile tmp:[%s]", relro_tmp); + + bool mk_file_ok = false; + int try_time = 0; + int tmp_fd = -1; + while (!mk_file_ok && try_time < 15) { + try_time++; + tmp_fd = TEMP_FAILURE_RETRY(mkstemp(relro_tmp)); + if (tmp_fd == -1) { + WEBLOADER_LOGE("CreateRelroFile mk file failed, try_time=[%d]", try_time); + usleep(500 * 1000); + } else { + WEBLOADER_LOGI("CreateRelroFile mk file ok, try_time=[%d]", try_time); + mk_file_ok = true; + } + } + + if (tmp_fd == -1) { + int tmp_no = errno; + WEBLOADER_LOGE("CreateRelroFile failed, error=[%s]", strerror(tmp_no)); + return false; + } + + Dl_namespace dlns; + dlns_init(&dlns, ns_name); + dlns_create(&dlns, ns_path); + + dl_extinfo extinfo = { + .flag = DL_EXT_WRITE_RELRO | DL_EXT_RESERVED_ADDRESS_RECURSIVE | + DL_EXT_RESERVED_ADDRESS, + .relro_fd = tmp_fd, + .reserved_addr = gReservedAddress, + .reserved_size = gReservedSize, + }; + + bool open_ok = false; + try_time = 0; + void *handle = NULL; + while (!open_ok && try_time < 15) { + try_time++; + handle = dlopen_ns_ext(&dlns, lib, RTLD_NOW, &extinfo); + if (handle == NULL) { + WEBLOADER_LOGE("CreateRelroFile dlopen_ns_ext failed, try_time=[%d]", + try_time); + usleep(500 * 1000); + } else { + WEBLOADER_LOGI("CreateRelroFile dlopen_ns_ext ok, try_time=[%d]", + try_time); + open_ok = true; + } + } + + int close_result = close(tmp_fd); + if (handle == NULL) { + unlink(relro_tmp); + int tmp_no = errno; + WEBLOADER_LOGE("CreateRelroFile failed, error=[%s]", strerror(tmp_no)); + return false; + } + + if (close_result != 0 || chmod(relro_tmp, S_IRUSR | S_IRGRP | S_IROTH) != 0 || + rename(relro_tmp, relro) != 0) { + unlink(relro_tmp); + int tmp_no = errno; + WEBLOADER_LOGE("CreateRelroFile failed, error=[%s]", strerror(tmp_no)); + return false; + } + + return true; +} + +void *LoadWithRelroFile(const char *lib, const char *relro, const char *ns_name, + const char *ns_path) { + InitAddrAndSize(); + Dl_namespace dlns; + dlns_init(&dlns, ns_name); + dlns_create(&dlns, ns_path); + int relro_fd = TEMP_FAILURE_RETRY(open(relro, O_RDONLY)); + if (relro_fd == -1) { + int tmp_no = errno; + WEBLOADER_LOGE("LoadWithRelroFile failed, use dlopen_ns, error=[%s]", + strerror(tmp_no)); + return dlopen_ns(&dlns, lib, RTLD_NOW | RTLD_GLOBAL); + } + + dl_extinfo extinfo = { + .flag = DL_EXT_USE_RELRO | DL_EXT_RESERVED_ADDRESS_RECURSIVE | + DL_EXT_RESERVED_ADDRESS, + .relro_fd = relro_fd, + .reserved_addr = gReservedAddress, + .reserved_size = gReservedSize, + }; + void *handle = dlopen_ns_ext(&dlns, lib, RTLD_NOW, &extinfo); + close(relro_fd); + if (handle == NULL) { + int tmp_no = errno; + WEBLOADER_LOGE("LoadWithRelroFile failed, use dlopen_ns, error=[%s]", + strerror(tmp_no)); + return dlopen_ns(&dlns, lib, RTLD_NOW | RTLD_GLOBAL); + } + + return handle; +} diff --git a/common/webview_loader.h b/common/webview_loader.h new file mode 100644 index 0000000000000000000000000000000000000000..f136bac78c86f78f7373ce4ac504644d98b5cad2 --- /dev/null +++ b/common/webview_loader.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stdbool.h" +#include "stdio.h" + +#ifndef WEBVIEW_LOADER +#define WEBVIEW_LOADER +#ifdef __cplusplus +extern "C" { +#endif + +void *gReservedAddress; +size_t gReservedSize; + +bool CreateRelroFile(const char *lib, const char *relro, const char *ns_name, + const char *ns_path); + +void *LoadWithRelroFile(const char *lib, const char *relro, const char *ns_name, + const char *ns_path); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/nweb_shared_relro.cfg b/nweb_shared_relro.cfg new file mode 100644 index 0000000000000000000000000000000000000000..b57a40a959f15a1f54f8e4daa7b76a98930b6c78 --- /dev/null +++ b/nweb_shared_relro.cfg @@ -0,0 +1,17 @@ +{ + "services" : [{ + "name" : "nweb_shared_relro", + "path" : ["/system/bin/nweb_shared_relro", + "--process-name com.ohos.appspawn.nweb_shared_relro --start-flags daemon --type standard ", + "--sandbox-switch on --bundle-name com.ohos.appspawn.nweb_shared_relro --app-operate-type operate ", + "--render-command command --app-launch-type singleton --app-visible true"], + "importance" : -20, + "uid" : "root", + "gid" : ["root"], + "sandbox" : 0, + "start-mode" : "boot", + "secon" : "u:r:nweb_shared_relro:s0", + "once" : 1 + } + ] +} \ No newline at end of file diff --git a/nweb_shared_relro/main.c b/nweb_shared_relro/main.c new file mode 100644 index 0000000000000000000000000000000000000000..721a67185953f8a9488b1c40d061fb7c7f47bacd --- /dev/null +++ b/nweb_shared_relro/main.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "webview_loader.h" + +int main(int argc, char *const argv[]) { +#ifdef webview_arm64 + CreateRelroFile( + "libweb_engine.so", "/data/misc/shared_relro/libwebviewchromium64.relro", + "nweb_ns", "/data/app/el1/bundle/public/com.ohos.nweb/libs/arm64"); +#else + CreateRelroFile( + "libweb_engine.so", "/data/misc/shared_relro/libwebviewchromium32.relro", + "nweb_ns", "/data/app/el1/bundle/public/com.ohos.nweb/libs/arm"); +#endif + return 0; +}