• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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_config.h"
30 
31 #include "linker_globals.h"
32 #include "linker_debug.h"
33 #include "linker_utils.h"
34 
35 #include <android-base/file.h>
36 #include <android-base/strings.h>
37 
38 #include <private/ScopeGuard.h>
39 
40 #include <stdlib.h>
41 
42 #include <string>
43 #include <unordered_map>
44 
45 class ConfigParser {
46  public:
47   enum {
48     kProperty,
49     kSection,
50     kEndOfFile,
51     kError,
52   };
53 
ConfigParser(std::string && content)54   explicit ConfigParser(std::string&& content)
55       : content_(content), p_(0), lineno_(0), was_end_of_file_(false) {}
56 
57   /*
58    * Possible return values
59    * kProperty: name is set to property name and value is set to property value
60    * kSection: name is set to section name.
61    * kEndOfFile: reached end of file.
62    * kError: error_msg is set.
63    */
next_token(std::string * name,std::string * value,std::string * error_msg)64   int next_token(std::string* name, std::string* value, std::string* error_msg) {
65     std::string line;
66     while(NextLine(&line)) {
67       size_t found = line.find('#');
68       line = android::base::Trim(line.substr(0, found));
69 
70       if (line.empty()) {
71         continue;
72       }
73 
74       if (line[0] == '[' && line[line.size() - 1] == ']') {
75         *name = line.substr(1, line.size() - 2);
76         return kSection;
77       }
78 
79       found = line.find('=');
80       if (found == std::string::npos) {
81         *error_msg = std::string("invalid format: ") +
82                     line +
83                     ", expected \"name = property\" or \"[section]\"";
84         return kError;
85       }
86 
87       *name = android::base::Trim(line.substr(0, found));
88       *value = android::base::Trim(line.substr(found + 1));
89       return kProperty;
90     }
91 
92     // to avoid infinite cycles when programmer makes a mistake
93     CHECK(!was_end_of_file_);
94     was_end_of_file_ = true;
95     return kEndOfFile;
96   }
97 
lineno() const98   size_t lineno() const {
99     return lineno_;
100   }
101 
102  private:
NextLine(std::string * line)103   bool NextLine(std::string* line) {
104     if (p_ == std::string::npos) {
105       return false;
106     }
107 
108     size_t found = content_.find('\n', p_);
109     if (found != std::string::npos) {
110       *line = content_.substr(p_, found - p_);
111       p_ = found + 1;
112     } else {
113       *line = content_.substr(p_);
114       p_ = std::string::npos;
115     }
116 
117     lineno_++;
118     return true;
119   }
120 
121   std::string content_;
122   size_t p_;
123   size_t lineno_;
124   bool was_end_of_file_;
125 
126   DISALLOW_IMPLICIT_CONSTRUCTORS(ConfigParser);
127 };
128 
129 class PropertyValue {
130  public:
131   PropertyValue() = default;
132 
PropertyValue(std::string && value,size_t lineno)133   PropertyValue(std::string&& value, size_t lineno)
134     : value_(value), lineno_(lineno) {}
135 
value() const136   const std::string& value() const {
137     return value_;
138   }
139 
lineno() const140   size_t lineno() const {
141     return lineno_;
142   }
143 
144  private:
145   std::string value_;
146   size_t lineno_;
147 };
148 
create_error_msg(const char * file,size_t lineno,const std::string & msg)149 static std::string create_error_msg(const char* file,
150                                     size_t lineno,
151                                     const std::string& msg) {
152   char buf[1024];
153   __libc_format_buffer(buf, sizeof(buf), "%s:%zu: error: %s", file, lineno, msg.c_str());
154 
155   return std::string(buf);
156 }
157 
parse_config_file(const char * ld_config_file_path,const char * binary_realpath,std::unordered_map<std::string,PropertyValue> * properties,std::string * error_msg)158 static bool parse_config_file(const char* ld_config_file_path,
159                               const char* binary_realpath,
160                               std::unordered_map<std::string, PropertyValue>* properties,
161                               std::string* error_msg) {
162   std::string content;
163   if (!android::base::ReadFileToString(ld_config_file_path, &content)) {
164     if (errno != ENOENT) {
165       *error_msg = std::string("error reading file \"") +
166                    ld_config_file_path + "\": " + strerror(errno);
167     }
168     return false;
169   }
170 
171   ConfigParser cp(std::move(content));
172 
173   std::string section_name;
174 
175   while(true) {
176     std::string name;
177     std::string value;
178     std::string error;
179 
180     int result = cp.next_token(&name, &value, &error);
181     if (result == ConfigParser::kError) {
182       DL_WARN("error parsing %s:%zd: %s (ignoring this line)",
183               ld_config_file_path,
184               cp.lineno(),
185               error.c_str());
186       continue;
187     }
188 
189     if (result == ConfigParser::kSection || result == ConfigParser::kEndOfFile) {
190       return false;
191     }
192 
193     if (result == ConfigParser::kProperty) {
194       if (!android::base::StartsWith(name, "dir.")) {
195         DL_WARN("error parsing %s:%zd: unexpected property name \"%s\", "
196                 "expected format dir.<section_name> (ignoring this line)",
197                 ld_config_file_path,
198                 cp.lineno(),
199                 name.c_str());
200         continue;
201       }
202 
203       // remove trailing '/'
204       while (value[value.size() - 1] == '/') {
205         value = value.substr(0, value.size() - 1);
206       }
207 
208       if (value.empty()) {
209         DL_WARN("error parsing %s:%zd: property value is empty (ignoring this line)",
210                 ld_config_file_path,
211                 cp.lineno());
212         continue;
213       }
214 
215       if (file_is_under_dir(binary_realpath, value)) {
216         section_name = name.substr(4);
217         break;
218       }
219     }
220   }
221 
222   // skip everything until we meet a correct section
223   while (true) {
224     std::string name;
225     std::string value;
226     std::string error;
227 
228     int result = cp.next_token(&name, &value, &error);
229 
230     if (result == ConfigParser::kSection && name == section_name) {
231       break;
232     }
233 
234     if (result == ConfigParser::kEndOfFile) {
235       *error_msg = create_error_msg(ld_config_file_path,
236                                     cp.lineno(),
237                                     std::string("section \"") + section_name + "\" not found");
238       return false;
239     }
240   }
241 
242   // found the section - parse it
243   while (true) {
244     std::string name;
245     std::string value;
246     std::string error;
247 
248     int result = cp.next_token(&name, &value, &error);
249 
250     if (result == ConfigParser::kEndOfFile || result == ConfigParser::kSection) {
251       break;
252     }
253 
254     if (result == ConfigParser::kProperty) {
255       if (properties->find(name) != properties->end()) {
256         DL_WARN("%s:%zd: warning: property \"%s\" redefinition",
257                 ld_config_file_path,
258                 cp.lineno(),
259                 name.c_str());
260       }
261 
262       (*properties)[name] = PropertyValue(std::move(value), cp.lineno());
263     }
264 
265     if (result == ConfigParser::kError) {
266       DL_WARN("error parsing %s:%zd: %s (ignoring this line)",
267               ld_config_file_path,
268               cp.lineno(),
269               error.c_str());
270       continue;
271     }
272   }
273 
274   return true;
275 }
276 
277 static Config g_config;
278 
279 static constexpr const char* kDefaultConfigName = "default";
280 static constexpr const char* kPropertyAdditionalNamespaces = "additional.namespaces";
281 #if defined(__LP64__)
282 static constexpr const char* kLibParamValue = "lib64";
283 #else
284 static constexpr const char* kLibParamValue = "lib";
285 #endif
286 
287 class Properties {
288  public:
Properties(std::unordered_map<std::string,PropertyValue> && properties)289   explicit Properties(std::unordered_map<std::string, PropertyValue>&& properties)
290       : properties_(properties), target_sdk_version_(__ANDROID_API__) {}
291 
get_strings(const std::string & name,size_t * lineno=nullptr) const292   std::vector<std::string> get_strings(const std::string& name, size_t* lineno = nullptr) const {
293     auto it = find_property(name, lineno);
294     if (it == properties_.end()) {
295       // return empty vector
296       return std::vector<std::string>();
297     }
298 
299     std::vector<std::string> strings = android::base::Split(it->second.value(), ",");
300 
301     for (size_t i = 0; i < strings.size(); ++i) {
302       strings[i] = android::base::Trim(strings[i]);
303     }
304 
305     return strings;
306   }
307 
get_bool(const std::string & name,size_t * lineno=nullptr) const308   bool get_bool(const std::string& name, size_t* lineno = nullptr) const {
309     auto it = find_property(name, lineno);
310     if (it == properties_.end()) {
311       return false;
312     }
313 
314     return it->second.value() == "true";
315   }
316 
get_string(const std::string & name,size_t * lineno=nullptr) const317   std::string get_string(const std::string& name, size_t* lineno = nullptr) const {
318     auto it = find_property(name, lineno);
319     return (it == properties_.end()) ? "" : it->second.value();
320   }
321 
get_paths(const std::string & name,size_t * lineno=nullptr)322   std::vector<std::string> get_paths(const std::string& name, size_t* lineno = nullptr) {
323     std::string paths_str = get_string(name, lineno);
324 
325     std::vector<std::string> paths;
326     split_path(paths_str.c_str(), ":", &paths);
327 
328     std::vector<std::pair<std::string, std::string>> params;
329     params.push_back({ "LIB", kLibParamValue });
330     if (target_sdk_version_ != 0) {
331       char buf[16];
332       __libc_format_buffer(buf, sizeof(buf), "%d", target_sdk_version_);
333       params.push_back({ "SDK_VER", buf });
334     }
335 
336     for (auto&& path : paths) {
337       format_string(&path, params);
338     }
339 
340     std::vector<std::string> resolved_paths;
341 
342     // do not remove paths that do not exist
343     resolve_paths(paths, &resolved_paths);
344 
345     return resolved_paths;
346   }
347 
set_target_sdk_version(int target_sdk_version)348   void set_target_sdk_version(int target_sdk_version) {
349     target_sdk_version_ = target_sdk_version;
350   }
351 
352  private:
353   std::unordered_map<std::string, PropertyValue>::const_iterator
find_property(const std::string & name,size_t * lineno) const354   find_property(const std::string& name, size_t* lineno) const {
355     auto it = properties_.find(name);
356     if (it != properties_.end() && lineno != nullptr) {
357       *lineno = it->second.lineno();
358     }
359 
360     return it;
361   }
362   std::unordered_map<std::string, PropertyValue> properties_;
363   int target_sdk_version_;
364 
365   DISALLOW_IMPLICIT_CONSTRUCTORS(Properties);
366 };
367 
read_binary_config(const char * ld_config_file_path,const char * binary_realpath,bool is_asan,const Config ** config,std::string * error_msg)368 bool Config::read_binary_config(const char* ld_config_file_path,
369                                       const char* binary_realpath,
370                                       bool is_asan,
371                                       const Config** config,
372                                       std::string* error_msg) {
373   // TODO(b/38114603) Currently, multiple namespaces does not support ASAN mode
374   // where some symbols should be intercepted via LD_PRELOAD; LD_PRELOADed libs
375   // are not being preloaded into the linked namespaces other than the default
376   // namespace. Until we fix the problem, we temporarily disable ld.config.txt
377   // in ASAN mode.
378   if (is_asan) {
379     return false;
380   }
381 
382   g_config.clear();
383 
384   std::unordered_map<std::string, PropertyValue> property_map;
385   if (!parse_config_file(ld_config_file_path, binary_realpath, &property_map, error_msg)) {
386     return false;
387   }
388 
389   Properties properties(std::move(property_map));
390 
391   auto failure_guard = make_scope_guard([] {
392     g_config.clear();
393   });
394 
395   std::unordered_map<std::string, NamespaceConfig*> namespace_configs;
396 
397   namespace_configs[kDefaultConfigName] = g_config.create_namespace_config(kDefaultConfigName);
398 
399   std::vector<std::string> additional_namespaces = properties.get_strings(kPropertyAdditionalNamespaces);
400   for (const auto& name : additional_namespaces) {
401     namespace_configs[name] = g_config.create_namespace_config(name);
402   }
403 
404   bool versioning_enabled = properties.get_bool("enable.target.sdk.version");
405   int target_sdk_version = __ANDROID_API__;
406   if (versioning_enabled) {
407     std::string version_file = dirname(binary_realpath) + "/.version";
408     std::string content;
409     if (!android::base::ReadFileToString(version_file, &content)) {
410       if (errno != ENOENT) {
411         *error_msg = std::string("error reading version file \"") +
412                      version_file + "\": " + strerror(errno);
413         return false;
414       }
415     } else {
416       content = android::base::Trim(content);
417       errno = 0;
418       char* end = nullptr;
419       const char* content_str = content.c_str();
420       int result = strtol(content_str, &end, 10);
421       if (errno == 0 && *end == '\0' && result > 0) {
422         target_sdk_version = result;
423         properties.set_target_sdk_version(target_sdk_version);
424       } else {
425         *error_msg = std::string("invalid version \"") + version_file + "\": \"" + content +"\"";
426         return false;
427       }
428     }
429   }
430 
431   g_config.set_target_sdk_version(target_sdk_version);
432 
433   for (auto ns_config_it : namespace_configs) {
434     auto& name = ns_config_it.first;
435     NamespaceConfig* ns_config = ns_config_it.second;
436 
437     std::string property_name_prefix = std::string("namespace.") + name;
438 
439     size_t lineno = 0;
440     std::vector<std::string> linked_namespaces =
441         properties.get_strings(property_name_prefix + ".links", &lineno);
442 
443     for (const auto& linked_ns_name : linked_namespaces) {
444       if (namespace_configs.find(linked_ns_name) == namespace_configs.end()) {
445         *error_msg = create_error_msg(ld_config_file_path,
446                                       lineno,
447                                       std::string("undefined namespace: ") + linked_ns_name);
448         return false;
449       }
450 
451       std::string shared_libs = properties.get_string(property_name_prefix +
452                                                       ".link." +
453                                                       linked_ns_name +
454                                                       ".shared_libs", &lineno);
455 
456       if (shared_libs.empty()) {
457         *error_msg = create_error_msg(ld_config_file_path,
458                                       lineno,
459                                       std::string("list of shared_libs for ") +
460                                       name +
461                                       "->" +
462                                       linked_ns_name +
463                                       " link is not specified or is empty.");
464         return false;
465       }
466 
467       ns_config->add_namespace_link(linked_ns_name, shared_libs);
468     }
469 
470     ns_config->set_isolated(properties.get_bool(property_name_prefix + ".isolated"));
471     ns_config->set_visible(properties.get_bool(property_name_prefix + ".visible"));
472 
473     // these are affected by is_asan flag
474     if (is_asan) {
475       property_name_prefix += ".asan";
476     }
477 
478     ns_config->set_search_paths(properties.get_paths(property_name_prefix + ".search.paths"));
479     ns_config->set_permitted_paths(properties.get_paths(property_name_prefix + ".permitted.paths"));
480   }
481 
482   failure_guard.disable();
483   *config = &g_config;
484   return true;
485 }
486 
create_namespace_config(const std::string & name)487 NamespaceConfig* Config::create_namespace_config(const std::string& name) {
488   namespace_configs_.push_back(std::unique_ptr<NamespaceConfig>(new NamespaceConfig(name)));
489   NamespaceConfig* ns_config_ptr = namespace_configs_.back().get();
490   namespace_configs_map_[name] = ns_config_ptr;
491   return ns_config_ptr;
492 }
493 
clear()494 void Config::clear() {
495   namespace_configs_.clear();
496   namespace_configs_map_.clear();
497 }
498