blob: 44b34583a6a5a1e5950e8566e91e1f6e91bc669e [file] [log] [blame]
Orion Hodson9b16e342019-10-09 13:29:16 +01001/*
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>
Jooyung Han538f99a2020-03-03 00:46:50 +090029#include <android-base/result.h>
Orion Hodson9b16e342019-10-09 13:29:16 +010030#include <android-base/strings.h>
Orion Hodson6dc0a432020-02-06 14:28:28 +000031#include <nativehelper/scoped_utf_chars.h>
Orion Hodson9b16e342019-10-09 13:29:16 +010032
33#include "nativeloader/dlext_namespaces.h"
34#include "public_libraries.h"
35#include "utils.h"
36
Orion Hodson9b16e342019-10-09 13:29:16 +010037namespace android::nativeloader {
38
39namespace {
Jooyung Han538f99a2020-03-03 00:46:50 +090040
41constexpr const char* kApexPath = "/apex/";
42
Orion Hodson9b16e342019-10-09 13:29:16 +010043// The device may be configured to have the vendor libraries loaded to a separate namespace.
44// For historical reasons this namespace was named sphal but effectively it is intended
45// to use to load vendor libraries to separate namespace with controlled interface between
46// vendor and system namespaces.
47constexpr const char* kVendorNamespaceName = "sphal";
48constexpr const char* kVndkNamespaceName = "vndk";
Justin Yuneb4f08c2020-02-18 11:29:07 +090049constexpr const char* kVndkProductNamespaceName = "vndk_product";
Kiyoung Kim272b36d2020-02-19 16:08:47 +090050constexpr const char* kArtNamespaceName = "com_android_art";
51constexpr const char* kNeuralNetworksNamespaceName = "com_android_neuralnetworks";
52constexpr const char* kCronetNamespaceName = "com_android_cronet";
53constexpr const char* kStatsdNamespaceName = "com_android_os_statsd";
Orion Hodson9b16e342019-10-09 13:29:16 +010054
55// classloader-namespace is a linker namespace that is created for the loaded
56// app. To be specific, it is created for the app classloader. When
57// System.load() is called from a Java class that is loaded from the
58// classloader, the classloader-namespace namespace associated with that
59// classloader is selected for dlopen. The namespace is configured so that its
60// search path is set to the app-local JNI directory and it is linked to the
Kiyoung Kim99c19ca2020-01-29 16:09:38 +090061// system namespace with the names of libs listed in the public.libraries.txt.
Orion Hodson9b16e342019-10-09 13:29:16 +010062// This way an app can only load its own JNI libraries along with the public libs.
63constexpr const char* kClassloaderNamespaceName = "classloader-namespace";
64// Same thing for vendor APKs.
65constexpr const char* kVendorClassloaderNamespaceName = "vendor-classloader-namespace";
Martin Stjernholm94fd9ea2019-10-24 16:57:34 +010066// If the namespace is shared then add this suffix to form
67// "classloader-namespace-shared" or "vendor-classloader-namespace-shared",
68// respectively. A shared namespace (cf. ANDROID_NAMESPACE_TYPE_SHARED) has
69// inherited all the libraries of the parent classloader namespace, or the
Kiyoung Kim99c19ca2020-01-29 16:09:38 +090070// system namespace for the main app classloader. It is used to give full
Martin Stjernholm94fd9ea2019-10-24 16:57:34 +010071// access to the platform libraries for apps bundled in the system image,
72// including their later updates installed in /data.
73constexpr const char* kSharedNamespaceSuffix = "-shared";
Orion Hodson9b16e342019-10-09 13:29:16 +010074
75// (http://b/27588281) This is a workaround for apps using custom classloaders and calling
76// System.load() with an absolute path which is outside of the classloader library search path.
77// This list includes all directories app is allowed to access this way.
78constexpr const char* kWhitelistedDirectories = "/data:/mnt/expand";
79
80constexpr const char* kVendorLibPath = "/vendor/" LIB;
81constexpr const char* kProductLibPath = "/product/" LIB ":/system/product/" LIB;
82
83const std::regex kVendorDexPathRegex("(^|:)/vendor/");
84const std::regex kProductDexPathRegex("(^|:)(/system)?/product/");
85
86// Define origin of APK if it is from vendor partition or product partition
Martin Stjernholm3bb009a2019-10-17 21:29:01 +010087using ApkOrigin = enum {
Orion Hodson9b16e342019-10-09 13:29:16 +010088 APK_ORIGIN_DEFAULT = 0,
89 APK_ORIGIN_VENDOR = 1,
90 APK_ORIGIN_PRODUCT = 2,
Martin Stjernholm3bb009a2019-10-17 21:29:01 +010091};
Orion Hodson9b16e342019-10-09 13:29:16 +010092
93jobject GetParentClassLoader(JNIEnv* env, jobject class_loader) {
94 jclass class_loader_class = env->FindClass("java/lang/ClassLoader");
95 jmethodID get_parent =
96 env->GetMethodID(class_loader_class, "getParent", "()Ljava/lang/ClassLoader;");
97
98 return env->CallObjectMethod(class_loader, get_parent);
99}
100
Jooyung Han538f99a2020-03-03 00:46:50 +0900101ApkOrigin GetApkOriginFromDexPath(const std::string& dex_path) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100102 ApkOrigin apk_origin = APK_ORIGIN_DEFAULT;
Jooyung Han538f99a2020-03-03 00:46:50 +0900103 if (std::regex_search(dex_path, kVendorDexPathRegex)) {
104 apk_origin = APK_ORIGIN_VENDOR;
105 }
106 if (std::regex_search(dex_path, kProductDexPathRegex)) {
107 LOG_ALWAYS_FATAL_IF(apk_origin == APK_ORIGIN_VENDOR,
108 "Dex path contains both vendor and product partition : %s",
109 dex_path.c_str());
Orion Hodson9b16e342019-10-09 13:29:16 +0100110
Jooyung Han538f99a2020-03-03 00:46:50 +0900111 apk_origin = APK_ORIGIN_PRODUCT;
Orion Hodson9b16e342019-10-09 13:29:16 +0100112 }
113 return apk_origin;
114}
115
116} // namespace
117
118void LibraryNamespaces::Initialize() {
119 // Once public namespace is initialized there is no
120 // point in running this code - it will have no effect
121 // on the current list of public libraries.
122 if (initialized_) {
123 return;
124 }
125
126 // android_init_namespaces() expects all the public libraries
127 // to be loaded so that they can be found by soname alone.
128 //
129 // TODO(dimitry): this is a bit misleading since we do not know
130 // if the vendor public library is going to be opened from /vendor/lib
131 // we might as well end up loading them from /system/lib or /product/lib
132 // For now we rely on CTS test to catch things like this but
133 // it should probably be addressed in the future.
134 for (const auto& soname : android::base::Split(preloadable_public_libraries(), ":")) {
135 LOG_ALWAYS_FATAL_IF(dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr,
136 "Error preloading public library %s: %s", soname.c_str(), dlerror());
137 }
138}
139
140Result<NativeLoaderNamespace*> LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sdk_version,
141 jobject class_loader, bool is_shared,
Jooyung Han538f99a2020-03-03 00:46:50 +0900142 jstring dex_path_j,
Orion Hodson9b16e342019-10-09 13:29:16 +0100143 jstring java_library_path,
144 jstring java_permitted_path) {
145 std::string library_path; // empty string by default.
Jooyung Han538f99a2020-03-03 00:46:50 +0900146 std::string dex_path;
Orion Hodson9b16e342019-10-09 13:29:16 +0100147
148 if (java_library_path != nullptr) {
149 ScopedUtfChars library_path_utf_chars(env, java_library_path);
150 library_path = library_path_utf_chars.c_str();
151 }
152
Jooyung Han538f99a2020-03-03 00:46:50 +0900153 if (dex_path_j != nullptr) {
154 ScopedUtfChars dex_path_chars(env, dex_path_j);
155 dex_path = dex_path_chars.c_str();
156 }
157
158 ApkOrigin apk_origin = GetApkOriginFromDexPath(dex_path);
Orion Hodson9b16e342019-10-09 13:29:16 +0100159
160 // (http://b/27588281) This is a workaround for apps using custom
161 // classloaders and calling System.load() with an absolute path which
162 // is outside of the classloader library search path.
163 //
164 // This part effectively allows such a classloader to access anything
165 // under /data and /mnt/expand
166 std::string permitted_path = kWhitelistedDirectories;
167
168 if (java_permitted_path != nullptr) {
169 ScopedUtfChars path(env, java_permitted_path);
170 if (path.c_str() != nullptr && path.size() > 0) {
171 permitted_path = permitted_path + ":" + path.c_str();
172 }
173 }
174
175 LOG_ALWAYS_FATAL_IF(FindNamespaceByClassLoader(env, class_loader) != nullptr,
176 "There is already a namespace associated with this classloader");
177
178 std::string system_exposed_libraries = default_public_libraries();
Martin Stjernholm94fd9ea2019-10-24 16:57:34 +0100179 std::string namespace_name = kClassloaderNamespaceName;
Justin Yuneb4f08c2020-02-18 11:29:07 +0900180 ApkOrigin unbundled_app_origin = APK_ORIGIN_DEFAULT;
Orion Hodson9b16e342019-10-09 13:29:16 +0100181 if ((apk_origin == APK_ORIGIN_VENDOR ||
Justin Yun3db26d52019-12-16 14:09:39 +0900182 (apk_origin == APK_ORIGIN_PRODUCT &&
183 is_product_vndk_version_defined())) &&
Orion Hodson9b16e342019-10-09 13:29:16 +0100184 !is_shared) {
Justin Yuneb4f08c2020-02-18 11:29:07 +0900185 unbundled_app_origin = apk_origin;
Orion Hodson9b16e342019-10-09 13:29:16 +0100186 // For vendor / product apks, give access to the vendor / product lib even though
187 // they are treated as unbundled; the libs and apks are still bundled
188 // together in the vendor / product partition.
189 const char* origin_partition;
190 const char* origin_lib_path;
Justin Yun089c1352020-02-06 16:53:08 +0900191 const char* llndk_libraries;
Orion Hodson9b16e342019-10-09 13:29:16 +0100192
193 switch (apk_origin) {
194 case APK_ORIGIN_VENDOR:
195 origin_partition = "vendor";
196 origin_lib_path = kVendorLibPath;
Justin Yun089c1352020-02-06 16:53:08 +0900197 llndk_libraries = llndk_libraries_vendor().c_str();
Orion Hodson9b16e342019-10-09 13:29:16 +0100198 break;
199 case APK_ORIGIN_PRODUCT:
200 origin_partition = "product";
201 origin_lib_path = kProductLibPath;
Justin Yun089c1352020-02-06 16:53:08 +0900202 llndk_libraries = llndk_libraries_product().c_str();
Orion Hodson9b16e342019-10-09 13:29:16 +0100203 break;
204 default:
205 origin_partition = "unknown";
206 origin_lib_path = "";
Justin Yun089c1352020-02-06 16:53:08 +0900207 llndk_libraries = "";
Orion Hodson9b16e342019-10-09 13:29:16 +0100208 }
209 library_path = library_path + ":" + origin_lib_path;
210 permitted_path = permitted_path + ":" + origin_lib_path;
211
Justin Yun089c1352020-02-06 16:53:08 +0900212 // Also give access to LLNDK libraries since they are available to vendor or product
213 system_exposed_libraries = system_exposed_libraries + ":" + llndk_libraries;
Orion Hodson9b16e342019-10-09 13:29:16 +0100214
215 // Different name is useful for debugging
216 namespace_name = kVendorClassloaderNamespaceName;
217 ALOGD("classloader namespace configured for unbundled %s apk. library_path=%s",
218 origin_partition, library_path.c_str());
219 } else {
220 // extended public libraries are NOT available to vendor apks, otherwise it
221 // would be system->vendor violation.
222 if (!extended_public_libraries().empty()) {
223 system_exposed_libraries = system_exposed_libraries + ':' + extended_public_libraries();
224 }
225 }
226
Martin Stjernholm94fd9ea2019-10-24 16:57:34 +0100227 if (is_shared) {
228 // Show in the name that the namespace was created as shared, for debugging
229 // purposes.
230 namespace_name = namespace_name + kSharedNamespaceSuffix;
231 }
232
Orion Hodson9b16e342019-10-09 13:29:16 +0100233 // Create the app namespace
234 NativeLoaderNamespace* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
235 // Heuristic: the first classloader with non-empty library_path is assumed to
236 // be the main classloader for app
237 // TODO(b/139178525) remove this heuristic by determining this in LoadedApk (or its
238 // friends) and then passing it down to here.
239 bool is_main_classloader = app_main_namespace_ == nullptr && !library_path.empty();
240 // Policy: the namespace for the main classloader is also used as the
241 // anonymous namespace.
242 bool also_used_as_anonymous = is_main_classloader;
243 // Note: this function is executed with g_namespaces_mutex held, thus no
244 // racing here.
245 auto app_ns = NativeLoaderNamespace::Create(
246 namespace_name, library_path, permitted_path, parent_ns, is_shared,
247 target_sdk_version < 24 /* is_greylist_enabled */, also_used_as_anonymous);
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900248 if (!app_ns.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100249 return app_ns.error();
250 }
251 // ... and link to other namespaces to allow access to some public libraries
252 bool is_bridged = app_ns->IsBridged();
253
Martin Stjernholmf0e99bd2020-02-11 22:57:14 +0000254 auto system_ns = NativeLoaderNamespace::GetSystemNamespace(is_bridged);
255 if (!system_ns.ok()) {
256 return system_ns.error();
Orion Hodson9b16e342019-10-09 13:29:16 +0100257 }
258
Martin Stjernholmf0e99bd2020-02-11 22:57:14 +0000259 auto linked = app_ns->Link(*system_ns, system_exposed_libraries);
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900260 if (!linked.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100261 return linked.error();
262 }
263
264 auto art_ns = NativeLoaderNamespace::GetExportedNamespace(kArtNamespaceName, is_bridged);
265 // ART APEX does not exist on host, and under certain build conditions.
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900266 if (art_ns.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100267 linked = app_ns->Link(*art_ns, art_public_libraries());
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900268 if (!linked.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100269 return linked.error();
270 }
271 }
272
273 // Give access to NNAPI libraries (apex-updated LLNDK library).
274 auto nnapi_ns =
275 NativeLoaderNamespace::GetExportedNamespace(kNeuralNetworksNamespaceName, is_bridged);
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900276 if (nnapi_ns.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100277 linked = app_ns->Link(*nnapi_ns, neuralnetworks_public_libraries());
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900278 if (!linked.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100279 return linked.error();
280 }
281 }
282
Justin Yuneb4f08c2020-02-18 11:29:07 +0900283 // Give access to VNDK-SP libraries from the 'vndk' namespace for unbundled vendor apps.
284 if (unbundled_app_origin == APK_ORIGIN_VENDOR && !vndksp_libraries_vendor().empty()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100285 auto vndk_ns = NativeLoaderNamespace::GetExportedNamespace(kVndkNamespaceName, is_bridged);
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900286 if (vndk_ns.ok()) {
Justin Yuneb4f08c2020-02-18 11:29:07 +0900287 linked = app_ns->Link(*vndk_ns, vndksp_libraries_vendor());
288 if (!linked.ok()) {
289 return linked.error();
290 }
291 }
292 }
293
294 // Give access to VNDK-SP libraries from the 'vndk_product' namespace for unbundled product apps.
295 if (unbundled_app_origin == APK_ORIGIN_PRODUCT && !vndksp_libraries_product().empty()) {
296 auto vndk_ns = NativeLoaderNamespace::GetExportedNamespace(kVndkProductNamespaceName, is_bridged);
297 if (vndk_ns.ok()) {
298 linked = app_ns->Link(*vndk_ns, vndksp_libraries_product());
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900299 if (!linked.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100300 return linked.error();
301 }
302 }
303 }
304
Jooyung Han538f99a2020-03-03 00:46:50 +0900305 auto apex_ns_name = FindApexNamespaceName(dex_path);
306 if (apex_ns_name.ok()) {
307 const auto& jni_libs = apex_jni_libraries(*apex_ns_name);
308 if (jni_libs != "") {
309 auto apex_ns = NativeLoaderNamespace::GetExportedNamespace(*apex_ns_name, is_bridged);
310 if (apex_ns.ok()) {
311 auto link = app_ns->Link(*apex_ns, jni_libs);
312 if (!link.ok()) {
313 return linked.error();
314 }
315 }
316 }
317 }
318
Luke Huang5c017722019-12-17 10:54:26 +0800319 // TODO(b/143733063): Remove it after library path of apex module is supported.
320 auto cronet_ns =
321 NativeLoaderNamespace::GetExportedNamespace(kCronetNamespaceName, is_bridged);
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900322 if (cronet_ns.ok()) {
Luke Huang5c017722019-12-17 10:54:26 +0800323 linked = app_ns->Link(*cronet_ns, cronet_public_libraries());
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900324 if (!linked.ok()) {
Luke Huang5c017722019-12-17 10:54:26 +0800325 return linked.error();
326 }
327 }
328
Jeffrey Huang52575032020-02-11 17:33:45 -0800329 // Give access to StatsdAPI libraries
330 auto statsd_ns =
331 NativeLoaderNamespace::GetExportedNamespace(kStatsdNamespaceName, is_bridged);
332 if (statsd_ns.ok()) {
333 linked = app_ns->Link(*statsd_ns, statsd_public_libraries());
334 if (!linked.ok()) {
335 return linked.error();
336 }
337 }
338
Orion Hodson9b16e342019-10-09 13:29:16 +0100339 if (!vendor_public_libraries().empty()) {
340 auto vendor_ns = NativeLoaderNamespace::GetExportedNamespace(kVendorNamespaceName, is_bridged);
Kiyoung Kim99c19ca2020-01-29 16:09:38 +0900341 // when vendor_ns is not configured, link to the system namespace
Martin Stjernholmf0e99bd2020-02-11 22:57:14 +0000342 auto target_ns = vendor_ns.ok() ? vendor_ns : system_ns;
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900343 if (target_ns.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100344 linked = app_ns->Link(*target_ns, vendor_public_libraries());
Bernie Innocenti4bd58952020-02-06 15:43:57 +0900345 if (!linked.ok()) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100346 return linked.error();
347 }
348 }
349 }
350
Orion Hodsonc20ab9a2020-02-06 12:32:08 +0000351 auto& emplaced = namespaces_.emplace_back(
352 std::make_pair(env->NewWeakGlobalRef(class_loader), *app_ns));
Orion Hodson9b16e342019-10-09 13:29:16 +0100353 if (is_main_classloader) {
Orion Hodsonc20ab9a2020-02-06 12:32:08 +0000354 app_main_namespace_ = &emplaced.second;
Orion Hodson9b16e342019-10-09 13:29:16 +0100355 }
Orion Hodsonc20ab9a2020-02-06 12:32:08 +0000356 return &emplaced.second;
Orion Hodson9b16e342019-10-09 13:29:16 +0100357}
358
359NativeLoaderNamespace* LibraryNamespaces::FindNamespaceByClassLoader(JNIEnv* env,
360 jobject class_loader) {
361 auto it = std::find_if(namespaces_.begin(), namespaces_.end(),
362 [&](const std::pair<jweak, NativeLoaderNamespace>& value) {
363 return env->IsSameObject(value.first, class_loader);
364 });
365 if (it != namespaces_.end()) {
366 return &it->second;
367 }
368
369 return nullptr;
370}
371
372NativeLoaderNamespace* LibraryNamespaces::FindParentNamespaceByClassLoader(JNIEnv* env,
373 jobject class_loader) {
374 jobject parent_class_loader = GetParentClassLoader(env, class_loader);
375
376 while (parent_class_loader != nullptr) {
377 NativeLoaderNamespace* ns;
378 if ((ns = FindNamespaceByClassLoader(env, parent_class_loader)) != nullptr) {
379 return ns;
380 }
381
382 parent_class_loader = GetParentClassLoader(env, parent_class_loader);
383 }
384
385 return nullptr;
386}
387
Jooyung Han538f99a2020-03-03 00:46:50 +0900388base::Result<std::string> FindApexNamespaceName(const std::string& location) {
389 // Lots of implicit assumptions here: we expect `location` to be of the form:
390 // /apex/modulename/...
391 //
392 // And we extract from it 'modulename', and then apply mangling rule to get namespace name for it.
393 if (android::base::StartsWith(location, kApexPath)) {
394 size_t start_index = strlen(kApexPath);
395 size_t slash_index = location.find_first_of('/', start_index);
396 LOG_ALWAYS_FATAL_IF((slash_index == std::string::npos),
397 "Error finding namespace of apex: no slash in path %s", location.c_str());
398 std::string name = location.substr(start_index, slash_index - start_index);
399 std::replace(name.begin(), name.end(), '.', '_');
400 return name;
401 }
402 return base::Error();
403}
404
Orion Hodson9b16e342019-10-09 13:29:16 +0100405} // namespace android::nativeloader