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