blob: c22ce8abf4c00752e20e8f8f787a4df50c553601 [file] [log] [blame]
Jiyong Park6291da22019-04-26 18:55:48 +09001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include "library_namespaces.h"
17
18#include <dirent.h>
19#include <dlfcn.h>
20
21#include <regex>
22#include <string>
23#include <vector>
24
Jiyong Park16a98962019-05-04 03:10:48 +090025#include <android-base/file.h>
26#include <android-base/logging.h>
27#include <android-base/macros.h>
28#include <android-base/properties.h>
29#include <android-base/strings.h>
30#include <nativehelper/ScopedUtfChars.h>
31
Jiyong Park6291da22019-04-26 18:55:48 +090032#include "nativeloader/dlext_namespaces.h"
Jiyong Park40a60772019-05-03 16:21:31 +090033#include "public_libraries.h"
Jiyong Parkf8802e52019-05-03 16:34:56 +090034#include "utils.h"
Jiyong Park6291da22019-04-26 18:55:48 +090035
Jiyong Park40a60772019-05-03 16:21:31 +090036namespace android::nativeloader {
Jiyong Park6291da22019-04-26 18:55:48 +090037
38namespace {
Jiyong Park6291da22019-04-26 18:55:48 +090039// The device may be configured to have the vendor libraries loaded to a separate namespace.
40// For historical reasons this namespace was named sphal but effectively it is intended
41// to use to load vendor libraries to separate namespace with controlled interface between
42// vendor and system namespaces.
43constexpr const char* kVendorNamespaceName = "sphal";
44constexpr const char* kVndkNamespaceName = "vndk";
Jiyong Park6291da22019-04-26 18:55:48 +090045constexpr const char* kRuntimeNamespaceName = "runtime";
Przemyslaw Szczepaniak0bb871d2019-07-10 12:08:57 +010046constexpr const char* kNeuralNetworksNamespaceName = "neuralnetworks";
Jiyong Park6291da22019-04-26 18:55:48 +090047
48// classloader-namespace is a linker namespace that is created for the loaded
49// app. To be specific, it is created for the app classloader. When
50// System.load() is called from a Java class that is loaded from the
51// classloader, the classloader-namespace namespace associated with that
52// classloader is selected for dlopen. The namespace is configured so that its
53// search path is set to the app-local JNI directory and it is linked to the
54// platform namespace with the names of libs listed in the public.libraries.txt.
55// This way an app can only load its own JNI libraries along with the public libs.
56constexpr const char* kClassloaderNamespaceName = "classloader-namespace";
57// Same thing for vendor APKs.
58constexpr const char* kVendorClassloaderNamespaceName = "vendor-classloader-namespace";
59
60// (http://b/27588281) This is a workaround for apps using custom classloaders and calling
61// System.load() with an absolute path which is outside of the classloader library search path.
62// This list includes all directories app is allowed to access this way.
63constexpr const char* kWhitelistedDirectories = "/data:/mnt/expand";
64
Jiyong Parkf8802e52019-05-03 16:34:56 +090065constexpr const char* kVendorLibPath = "/vendor/" LIB;
66constexpr const char* kProductLibPath = "/product/" LIB ":/system/product/" LIB;
Jiyong Park6291da22019-04-26 18:55:48 +090067
68const std::regex kVendorDexPathRegex("(^|:)/vendor/");
69const std::regex kProductDexPathRegex("(^|:)(/system)?/product/");
70
71// Define origin of APK if it is from vendor partition or product partition
72typedef enum {
73 APK_ORIGIN_DEFAULT = 0,
74 APK_ORIGIN_VENDOR = 1,
75 APK_ORIGIN_PRODUCT = 2,
76} ApkOrigin;
77
Jiyong Park6291da22019-04-26 18:55:48 +090078jobject GetParentClassLoader(JNIEnv* env, jobject class_loader) {
79 jclass class_loader_class = env->FindClass("java/lang/ClassLoader");
80 jmethodID get_parent =
81 env->GetMethodID(class_loader_class, "getParent", "()Ljava/lang/ClassLoader;");
82
83 return env->CallObjectMethod(class_loader, get_parent);
84}
85
86ApkOrigin GetApkOriginFromDexPath(JNIEnv* env, jstring dex_path) {
87 ApkOrigin apk_origin = APK_ORIGIN_DEFAULT;
88
89 if (dex_path != nullptr) {
90 ScopedUtfChars dex_path_utf_chars(env, dex_path);
91
92 if (std::regex_search(dex_path_utf_chars.c_str(), kVendorDexPathRegex)) {
93 apk_origin = APK_ORIGIN_VENDOR;
94 }
95
96 if (std::regex_search(dex_path_utf_chars.c_str(), kProductDexPathRegex)) {
97 LOG_ALWAYS_FATAL_IF(apk_origin == APK_ORIGIN_VENDOR,
98 "Dex path contains both vendor and product partition : %s",
99 dex_path_utf_chars.c_str());
100
101 apk_origin = APK_ORIGIN_PRODUCT;
102 }
103 }
104 return apk_origin;
105}
106
107} // namespace
108
109void LibraryNamespaces::Initialize() {
110 // Once public namespace is initialized there is no
111 // point in running this code - it will have no effect
112 // on the current list of public libraries.
113 if (initialized_) {
114 return;
115 }
116
Jiyong Park6291da22019-04-26 18:55:48 +0900117 // android_init_namespaces() expects all the public libraries
118 // to be loaded so that they can be found by soname alone.
119 //
120 // TODO(dimitry): this is a bit misleading since we do not know
121 // if the vendor public library is going to be opened from /vendor/lib
122 // we might as well end up loading them from /system/lib or /product/lib
123 // For now we rely on CTS test to catch things like this but
124 // it should probably be addressed in the future.
Jiyong Park5b8b3062019-05-03 18:11:49 +0900125 for (const auto& soname : android::base::Split(default_public_libraries(), ":")) {
Jiyong Park6291da22019-04-26 18:55:48 +0900126 LOG_ALWAYS_FATAL_IF(dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr,
127 "Error preloading public library %s: %s", soname.c_str(), dlerror());
128 }
Jiyong Park6291da22019-04-26 18:55:48 +0900129}
130
131NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sdk_version,
132 jobject class_loader, bool is_shared,
133 jstring dex_path, jstring java_library_path,
134 jstring java_permitted_path,
135 std::string* error_msg) {
136 std::string library_path; // empty string by default.
137
138 if (java_library_path != nullptr) {
139 ScopedUtfChars library_path_utf_chars(env, java_library_path);
140 library_path = library_path_utf_chars.c_str();
141 }
142
143 ApkOrigin apk_origin = GetApkOriginFromDexPath(env, dex_path);
144
145 // (http://b/27588281) This is a workaround for apps using custom
146 // classloaders and calling System.load() with an absolute path which
147 // is outside of the classloader library search path.
148 //
149 // This part effectively allows such a classloader to access anything
150 // under /data and /mnt/expand
151 std::string permitted_path = kWhitelistedDirectories;
152
153 if (java_permitted_path != nullptr) {
154 ScopedUtfChars path(env, java_permitted_path);
155 if (path.c_str() != nullptr && path.size() > 0) {
156 permitted_path = permitted_path + ":" + path.c_str();
157 }
158 }
159
160 // Initialize the anonymous namespace with the first non-empty library path.
161 if (!library_path.empty() && !initialized_ &&
162 !InitPublicNamespace(library_path.c_str(), error_msg)) {
163 return nullptr;
164 }
165
166 bool found = FindNamespaceByClassLoader(env, class_loader);
167
168 LOG_ALWAYS_FATAL_IF(found, "There is already a namespace associated with this classloader");
169
Jiyong Park5b8b3062019-05-03 18:11:49 +0900170 std::string system_exposed_libraries = default_public_libraries();
Jiyong Park6291da22019-04-26 18:55:48 +0900171 const char* namespace_name = kClassloaderNamespaceName;
Jiyong Park85377812019-05-04 00:30:23 +0900172 bool unbundled_vendor_or_product_app = false;
Jiyong Park6291da22019-04-26 18:55:48 +0900173 if ((apk_origin == APK_ORIGIN_VENDOR ||
174 (apk_origin == APK_ORIGIN_PRODUCT && target_sdk_version > 29)) &&
175 !is_shared) {
Jiyong Park85377812019-05-04 00:30:23 +0900176 unbundled_vendor_or_product_app = true;
Jiyong Park6291da22019-04-26 18:55:48 +0900177 // For vendor / product apks, give access to the vendor / product lib even though
178 // they are treated as unbundled; the libs and apks are still bundled
179 // together in the vendor / product partition.
180 const char* origin_partition;
181 const char* origin_lib_path;
182
183 switch (apk_origin) {
184 case APK_ORIGIN_VENDOR:
185 origin_partition = "vendor";
186 origin_lib_path = kVendorLibPath;
187 break;
188 case APK_ORIGIN_PRODUCT:
189 origin_partition = "product";
190 origin_lib_path = kProductLibPath;
191 break;
192 default:
193 origin_partition = "unknown";
194 origin_lib_path = "";
195 }
Jiyong Park6291da22019-04-26 18:55:48 +0900196 library_path = library_path + ":" + origin_lib_path;
197 permitted_path = permitted_path + ":" + origin_lib_path;
198
199 // Also give access to LLNDK libraries since they are available to vendors
Jiyong Park5b8b3062019-05-03 18:11:49 +0900200 system_exposed_libraries = system_exposed_libraries + ":" + llndk_libraries().c_str();
Jiyong Park6291da22019-04-26 18:55:48 +0900201
Jiyong Park6291da22019-04-26 18:55:48 +0900202 // Different name is useful for debugging
203 namespace_name = kVendorClassloaderNamespaceName;
204 ALOGD("classloader namespace configured for unbundled %s apk. library_path=%s",
205 origin_partition, library_path.c_str());
206 } else {
Jiyong Park5b8b3062019-05-03 18:11:49 +0900207 // extended public libraries are NOT available to vendor apks, otherwise it
Jiyong Park6291da22019-04-26 18:55:48 +0900208 // would be system->vendor violation.
Jiyong Park5b8b3062019-05-03 18:11:49 +0900209 if (!extended_public_libraries().empty()) {
210 system_exposed_libraries = system_exposed_libraries + ':' + extended_public_libraries();
Jiyong Park6291da22019-04-26 18:55:48 +0900211 }
212 }
Jiyong Park6291da22019-04-26 18:55:48 +0900213
Jiyong Park85377812019-05-04 00:30:23 +0900214 // Create the app namespace
215 NativeLoaderNamespace* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
216 auto app_ns =
217 NativeLoaderNamespace::Create(namespace_name, library_path, permitted_path, parent_ns,
218 is_shared, target_sdk_version < 24 /* is_greylist_enabled */);
219 if (app_ns.IsNil()) {
220 *error_msg = app_ns.GetError();
221 return nullptr;
Jiyong Park6291da22019-04-26 18:55:48 +0900222 }
223
Jiyong Park85377812019-05-04 00:30:23 +0900224 // ... and link to other namespaces to allow access to some public libraries
225 bool is_bridged = app_ns.IsBridged();
226
227 auto platform_ns = NativeLoaderNamespace::GetPlatformNamespace(is_bridged);
228 if (!app_ns.Link(platform_ns, system_exposed_libraries)) {
229 *error_msg = app_ns.GetError();
230 return nullptr;
231 }
232
233 auto runtime_ns = NativeLoaderNamespace::GetExportedNamespace(kRuntimeNamespaceName, is_bridged);
234 // Runtime apex does not exist in host, and under certain build conditions.
235 if (!runtime_ns.IsNil()) {
236 if (!app_ns.Link(runtime_ns, runtime_public_libraries())) {
237 *error_msg = app_ns.GetError();
238 return nullptr;
239 }
240 }
241
Przemyslaw Szczepaniak0bb871d2019-07-10 12:08:57 +0100242 // Give access to NNAPI libraries (apex-updated LLNDK library).
243 auto nnapi_ns =
244 NativeLoaderNamespace::GetExportedNamespace(kNeuralNetworksNamespaceName, is_bridged);
245 if (!app_ns.Link(nnapi_ns, neuralnetworks_public_libraries())) {
246 *error_msg = app_ns.GetError();
247 return nullptr;
248 }
249
Jiyong Park85377812019-05-04 00:30:23 +0900250 // Give access to VNDK-SP libraries from the 'vndk' namespace.
251 if (unbundled_vendor_or_product_app && !vndksp_libraries().empty()) {
252 auto vndk_ns = NativeLoaderNamespace::GetExportedNamespace(kVndkNamespaceName, is_bridged);
253 if (!vndk_ns.IsNil() && !app_ns.Link(vndk_ns, vndksp_libraries())) {
254 *error_msg = app_ns.GetError();
255 return nullptr;
256 }
257 }
258
259 // Note that when vendor_ns is not configured, vendor_ns.IsNil() will be true
260 // and it will result in linking to the default namespace which is expected
261 // behavior in this case.
262 if (!vendor_public_libraries().empty()) {
263 auto vendor_ns = NativeLoaderNamespace::GetExportedNamespace(kVendorNamespaceName, is_bridged);
264 if (!app_ns.Link(vendor_ns, vendor_public_libraries())) {
265 *error_msg = dlerror();
266 return nullptr;
267 }
268 }
269
270 namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), app_ns));
Jiyong Park6291da22019-04-26 18:55:48 +0900271
272 return &(namespaces_.back().second);
273}
274
275NativeLoaderNamespace* LibraryNamespaces::FindNamespaceByClassLoader(JNIEnv* env,
276 jobject class_loader) {
277 auto it = std::find_if(namespaces_.begin(), namespaces_.end(),
278 [&](const std::pair<jweak, NativeLoaderNamespace>& value) {
279 return env->IsSameObject(value.first, class_loader);
280 });
281 if (it != namespaces_.end()) {
282 return &it->second;
283 }
284
285 return nullptr;
286}
287
288bool LibraryNamespaces::InitPublicNamespace(const char* library_path, std::string* error_msg) {
289 // Ask native bride if this apps library path should be handled by it
290 bool is_native_bridge = NativeBridgeIsPathSupported(library_path);
291
292 // (http://b/25844435) - Some apps call dlopen from generated code (mono jited
293 // code is one example) unknown to linker in which case linker uses anonymous
294 // namespace. The second argument specifies the search path for the anonymous
295 // namespace which is the library_path of the classloader.
Jiyong Park5b8b3062019-05-03 18:11:49 +0900296 initialized_ = android_init_anonymous_namespace(default_public_libraries().c_str(),
Jiyong Park6291da22019-04-26 18:55:48 +0900297 is_native_bridge ? nullptr : library_path);
298 if (!initialized_) {
299 *error_msg = dlerror();
300 return false;
301 }
302
303 // and now initialize native bridge namespaces if necessary.
304 if (NativeBridgeInitialized()) {
Jiyong Park5b8b3062019-05-03 18:11:49 +0900305 initialized_ = NativeBridgeInitAnonymousNamespace(default_public_libraries().c_str(),
Jiyong Park6291da22019-04-26 18:55:48 +0900306 is_native_bridge ? library_path : nullptr);
307 if (!initialized_) {
308 *error_msg = NativeBridgeGetError();
309 }
310 }
311
312 return initialized_;
313}
314
315NativeLoaderNamespace* LibraryNamespaces::FindParentNamespaceByClassLoader(JNIEnv* env,
316 jobject class_loader) {
317 jobject parent_class_loader = GetParentClassLoader(env, class_loader);
318
319 while (parent_class_loader != nullptr) {
320 NativeLoaderNamespace* ns;
321 if ((ns = FindNamespaceByClassLoader(env, parent_class_loader)) != nullptr) {
322 return ns;
323 }
324
325 parent_class_loader = GetParentClassLoader(env, parent_class_loader);
326 }
327
328 return nullptr;
329}
330
Jiyong Park40a60772019-05-03 16:21:31 +0900331} // namespace android::nativeloader