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