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