xref: /aosp_15_r20/bionic/linker/linker_utils.cpp (revision 8d67ca893c1523eb926b9080dbe4e2ffd2a27ba1)
1*8d67ca89SAndroid Build Coastguard Worker /*
2*8d67ca89SAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*8d67ca89SAndroid Build Coastguard Worker  * All rights reserved.
4*8d67ca89SAndroid Build Coastguard Worker  *
5*8d67ca89SAndroid Build Coastguard Worker  * Redistribution and use in source and binary forms, with or without
6*8d67ca89SAndroid Build Coastguard Worker  * modification, are permitted provided that the following conditions
7*8d67ca89SAndroid Build Coastguard Worker  * are met:
8*8d67ca89SAndroid Build Coastguard Worker  *  * Redistributions of source code must retain the above copyright
9*8d67ca89SAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer.
10*8d67ca89SAndroid Build Coastguard Worker  *  * Redistributions in binary form must reproduce the above copyright
11*8d67ca89SAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer in
12*8d67ca89SAndroid Build Coastguard Worker  *    the documentation and/or other materials provided with the
13*8d67ca89SAndroid Build Coastguard Worker  *    distribution.
14*8d67ca89SAndroid Build Coastguard Worker  *
15*8d67ca89SAndroid Build Coastguard Worker  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16*8d67ca89SAndroid Build Coastguard Worker  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17*8d67ca89SAndroid Build Coastguard Worker  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18*8d67ca89SAndroid Build Coastguard Worker  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19*8d67ca89SAndroid Build Coastguard Worker  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20*8d67ca89SAndroid Build Coastguard Worker  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21*8d67ca89SAndroid Build Coastguard Worker  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22*8d67ca89SAndroid Build Coastguard Worker  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23*8d67ca89SAndroid Build Coastguard Worker  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24*8d67ca89SAndroid Build Coastguard Worker  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25*8d67ca89SAndroid Build Coastguard Worker  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*8d67ca89SAndroid Build Coastguard Worker  * SUCH DAMAGE.
27*8d67ca89SAndroid Build Coastguard Worker  */
28*8d67ca89SAndroid Build Coastguard Worker 
29*8d67ca89SAndroid Build Coastguard Worker #include "linker_utils.h"
30*8d67ca89SAndroid Build Coastguard Worker 
31*8d67ca89SAndroid Build Coastguard Worker #include "linker_debug.h"
32*8d67ca89SAndroid Build Coastguard Worker #include "linker_globals.h"
33*8d67ca89SAndroid Build Coastguard Worker 
34*8d67ca89SAndroid Build Coastguard Worker #include "android-base/strings.h"
35*8d67ca89SAndroid Build Coastguard Worker 
36*8d67ca89SAndroid Build Coastguard Worker #include <sys/stat.h>
37*8d67ca89SAndroid Build Coastguard Worker #include <unistd.h>
38*8d67ca89SAndroid Build Coastguard Worker 
format_string(std::string * str,const std::vector<std::pair<std::string,std::string>> & params)39*8d67ca89SAndroid Build Coastguard Worker void format_string(std::string* str, const std::vector<std::pair<std::string, std::string>>& params) {
40*8d67ca89SAndroid Build Coastguard Worker   size_t pos = 0;
41*8d67ca89SAndroid Build Coastguard Worker   while (pos < str->size()) {
42*8d67ca89SAndroid Build Coastguard Worker     pos = str->find("$", pos);
43*8d67ca89SAndroid Build Coastguard Worker     if (pos == std::string::npos) break;
44*8d67ca89SAndroid Build Coastguard Worker     for (const auto& param : params) {
45*8d67ca89SAndroid Build Coastguard Worker       const std::string& token = param.first;
46*8d67ca89SAndroid Build Coastguard Worker       const std::string& replacement = param.second;
47*8d67ca89SAndroid Build Coastguard Worker       if (str->substr(pos + 1, token.size()) == token) {
48*8d67ca89SAndroid Build Coastguard Worker         str->replace(pos, token.size() + 1, replacement);
49*8d67ca89SAndroid Build Coastguard Worker         // -1 to compensate for the ++pos below.
50*8d67ca89SAndroid Build Coastguard Worker         pos += replacement.size() - 1;
51*8d67ca89SAndroid Build Coastguard Worker         break;
52*8d67ca89SAndroid Build Coastguard Worker       } else if (str->substr(pos + 1, token.size() + 2) == "{" + token + "}") {
53*8d67ca89SAndroid Build Coastguard Worker         str->replace(pos, token.size() + 3, replacement);
54*8d67ca89SAndroid Build Coastguard Worker         pos += replacement.size() - 1;
55*8d67ca89SAndroid Build Coastguard Worker         break;
56*8d67ca89SAndroid Build Coastguard Worker       }
57*8d67ca89SAndroid Build Coastguard Worker     }
58*8d67ca89SAndroid Build Coastguard Worker     // Skip $ in case it did not match any of the known substitutions.
59*8d67ca89SAndroid Build Coastguard Worker     ++pos;
60*8d67ca89SAndroid Build Coastguard Worker   }
61*8d67ca89SAndroid Build Coastguard Worker }
62*8d67ca89SAndroid Build Coastguard Worker 
dirname(const char * path)63*8d67ca89SAndroid Build Coastguard Worker std::string dirname(const char* path) {
64*8d67ca89SAndroid Build Coastguard Worker   const char* last_slash = strrchr(path, '/');
65*8d67ca89SAndroid Build Coastguard Worker 
66*8d67ca89SAndroid Build Coastguard Worker   if (last_slash == path) {
67*8d67ca89SAndroid Build Coastguard Worker     return "/";
68*8d67ca89SAndroid Build Coastguard Worker   } else if (last_slash == nullptr) {
69*8d67ca89SAndroid Build Coastguard Worker     return ".";
70*8d67ca89SAndroid Build Coastguard Worker   } else {
71*8d67ca89SAndroid Build Coastguard Worker     return std::string(path, last_slash - path);
72*8d67ca89SAndroid Build Coastguard Worker   }
73*8d67ca89SAndroid Build Coastguard Worker }
74*8d67ca89SAndroid Build Coastguard Worker 
normalize_path(const char * path,std::string * normalized_path)75*8d67ca89SAndroid Build Coastguard Worker bool normalize_path(const char* path, std::string* normalized_path) {
76*8d67ca89SAndroid Build Coastguard Worker   // Input should be an absolute path
77*8d67ca89SAndroid Build Coastguard Worker   if (path[0] != '/') {
78*8d67ca89SAndroid Build Coastguard Worker     DL_WARN("normalize_path - invalid input: \"%s\", the input path should be absolute", path);
79*8d67ca89SAndroid Build Coastguard Worker     return false;
80*8d67ca89SAndroid Build Coastguard Worker   }
81*8d67ca89SAndroid Build Coastguard Worker 
82*8d67ca89SAndroid Build Coastguard Worker   const size_t len = strlen(path) + 1;
83*8d67ca89SAndroid Build Coastguard Worker   char buf[len];
84*8d67ca89SAndroid Build Coastguard Worker 
85*8d67ca89SAndroid Build Coastguard Worker   const char* in_ptr = path;
86*8d67ca89SAndroid Build Coastguard Worker   char* out_ptr = buf;
87*8d67ca89SAndroid Build Coastguard Worker 
88*8d67ca89SAndroid Build Coastguard Worker   while (*in_ptr != 0) {
89*8d67ca89SAndroid Build Coastguard Worker     if (*in_ptr == '/') {
90*8d67ca89SAndroid Build Coastguard Worker       char c1 = in_ptr[1];
91*8d67ca89SAndroid Build Coastguard Worker       if (c1 == '.') {
92*8d67ca89SAndroid Build Coastguard Worker         char c2 = in_ptr[2];
93*8d67ca89SAndroid Build Coastguard Worker         if (c2 == '/') {
94*8d67ca89SAndroid Build Coastguard Worker           in_ptr += 2;
95*8d67ca89SAndroid Build Coastguard Worker           continue;
96*8d67ca89SAndroid Build Coastguard Worker         } else if (c2 == '.' && (in_ptr[3] == '/' || in_ptr[3] == 0)) {
97*8d67ca89SAndroid Build Coastguard Worker           in_ptr += 3;
98*8d67ca89SAndroid Build Coastguard Worker           while (out_ptr > buf && *--out_ptr != '/') {
99*8d67ca89SAndroid Build Coastguard Worker           }
100*8d67ca89SAndroid Build Coastguard Worker           if (in_ptr[0] == 0) {
101*8d67ca89SAndroid Build Coastguard Worker             // retain '/' (or write the initial '/' for "/..")
102*8d67ca89SAndroid Build Coastguard Worker             *out_ptr++ = '/';
103*8d67ca89SAndroid Build Coastguard Worker           }
104*8d67ca89SAndroid Build Coastguard Worker           continue;
105*8d67ca89SAndroid Build Coastguard Worker         }
106*8d67ca89SAndroid Build Coastguard Worker       } else if (c1 == '/') {
107*8d67ca89SAndroid Build Coastguard Worker         ++in_ptr;
108*8d67ca89SAndroid Build Coastguard Worker         continue;
109*8d67ca89SAndroid Build Coastguard Worker       }
110*8d67ca89SAndroid Build Coastguard Worker     }
111*8d67ca89SAndroid Build Coastguard Worker     *out_ptr++ = *in_ptr++;
112*8d67ca89SAndroid Build Coastguard Worker   }
113*8d67ca89SAndroid Build Coastguard Worker 
114*8d67ca89SAndroid Build Coastguard Worker   *out_ptr = 0;
115*8d67ca89SAndroid Build Coastguard Worker   *normalized_path = buf;
116*8d67ca89SAndroid Build Coastguard Worker   return true;
117*8d67ca89SAndroid Build Coastguard Worker }
118*8d67ca89SAndroid Build Coastguard Worker 
file_is_in_dir(const std::string & file,const std::string & dir)119*8d67ca89SAndroid Build Coastguard Worker bool file_is_in_dir(const std::string& file, const std::string& dir) {
120*8d67ca89SAndroid Build Coastguard Worker   const char* needle = dir.c_str();
121*8d67ca89SAndroid Build Coastguard Worker   const char* haystack = file.c_str();
122*8d67ca89SAndroid Build Coastguard Worker   size_t needle_len = strlen(needle);
123*8d67ca89SAndroid Build Coastguard Worker 
124*8d67ca89SAndroid Build Coastguard Worker   return strncmp(haystack, needle, needle_len) == 0 &&
125*8d67ca89SAndroid Build Coastguard Worker          haystack[needle_len] == '/' &&
126*8d67ca89SAndroid Build Coastguard Worker          strchr(haystack + needle_len + 1, '/') == nullptr;
127*8d67ca89SAndroid Build Coastguard Worker }
128*8d67ca89SAndroid Build Coastguard Worker 
file_is_under_dir(const std::string & file,const std::string & dir)129*8d67ca89SAndroid Build Coastguard Worker bool file_is_under_dir(const std::string& file, const std::string& dir) {
130*8d67ca89SAndroid Build Coastguard Worker   const char* needle = dir.c_str();
131*8d67ca89SAndroid Build Coastguard Worker   const char* haystack = file.c_str();
132*8d67ca89SAndroid Build Coastguard Worker   size_t needle_len = strlen(needle);
133*8d67ca89SAndroid Build Coastguard Worker 
134*8d67ca89SAndroid Build Coastguard Worker   return strncmp(haystack, needle, needle_len) == 0 &&
135*8d67ca89SAndroid Build Coastguard Worker          haystack[needle_len] == '/';
136*8d67ca89SAndroid Build Coastguard Worker }
137*8d67ca89SAndroid Build Coastguard Worker 
138*8d67ca89SAndroid Build Coastguard Worker const char* const kZipFileSeparator = "!/";
139*8d67ca89SAndroid Build Coastguard Worker 
parse_zip_path(const char * input_path,std::string * zip_path,std::string * entry_path)140*8d67ca89SAndroid Build Coastguard Worker bool parse_zip_path(const char* input_path, std::string* zip_path, std::string* entry_path) {
141*8d67ca89SAndroid Build Coastguard Worker   std::string normalized_path;
142*8d67ca89SAndroid Build Coastguard Worker   if (!normalize_path(input_path, &normalized_path)) {
143*8d67ca89SAndroid Build Coastguard Worker     return false;
144*8d67ca89SAndroid Build Coastguard Worker   }
145*8d67ca89SAndroid Build Coastguard Worker 
146*8d67ca89SAndroid Build Coastguard Worker   const char* const path = normalized_path.c_str();
147*8d67ca89SAndroid Build Coastguard Worker   LD_DEBUG(any, "Trying zip file open from path \"%s\" -> normalized \"%s\"", input_path, path);
148*8d67ca89SAndroid Build Coastguard Worker 
149*8d67ca89SAndroid Build Coastguard Worker   // Treat an '!/' separator inside a path as the separator between the name
150*8d67ca89SAndroid Build Coastguard Worker   // of the zip file on disk and the subdirectory to search within it.
151*8d67ca89SAndroid Build Coastguard Worker   // For example, if path is "foo.zip!/bar/bas/x.so", then we search for
152*8d67ca89SAndroid Build Coastguard Worker   // "bar/bas/x.so" within "foo.zip".
153*8d67ca89SAndroid Build Coastguard Worker   const char* const separator = strstr(path, kZipFileSeparator);
154*8d67ca89SAndroid Build Coastguard Worker   if (separator == nullptr) {
155*8d67ca89SAndroid Build Coastguard Worker     return false;
156*8d67ca89SAndroid Build Coastguard Worker   }
157*8d67ca89SAndroid Build Coastguard Worker 
158*8d67ca89SAndroid Build Coastguard Worker   char buf[512];
159*8d67ca89SAndroid Build Coastguard Worker   if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) {
160*8d67ca89SAndroid Build Coastguard Worker     DL_WARN("ignoring very long library path: %s", path);
161*8d67ca89SAndroid Build Coastguard Worker     return false;
162*8d67ca89SAndroid Build Coastguard Worker   }
163*8d67ca89SAndroid Build Coastguard Worker 
164*8d67ca89SAndroid Build Coastguard Worker   buf[separator - path] = '\0';
165*8d67ca89SAndroid Build Coastguard Worker 
166*8d67ca89SAndroid Build Coastguard Worker   *zip_path = buf;
167*8d67ca89SAndroid Build Coastguard Worker   *entry_path = &buf[separator - path + 2];
168*8d67ca89SAndroid Build Coastguard Worker 
169*8d67ca89SAndroid Build Coastguard Worker   return true;
170*8d67ca89SAndroid Build Coastguard Worker }
171*8d67ca89SAndroid Build Coastguard Worker 
safe_add(off64_t * out,off64_t a,size_t b)172*8d67ca89SAndroid Build Coastguard Worker bool safe_add(off64_t* out, off64_t a, size_t b) {
173*8d67ca89SAndroid Build Coastguard Worker   CHECK(a >= 0);
174*8d67ca89SAndroid Build Coastguard Worker   if (static_cast<uint64_t>(INT64_MAX - a) < b) {
175*8d67ca89SAndroid Build Coastguard Worker     return false;
176*8d67ca89SAndroid Build Coastguard Worker   }
177*8d67ca89SAndroid Build Coastguard Worker 
178*8d67ca89SAndroid Build Coastguard Worker   *out = a + b;
179*8d67ca89SAndroid Build Coastguard Worker   return true;
180*8d67ca89SAndroid Build Coastguard Worker }
181*8d67ca89SAndroid Build Coastguard Worker 
split_path(const char * path,const char * delimiters,std::vector<std::string> * paths)182*8d67ca89SAndroid Build Coastguard Worker void split_path(const char* path, const char* delimiters,
183*8d67ca89SAndroid Build Coastguard Worker                 std::vector<std::string>* paths) {
184*8d67ca89SAndroid Build Coastguard Worker   if (path != nullptr && path[0] != 0) {
185*8d67ca89SAndroid Build Coastguard Worker     *paths = android::base::Split(path, delimiters);
186*8d67ca89SAndroid Build Coastguard Worker   }
187*8d67ca89SAndroid Build Coastguard Worker }
188*8d67ca89SAndroid Build Coastguard Worker 
resolve_paths(std::vector<std::string> & paths,std::vector<std::string> * resolved_paths)189*8d67ca89SAndroid Build Coastguard Worker void resolve_paths(std::vector<std::string>& paths,
190*8d67ca89SAndroid Build Coastguard Worker                    std::vector<std::string>* resolved_paths) {
191*8d67ca89SAndroid Build Coastguard Worker   resolved_paths->clear();
192*8d67ca89SAndroid Build Coastguard Worker   for (const auto& path : paths) {
193*8d67ca89SAndroid Build Coastguard Worker     // skip empty paths
194*8d67ca89SAndroid Build Coastguard Worker     if (path.empty()) {
195*8d67ca89SAndroid Build Coastguard Worker       continue;
196*8d67ca89SAndroid Build Coastguard Worker     }
197*8d67ca89SAndroid Build Coastguard Worker     std::string resolved = resolve_path(path);
198*8d67ca89SAndroid Build Coastguard Worker     if (!resolved.empty()) {
199*8d67ca89SAndroid Build Coastguard Worker       resolved_paths->push_back(std::move(resolved));
200*8d67ca89SAndroid Build Coastguard Worker     }
201*8d67ca89SAndroid Build Coastguard Worker   }
202*8d67ca89SAndroid Build Coastguard Worker }
203*8d67ca89SAndroid Build Coastguard Worker 
resolve_path(const std::string & path)204*8d67ca89SAndroid Build Coastguard Worker std::string resolve_path(const std::string& path) {
205*8d67ca89SAndroid Build Coastguard Worker   char resolved_path[PATH_MAX];
206*8d67ca89SAndroid Build Coastguard Worker   const char* original_path = path.c_str();
207*8d67ca89SAndroid Build Coastguard Worker   if (realpath(original_path, resolved_path) != nullptr) {
208*8d67ca89SAndroid Build Coastguard Worker     struct stat s;
209*8d67ca89SAndroid Build Coastguard Worker     if (stat(resolved_path, &s) == -1) {
210*8d67ca89SAndroid Build Coastguard Worker       DL_WARN("Warning: cannot stat file \"%s\": %m (ignoring)", resolved_path);
211*8d67ca89SAndroid Build Coastguard Worker       return "";
212*8d67ca89SAndroid Build Coastguard Worker     }
213*8d67ca89SAndroid Build Coastguard Worker     if (!S_ISDIR(s.st_mode)) {
214*8d67ca89SAndroid Build Coastguard Worker       DL_WARN("Warning: \"%s\" is not a directory (ignoring)", resolved_path);
215*8d67ca89SAndroid Build Coastguard Worker       return "";
216*8d67ca89SAndroid Build Coastguard Worker     }
217*8d67ca89SAndroid Build Coastguard Worker     return resolved_path;
218*8d67ca89SAndroid Build Coastguard Worker   } else {
219*8d67ca89SAndroid Build Coastguard Worker     std::string normalized_path;
220*8d67ca89SAndroid Build Coastguard Worker     if (!normalize_path(original_path, &normalized_path)) {
221*8d67ca89SAndroid Build Coastguard Worker       DL_WARN("Warning: unable to normalize \"%s\" (ignoring)", original_path);
222*8d67ca89SAndroid Build Coastguard Worker       return "";
223*8d67ca89SAndroid Build Coastguard Worker     }
224*8d67ca89SAndroid Build Coastguard Worker 
225*8d67ca89SAndroid Build Coastguard Worker     std::string zip_path;
226*8d67ca89SAndroid Build Coastguard Worker     std::string entry_path;
227*8d67ca89SAndroid Build Coastguard Worker     if (parse_zip_path(normalized_path.c_str(), &zip_path, &entry_path)) {
228*8d67ca89SAndroid Build Coastguard Worker       if (realpath(zip_path.c_str(), resolved_path) == nullptr) {
229*8d67ca89SAndroid Build Coastguard Worker         DL_WARN("Warning: unable to resolve \"%s\": %m (ignoring)", zip_path.c_str());
230*8d67ca89SAndroid Build Coastguard Worker         return "";
231*8d67ca89SAndroid Build Coastguard Worker       }
232*8d67ca89SAndroid Build Coastguard Worker 
233*8d67ca89SAndroid Build Coastguard Worker       return std::string(resolved_path) + kZipFileSeparator + entry_path;
234*8d67ca89SAndroid Build Coastguard Worker     } else {
235*8d67ca89SAndroid Build Coastguard Worker       struct stat s;
236*8d67ca89SAndroid Build Coastguard Worker       if (stat(normalized_path.c_str(), &s) == 0 && S_ISDIR(s.st_mode)) {
237*8d67ca89SAndroid Build Coastguard Worker         // Path is not a zip path, but an existing directory. Then add it
238*8d67ca89SAndroid Build Coastguard Worker         // although we failed to resolve it. b/119656753
239*8d67ca89SAndroid Build Coastguard Worker         return normalized_path;
240*8d67ca89SAndroid Build Coastguard Worker       }
241*8d67ca89SAndroid Build Coastguard Worker     }
242*8d67ca89SAndroid Build Coastguard Worker   }
243*8d67ca89SAndroid Build Coastguard Worker   return "";
244*8d67ca89SAndroid Build Coastguard Worker }
245*8d67ca89SAndroid Build Coastguard Worker 
is_first_stage_init()246*8d67ca89SAndroid Build Coastguard Worker bool is_first_stage_init() {
247*8d67ca89SAndroid Build Coastguard Worker   static bool ret = (getpid() == 1 && access("/proc/self/exe", F_OK) == -1);
248*8d67ca89SAndroid Build Coastguard Worker   return ret;
249*8d67ca89SAndroid Build Coastguard Worker }
250