blob: f7f972ffccfdc9223ac6148d6678e9db87376c7b [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";
46
47// classloader-namespace is a linker namespace that is created for the loaded
48// app. To be specific, it is created for the app classloader. When
49// System.load() is called from a Java class that is loaded from the
50// classloader, the classloader-namespace namespace associated with that
51// classloader is selected for dlopen. The namespace is configured so that its
52// search path is set to the app-local JNI directory and it is linked to the
53// platform namespace with the names of libs listed in the public.libraries.txt.
54// This way an app can only load its own JNI libraries along with the public libs.
55constexpr const char* kClassloaderNamespaceName = "classloader-namespace";
56// Same thing for vendor APKs.
57constexpr const char* kVendorClassloaderNamespaceName = "vendor-classloader-namespace";
58
59// (http://b/27588281) This is a workaround for apps using custom classloaders and calling
60// System.load() with an absolute path which is outside of the classloader library search path.
61// This list includes all directories app is allowed to access this way.
62constexpr const char* kWhitelistedDirectories = "/data:/mnt/expand";
63
Jiyong Parkf8802e52019-05-03 16:34:56 +090064constexpr const char* kVendorLibPath = "/vendor/" LIB;
65constexpr const char* kProductLibPath = "/product/" LIB ":/system/product/" LIB;
Jiyong Park6291da22019-04-26 18:55:48 +090066
67const std::regex kVendorDexPathRegex("(^|:)/vendor/");
68const std::regex kProductDexPathRegex("(^|:)(/system)?/product/");
69
70// Define origin of APK if it is from vendor partition or product partition
71typedef enum {
72 APK_ORIGIN_DEFAULT = 0,
73 APK_ORIGIN_VENDOR = 1,
74 APK_ORIGIN_PRODUCT = 2,
75} ApkOrigin;
76
Jiyong Park6291da22019-04-26 18:55:48 +090077jobject GetParentClassLoader(JNIEnv* env, jobject class_loader) {
78 jclass class_loader_class = env->FindClass("java/lang/ClassLoader");
79 jmethodID get_parent =
80 env->GetMethodID(class_loader_class, "getParent", "()Ljava/lang/ClassLoader;");
81
82 return env->CallObjectMethod(class_loader, get_parent);
83}
84
85ApkOrigin GetApkOriginFromDexPath(JNIEnv* env, jstring dex_path) {
86 ApkOrigin apk_origin = APK_ORIGIN_DEFAULT;
87
88 if (dex_path != nullptr) {
89 ScopedUtfChars dex_path_utf_chars(env, dex_path);
90
91 if (std::regex_search(dex_path_utf_chars.c_str(), kVendorDexPathRegex)) {
92 apk_origin = APK_ORIGIN_VENDOR;
93 }
94
95 if (std::regex_search(dex_path_utf_chars.c_str(), kProductDexPathRegex)) {
96 LOG_ALWAYS_FATAL_IF(apk_origin == APK_ORIGIN_VENDOR,
97 "Dex path contains both vendor and product partition : %s",
98 dex_path_utf_chars.c_str());
99
100 apk_origin = APK_ORIGIN_PRODUCT;
101 }
102 }
103 return apk_origin;
104}
105
106} // namespace
107
108void LibraryNamespaces::Initialize() {
109 // Once public namespace is initialized there is no
110 // point in running this code - it will have no effect
111 // on the current list of public libraries.
112 if (initialized_) {
113 return;
114 }
115
Jiyong Park6291da22019-04-26 18:55:48 +0900116 // android_init_namespaces() expects all the public libraries
117 // to be loaded so that they can be found by soname alone.
118 //
119 // TODO(dimitry): this is a bit misleading since we do not know
120 // if the vendor public library is going to be opened from /vendor/lib
121 // we might as well end up loading them from /system/lib or /product/lib
122 // For now we rely on CTS test to catch things like this but
123 // it should probably be addressed in the future.
Jiyong Park5b8b3062019-05-03 18:11:49 +0900124 for (const auto& soname : android::base::Split(default_public_libraries(), ":")) {
Jiyong Park6291da22019-04-26 18:55:48 +0900125 LOG_ALWAYS_FATAL_IF(dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr,
126 "Error preloading public library %s: %s", soname.c_str(), dlerror());
127 }
Jiyong Park6291da22019-04-26 18:55:48 +0900128}
129
130NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sdk_version,
131 jobject class_loader, bool is_shared,
132 jstring dex_path, jstring java_library_path,
133 jstring java_permitted_path,
134 std::string* error_msg) {
135 std::string library_path; // empty string by default.
136
137 if (java_library_path != nullptr) {
138 ScopedUtfChars library_path_utf_chars(env, java_library_path);
139 library_path = library_path_utf_chars.c_str();
140 }
141
142 ApkOrigin apk_origin = GetApkOriginFromDexPath(env, dex_path);
143
144 // (http://b/27588281) This is a workaround for apps using custom
145 // classloaders and calling System.load() with an absolute path which
146 // is outside of the classloader library search path.
147 //
148 // This part effectively allows such a classloader to access anything
149 // under /data and /mnt/expand
150 std::string permitted_path = kWhitelistedDirectories;
151
152 if (java_permitted_path != nullptr) {
153 ScopedUtfChars path(env, java_permitted_path);
154 if (path.c_str() != nullptr && path.size() > 0) {
155 permitted_path = permitted_path + ":" + path.c_str();
156 }
157 }
158
159 // Initialize the anonymous namespace with the first non-empty library path.
160 if (!library_path.empty() && !initialized_ &&
161 !InitPublicNamespace(library_path.c_str(), error_msg)) {
162 return nullptr;
163 }
164
165 bool found = FindNamespaceByClassLoader(env, class_loader);
166
167 LOG_ALWAYS_FATAL_IF(found, "There is already a namespace associated with this classloader");
168
Jiyong Park5b8b3062019-05-03 18:11:49 +0900169 std::string system_exposed_libraries = default_public_libraries();
Jiyong Park6291da22019-04-26 18:55:48 +0900170 const char* namespace_name = kClassloaderNamespaceName;
Jiyong Park85377812019-05-04 00:30:23 +0900171 bool unbundled_vendor_or_product_app = false;
Jiyong Park6291da22019-04-26 18:55:48 +0900172 if ((apk_origin == APK_ORIGIN_VENDOR ||
173 (apk_origin == APK_ORIGIN_PRODUCT && target_sdk_version > 29)) &&
174 !is_shared) {
Jiyong Park85377812019-05-04 00:30:23 +0900175 unbundled_vendor_or_product_app = true;
Jiyong Park6291da22019-04-26 18:55:48 +0900176 // For vendor / product apks, give access to the vendor / product lib even though
177 // they are treated as unbundled; the libs and apks are still bundled
178 // together in the vendor / product partition.
179 const char* origin_partition;
180 const char* origin_lib_path;
181
182 switch (apk_origin) {
183 case APK_ORIGIN_VENDOR:
184 origin_partition = "vendor";
185 origin_lib_path = kVendorLibPath;
186 break;
187 case APK_ORIGIN_PRODUCT:
188 origin_partition = "product";
189 origin_lib_path = kProductLibPath;
190 break;
191 default:
192 origin_partition = "unknown";
193 origin_lib_path = "";
194 }
Jiyong Park6291da22019-04-26 18:55:48 +0900195 library_path = library_path + ":" + origin_lib_path;
196 permitted_path = permitted_path + ":" + origin_lib_path;
197
198 // Also give access to LLNDK libraries since they are available to vendors
Jiyong Park5b8b3062019-05-03 18:11:49 +0900199 system_exposed_libraries = system_exposed_libraries + ":" + llndk_libraries().c_str();
Jiyong Park6291da22019-04-26 18:55:48 +0900200
Jiyong Park6291da22019-04-26 18:55:48 +0900201 // Different name is useful for debugging
202 namespace_name = kVendorClassloaderNamespaceName;
203 ALOGD("classloader namespace configured for unbundled %s apk. library_path=%s",
204 origin_partition, library_path.c_str());
205 } else {
Jiyong Park5b8b3062019-05-03 18:11:49 +0900206 // extended public libraries are NOT available to vendor apks, otherwise it
Jiyong Park6291da22019-04-26 18:55:48 +0900207 // would be system->vendor violation.
Jiyong Park5b8b3062019-05-03 18:11:49 +0900208 if (!extended_public_libraries().empty()) {
209 system_exposed_libraries = system_exposed_libraries + ':' + extended_public_libraries();
Jiyong Park6291da22019-04-26 18:55:48 +0900210 }
211 }
Jiyong Park6291da22019-04-26 18:55:48 +0900212
Jiyong Park85377812019-05-04 00:30:23 +0900213 // Create the app namespace
214 NativeLoaderNamespace* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
215 auto app_ns =
216 NativeLoaderNamespace::Create(namespace_name, library_path, permitted_path, parent_ns,
217 is_shared, target_sdk_version < 24 /* is_greylist_enabled */);
218 if (app_ns.IsNil()) {
219 *error_msg = app_ns.GetError();
220 return nullptr;
Jiyong Park6291da22019-04-26 18:55:48 +0900221 }
222
Jiyong Park85377812019-05-04 00:30:23 +0900223 // ... and link to other namespaces to allow access to some public libraries
224 bool is_bridged = app_ns.IsBridged();
225
226 auto platform_ns = NativeLoaderNamespace::GetPlatformNamespace(is_bridged);
227 if (!app_ns.Link(platform_ns, system_exposed_libraries)) {
228 *error_msg = app_ns.GetError();
229 return nullptr;
230 }
231
232 auto runtime_ns = NativeLoaderNamespace::GetExportedNamespace(kRuntimeNamespaceName, is_bridged);
233 // Runtime apex does not exist in host, and under certain build conditions.
234 if (!runtime_ns.IsNil()) {
235 if (!app_ns.Link(runtime_ns, runtime_public_libraries())) {
236 *error_msg = app_ns.GetError();
237 return nullptr;
238 }
239 }
240
241 // Give access to VNDK-SP libraries from the 'vndk' namespace.
242 if (unbundled_vendor_or_product_app && !vndksp_libraries().empty()) {
243 auto vndk_ns = NativeLoaderNamespace::GetExportedNamespace(kVndkNamespaceName, is_bridged);
244 if (!vndk_ns.IsNil() && !app_ns.Link(vndk_ns, vndksp_libraries())) {
245 *error_msg = app_ns.GetError();
246 return nullptr;
247 }
248 }
249
250 // Note that when vendor_ns is not configured, vendor_ns.IsNil() will be true
251 // and it will result in linking to the default namespace which is expected
252 // behavior in this case.
253 if (!vendor_public_libraries().empty()) {
254 auto vendor_ns = NativeLoaderNamespace::GetExportedNamespace(kVendorNamespaceName, is_bridged);
255 if (!app_ns.Link(vendor_ns, vendor_public_libraries())) {
256 *error_msg = dlerror();
257 return nullptr;
258 }
259 }
260
261 namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), app_ns));
Jiyong Park6291da22019-04-26 18:55:48 +0900262
263 return &(namespaces_.back().second);
264}
265
266NativeLoaderNamespace* LibraryNamespaces::FindNamespaceByClassLoader(JNIEnv* env,
267 jobject class_loader) {
268 auto it = std::find_if(namespaces_.begin(), namespaces_.end(),
269 [&](const std::pair<jweak, NativeLoaderNamespace>& value) {
270 return env->IsSameObject(value.first, class_loader);
271 });
272 if (it != namespaces_.end()) {
273 return &it->second;
274 }
275
276 return nullptr;
277}
278
279bool LibraryNamespaces::InitPublicNamespace(const char* library_path, std::string* error_msg) {
280 // Ask native bride if this apps library path should be handled by it
281 bool is_native_bridge = NativeBridgeIsPathSupported(library_path);
282
283 // (http://b/25844435) - Some apps call dlopen from generated code (mono jited
284 // code is one example) unknown to linker in which case linker uses anonymous
285 // namespace. The second argument specifies the search path for the anonymous
286 // namespace which is the library_path of the classloader.
Jiyong Park5b8b3062019-05-03 18:11:49 +0900287 initialized_ = android_init_anonymous_namespace(default_public_libraries().c_str(),
Jiyong Park6291da22019-04-26 18:55:48 +0900288 is_native_bridge ? nullptr : library_path);
289 if (!initialized_) {
290 *error_msg = dlerror();
291 return false;
292 }
293
294 // and now initialize native bridge namespaces if necessary.
295 if (NativeBridgeInitialized()) {
Jiyong Park5b8b3062019-05-03 18:11:49 +0900296 initialized_ = NativeBridgeInitAnonymousNamespace(default_public_libraries().c_str(),
Jiyong Park6291da22019-04-26 18:55:48 +0900297 is_native_bridge ? library_path : nullptr);
298 if (!initialized_) {
299 *error_msg = NativeBridgeGetError();
300 }
301 }
302
303 return initialized_;
304}
305
306NativeLoaderNamespace* LibraryNamespaces::FindParentNamespaceByClassLoader(JNIEnv* env,
307 jobject class_loader) {
308 jobject parent_class_loader = GetParentClassLoader(env, class_loader);
309
310 while (parent_class_loader != nullptr) {
311 NativeLoaderNamespace* ns;
312 if ((ns = FindNamespaceByClassLoader(env, parent_class_loader)) != nullptr) {
313 return ns;
314 }
315
316 parent_class_loader = GetParentClassLoader(env, parent_class_loader);
317 }
318
319 return nullptr;
320}
321
Jiyong Park40a60772019-05-03 16:21:31 +0900322} // namespace android::nativeloader