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