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 "dynamic_loader.h"
17 
18 #include "cj_hilog.h"
19 #include <dlfcn.h>
20 #include <cstdio>
21 #include <securec.h>
22 #include <unordered_set>
23 #include <string>
24 
25 namespace {
26 constexpr auto ERROR_BUF_SIZE = 255;
27 static char g_dlError[ERROR_BUF_SIZE];
28 static std::unordered_set<std::string> HasInited;
29 static char* g_sharedLibsSonames = nullptr;
30 
31 enum ErrorCode {
32     OUT_OF_MEMORY = 12,
33     FILE_EXISTS = 17,
34     INVALID_ARGUMENT = 22,
35 };
36 
ReadDlError()37 static void ReadDlError()
38 {
39     char* errMsg = dlerror();
40     if (!errMsg) {
41         return;
42     }
43     auto ends = sprintf_s(g_dlError, sizeof(g_dlError), "%s", errMsg);
44     if (ends >= ERROR_BUF_SIZE) {
45         g_dlError[ERROR_BUF_SIZE - 1] = '\0';
46     } else {
47         g_dlError[ends] = '\0';
48     }
49 }
50 
InitSharedLibsSonames()51 static void InitSharedLibsSonames()
52 {
53     if (g_sharedLibsSonames != nullptr) {
54         return;
55     }
56     const char* allowList[] = {
57         "libc.so",
58         "libdl.so",
59         "libm.so",
60         "libz.so",
61         "libclang_rt.asan.so",
62         "libclang_rt.tsan.so",
63         // z library
64         "libace_napi.z.so",
65         "libace_ndk.z.so",
66         "libbundle_ndk.z.so",
67         "libdeviceinfo_ndk.z.so",
68         "libEGL.so",
69         "libGLESv3.so",
70         "libhiappevent_ndk.z.so",
71         "libhuks_ndk.z.so",
72         "libhukssdk.z.so",
73         "libnative_drawing.so",
74         "libnative_window.so",
75         "libnative_buffer.so",
76         "libnative_vsync.so",
77         "libOpenSLES.so",
78         "libpixelmap_ndk.z.so",
79         "libimage_ndk.z.so",
80         "libimage_receiver_ndk.z.so",
81         "libimage_source_ndk.z.so",
82         "librawfile.z.so",
83         "libuv.so",
84         "libhilog.so",
85         "libnative_image.so",
86         "libnative_media_adec.so",
87         "libnative_media_aenc.so",
88         "libnative_media_codecbase.so",
89         "libnative_media_core.so",
90         "libnative_media_vdec.so",
91         "libnative_media_venc.so",
92         "libnative_media_avmuxer.so",
93         "libnative_media_avdemuxer.so",
94         "libnative_media_avsource.so",
95         "libnative_avscreen_capture.so",
96         "libavplayer.so",
97         // adaptor library
98         "libohosadaptor.so",
99         "libusb_ndk.z.so",
100         "libvulkan.so",
101     };
102 
103     size_t allowListLength = sizeof(allowList) / sizeof(char*);
104     int32_t sharedLibsSonamesLength = 1;
105     for (size_t i = 0; i < allowListLength; i++) {
106         sharedLibsSonamesLength += strlen(allowList[i]) + 1;
107     }
108     g_sharedLibsSonames = new char[sharedLibsSonamesLength];
109     int32_t cursor = 0;
110     for (size_t i = 0; i < allowListLength; i++) {
111         if (sprintf_s(g_sharedLibsSonames + cursor, sharedLibsSonamesLength - cursor, "%s:", allowList[i]) == -1) {
112             delete[] g_sharedLibsSonames;
113             g_sharedLibsSonames = nullptr;
114             return;
115         }
116         cursor += strlen(allowList[i]) + 1;
117     }
118     g_sharedLibsSonames[cursor] = '\0';
119 }
120 }
121 
122 extern "C" {
DynamicInitNamespace(Dl_namespace * ns,void * parent,const char * entries,const char * name)123 void DynamicInitNamespace(Dl_namespace* ns, void* parent, const char* entries, const char* name)
124 {
125     if (!ns || !entries || !name) {
126         LOGE("Invaild args for init namespace.");
127         return;
128     }
129     if (HasInited.count(std::string(name))) {
130         return;
131     }
132     dlns_init(ns, name);
133     auto status = dlns_create2(ns, entries, 0);
134     std::string errMsg;
135     if (status != 0) {
136         switch (status) {
137             case FILE_EXISTS:
138                 errMsg = "dlns_create failed: File exists";
139                 break;
140             case INVALID_ARGUMENT:
141                 errMsg = "dlns_create failed: Invalid argument";
142                 break;
143             case OUT_OF_MEMORY:
144                 errMsg = "dlns_create failed: Out of memory";
145                 break;
146             default:
147                 errMsg = "dlns_create failed, status: " + std::to_string(status);
148         }
149         if (sprintf_s(g_dlError, sizeof(g_dlError), errMsg.c_str()) == -1) {
150             LOGE("Fail to generate error msg.");
151             return;
152         }
153         return;
154     }
155     if (parent) {
156         dlns_inherit((Dl_namespace*)parent, ns, "allow_all_shared_libs");
157     }
158     Dl_namespace current;
159     dlns_get(nullptr, &current);
160     if (strcmp(name, "cj_app") != 0) {
161         dlns_inherit(ns, &current, "allow_all_shared_libs");
162     } else {
163         InitSharedLibsSonames();
164         dlns_inherit(ns, &current, g_sharedLibsSonames);
165         if (g_sharedLibsSonames != nullptr) {
166             delete[] g_sharedLibsSonames;
167             g_sharedLibsSonames = nullptr;
168         }
169     }
170     Dl_namespace chip_sdk;
171     dlns_get("cj_chipsdk", &chip_sdk);
172     dlns_inherit(ns, &chip_sdk, "allow_all_shared_libs");
173     HasInited.insert(std::string(name));
174 }
175 
DynamicLoadLibrary(Dl_namespace * ns,const char * dlPath,unsigned int mode)176 void* DynamicLoadLibrary(Dl_namespace *ns, const char* dlPath, unsigned int mode)
177 {
178     if (ns == nullptr) {
179         dlns_get("cj_app", ns);
180     }
181 
182     auto result = dlopen_ns(ns, dlPath, mode | RTLD_GLOBAL | RTLD_NOW);
183     if (!result) {
184         ReadDlError();
185     }
186     return result;
187 }
188 
DynamicFindSymbol(void * so,const char * symbol)189 void* DynamicFindSymbol(void* so, const char* symbol)
190 {
191     return dlsym(so, symbol);
192 }
193 
DynamicFreeLibrary(void * so)194 void DynamicFreeLibrary(void* so)
195 {
196     (void)dlclose(so);
197 }
198 
DynamicGetError()199 const char* DynamicGetError()
200 {
201     return g_dlError;
202 }
203 }
204