blob: a81fddf0fa256b965cc46a3fa58eb1b9799c11d3 [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
17#define LOG_TAG "nativeloader"
18
19#include "native_loader_namespace.h"
20
21#include <dlfcn.h>
22
23#include <functional>
24
25#include <android-base/strings.h>
26#include <log/log.h>
27#include <nativebridge/native_bridge.h>
28
29#include "nativeloader/dlext_namespaces.h"
30
31using android::base::Error;
32using android::base::Errorf;
33
34namespace android {
35
36namespace {
37
38constexpr const char* kDefaultNamespaceName = "default";
39constexpr const char* kPlatformNamespaceName = "platform";
40
41std::string GetLinkerError(bool is_bridged) {
42 const char* msg = is_bridged ? NativeBridgeGetError() : dlerror();
43 if (msg == nullptr) {
44 return "no error";
45 }
46 return std::string(msg);
47}
48
49} // namespace
50
51Result<NativeLoaderNamespace> NativeLoaderNamespace::GetExportedNamespace(const std::string& name,
52 bool is_bridged) {
53 if (!is_bridged) {
54 auto raw = android_get_exported_namespace(name.c_str());
55 if (raw != nullptr) {
56 return NativeLoaderNamespace(name, raw);
57 }
58 } else {
59 auto raw = NativeBridgeGetExportedNamespace(name.c_str());
60 if (raw != nullptr) {
61 return NativeLoaderNamespace(name, raw);
62 }
63 }
64 return Errorf("namespace {} does not exist or exported", name);
65}
66
67// The platform namespace is called "default" for binaries in /system and
68// "platform" for those in the Runtime APEX. Try "platform" first since
69// "default" always exists.
70Result<NativeLoaderNamespace> NativeLoaderNamespace::GetPlatformNamespace(bool is_bridged) {
71 auto ns = GetExportedNamespace(kPlatformNamespaceName, is_bridged);
72 if (ns) return ns;
73 ns = GetExportedNamespace(kDefaultNamespaceName, is_bridged);
74 if (ns) return ns;
75
76 // If nothing is found, return NativeLoaderNamespace constructed from nullptr.
77 // nullptr also means default namespace to the linker.
78 if (!is_bridged) {
79 return NativeLoaderNamespace(kDefaultNamespaceName, static_cast<android_namespace_t*>(nullptr));
80 } else {
81 return NativeLoaderNamespace(kDefaultNamespaceName,
82 static_cast<native_bridge_namespace_t*>(nullptr));
83 }
84}
85
86Result<NativeLoaderNamespace> NativeLoaderNamespace::Create(
87 const std::string& name, const std::string& search_paths, const std::string& permitted_paths,
88 const NativeLoaderNamespace* parent, bool is_shared, bool is_greylist_enabled,
89 bool also_used_as_anonymous) {
90 bool is_bridged = false;
91 if (parent != nullptr) {
92 is_bridged = parent->IsBridged();
93 } else if (!search_paths.empty()) {
94 is_bridged = NativeBridgeIsPathSupported(search_paths.c_str());
95 }
96
97 // Fall back to the platform namespace if no parent is set.
98 auto platform_ns = GetPlatformNamespace(is_bridged);
99 if (!platform_ns) {
100 return platform_ns.error();
101 }
102 const NativeLoaderNamespace& effective_parent = parent != nullptr ? *parent : *platform_ns;
103
104 // All namespaces for apps are isolated
105 uint64_t type = ANDROID_NAMESPACE_TYPE_ISOLATED;
106
107 // The namespace is also used as the anonymous namespace
108 // which is used when the linker fails to determine the caller address
109 if (also_used_as_anonymous) {
110 type |= ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS;
111 }
112
113 // Bundled apps have access to all system libraries that are currently loaded
114 // in the default namespace
115 if (is_shared) {
116 type |= ANDROID_NAMESPACE_TYPE_SHARED;
117 }
118 if (is_greylist_enabled) {
119 type |= ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED;
120 }
121
122 if (!is_bridged) {
123 android_namespace_t* raw =
124 android_create_namespace(name.c_str(), nullptr, search_paths.c_str(), type,
125 permitted_paths.c_str(), effective_parent.ToRawAndroidNamespace());
126 if (raw != nullptr) {
127 return NativeLoaderNamespace(name, raw);
128 }
129 } else {
130 native_bridge_namespace_t* raw = NativeBridgeCreateNamespace(
131 name.c_str(), nullptr, search_paths.c_str(), type, permitted_paths.c_str(),
132 effective_parent.ToRawNativeBridgeNamespace());
133 if (raw != nullptr) {
134 return NativeLoaderNamespace(name, raw);
135 }
136 }
137 return Errorf("failed to create {} namespace name:{}, search_paths:{}, permitted_paths:{}",
138 is_bridged ? "bridged" : "native", name, search_paths, permitted_paths);
139}
140
141Result<void> NativeLoaderNamespace::Link(const NativeLoaderNamespace& target,
142 const std::string& shared_libs) const {
143 LOG_ALWAYS_FATAL_IF(shared_libs.empty(), "empty share lib when linking %s to %s",
144 this->name().c_str(), target.name().c_str());
145 if (!IsBridged()) {
146 if (android_link_namespaces(this->ToRawAndroidNamespace(), target.ToRawAndroidNamespace(),
147 shared_libs.c_str())) {
148 return {};
149 }
150 } else {
151 if (NativeBridgeLinkNamespaces(this->ToRawNativeBridgeNamespace(),
152 target.ToRawNativeBridgeNamespace(), shared_libs.c_str())) {
153 return {};
154 }
155 }
156 return Error() << GetLinkerError(IsBridged());
157}
158
159Result<void*> NativeLoaderNamespace::Load(const char* lib_name) const {
160 if (!IsBridged()) {
161 android_dlextinfo extinfo;
162 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
163 extinfo.library_namespace = this->ToRawAndroidNamespace();
164 void* handle = android_dlopen_ext(lib_name, RTLD_NOW, &extinfo);
165 if (handle != nullptr) {
166 return handle;
167 }
168 } else {
169 void* handle =
170 NativeBridgeLoadLibraryExt(lib_name, RTLD_NOW, this->ToRawNativeBridgeNamespace());
171 if (handle != nullptr) {
172 return handle;
173 }
174 }
175 return Error() << GetLinkerError(IsBridged());
176}
177
178} // namespace android