1 /*
2  * Copyright (C) 2020 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 #include "linker_translate_path.h"
18 
19 #include <string>
20 
21 #include <android/api-level.h>
22 
23 #include "linker.h"
24 
25 // Handle dlopen by full path.
26 //
27 // 1. Translate original path to native_bridge path.
28 //
29 // Native bridge libraries reside in $LIB/$ABI subdirectory. For example:
30 //   /system/lib/liblog.so -> /system/lib/arm/liblog.so
31 //
32 // Native bridge libraries do not use apex. For example:
33 //   /apex/com.android.i18n/lib/libicuuc.so -> /system/lib/arm/libicuuc.so
34 //
35 // 2. Repeat linker workaround to open apex libraries by system path (see http://b/121248172).
36 //
37 // For older target SDK versions, linker allows to open apex libraries by system path, so it does:
38 //   /system/lib/libicuuc.so -> /apex/com.android.art/lib/libicuuc.so
39 //
40 // Adding native bridge path translation, we get:
41 //   /system/lib/libicuuc.so -> /apex/com.android.art/lib/libicuuc.so -> /system/lib/arm/libicuuc.so
42 
43 #if defined(__arm__)
44 #define SYSTEM_LIB(name) \
45   { "/system/lib/" name, "/system/lib/arm/" name }
46 #define APEX_LIB(apex, name) \
47   { "/apex/" apex "/lib/" name, "/system/lib/arm/" name }
48 #elif defined(__aarch64__)
49 #define SYSTEM_LIB(name) \
50   { "/system/lib64/" name, "/system/lib64/arm64/" name }
51 #define APEX_LIB(apex, name) \
52   { "/apex/" apex "/lib64/" name, "/system/lib64/arm64/" name }
53 #elif defined(__riscv)
54 #define SYSTEM_LIB(name) \
55   { "/system/lib64/" name, "/system/lib64/riscv64/" name }
56 #define APEX_LIB(apex, name) \
57   { "/apex/" apex "/lib64/" name, "/system/lib64/riscv64/" name }
58 #else
59 #error "Unknown guest arch"
60 #endif
61 
62 /**
63  * Translate /system path or /apex path to native_bridge path
64  * Function name is misleading, as it overrides the corresponding function in original linker.
65  *
66  * param out_name pointing to native_bridge path
67  * return true if translation is needed
68  */
translateSystemPathToApexPath(const char * name,std::string * out_name)69 bool translateSystemPathToApexPath(const char* name, std::string* out_name) {
70   static constexpr const char* kPathTranslation[][2] = {
71     // Libraries accessible by system path.
72     SYSTEM_LIB("libEGL.so"),
73     SYSTEM_LIB("libGLESv1_CM.so"),
74     SYSTEM_LIB("libGLESv2.so"),
75     SYSTEM_LIB("libGLESv3.so"),
76     SYSTEM_LIB("libOpenMAXAL.so"),
77     SYSTEM_LIB("libOpenSLES.so"),
78     SYSTEM_LIB("libRS.so"),
79     SYSTEM_LIB("libaaudio.so"),
80     SYSTEM_LIB("libamidi.so"),
81     SYSTEM_LIB("libandroid.so"),
82     SYSTEM_LIB("libbinder_ndk.so"),
83     SYSTEM_LIB("libc.so"),
84     SYSTEM_LIB("libcamera2ndk.so"),
85     SYSTEM_LIB("libdl.so"),
86     SYSTEM_LIB("libjnigraphics.so"),
87     SYSTEM_LIB("liblog.so"),
88     SYSTEM_LIB("libm.so"),
89     SYSTEM_LIB("libmediandk.so"),
90     SYSTEM_LIB("libnativewindow.so"),
91     SYSTEM_LIB("libstdc++.so"),
92     SYSTEM_LIB("libsync.so"),
93     SYSTEM_LIB("libvulkan.so"),
94     SYSTEM_LIB("libwebviewchromium_plat_support.so"),
95     SYSTEM_LIB("libz.so"),
96     // Apex/system after R.
97     APEX_LIB("com.android.i18n", "libandroidicu.so"),
98     APEX_LIB("com.android.i18n", "libicu.so"),
99     APEX_LIB("com.android.i18n", "libicui18n.so"),
100     APEX_LIB("com.android.i18n", "libicuuc.so"),
101     APEX_LIB("com.android.neuralnetworks", "libneuralnetworks.so"),
102     // Apex/system on R (see http://b/161958857).
103     APEX_LIB("com.android.art", "libicui18n.so"),
104     APEX_LIB("com.android.art", "libicuuc.so"),
105     APEX_LIB("com.android.art", "libnativehelper.so"),
106     // Apex/system on Q.
107     APEX_LIB("com.android.runtime", "libicui18n.so"),
108     APEX_LIB("com.android.runtime", "libicuuc.so"),
109   };
110 
111   static constexpr const char* kPathTranslationQ[][2] = {
112     // Apps targeting below Q can open apex libraries by system path.
113     SYSTEM_LIB("libicui18n.so"),
114     SYSTEM_LIB("libicuuc.so"),
115     SYSTEM_LIB("libneuralnetworks.so"),
116   };
117 
118   static constexpr const char* kPathTranslationN[][2] = {
119     // Apps targeting below N can open greylisted libraries.
120     SYSTEM_LIB("libandroid_runtime.so"),
121     SYSTEM_LIB("libbinder.so"),
122     SYSTEM_LIB("libcrypto.so"),
123     SYSTEM_LIB("libcutils.so"),
124     SYSTEM_LIB("libexpat.so"),
125     SYSTEM_LIB("libgui.so"),
126     SYSTEM_LIB("libmedia.so"),
127     SYSTEM_LIB("libnativehelper.so"),
128     SYSTEM_LIB("libssl.so"),
129     SYSTEM_LIB("libstagefright.so"),
130     SYSTEM_LIB("libsqlite.so"),
131     SYSTEM_LIB("libui.so"),
132     SYSTEM_LIB("libutils.so"),
133     SYSTEM_LIB("libvorbisidec.so"),
134   };
135 
136   if (name == nullptr) {
137     return false;
138   }
139 
140   auto comparator = [name](auto p) { return strcmp(name, p[0]) == 0; };
141 
142   if (auto it = std::find_if(std::begin(kPathTranslation), std::end(kPathTranslation), comparator);
143       it != std::end(kPathTranslation)) {
144     *out_name = (*it)[1];
145     return true;
146   }
147 
148   if (get_application_target_sdk_version() < __ANDROID_API_Q__) {
149     if (auto it =
150             std::find_if(std::begin(kPathTranslationQ), std::end(kPathTranslationQ), comparator);
151         it != std::end(kPathTranslationQ)) {
152       *out_name = (*it)[1];
153       return true;
154     }
155   }
156 
157   if (get_application_target_sdk_version() < __ANDROID_API_N__) {
158     if (auto it =
159             std::find_if(std::begin(kPathTranslationN), std::end(kPathTranslationN), comparator);
160         it != std::end(kPathTranslationN)) {
161       *out_name = (*it)[1];
162       return true;
163     }
164   }
165 
166   return false;
167 }
168