• 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/properties.h>
37 #include <android-base/scopeguard.h>
38 #include <android-base/strings.h>
39 
40 #include <async_safe/log.h>
41 
42 #include <stdlib.h>
43 
44 #include <string>
45 #include <unordered_map>
46 
47 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
48 #include <sys/_system_properties.h>
49 
50 class ConfigParser {
51  public:
52   enum {
53     kPropertyAssign,
54     kPropertyAppend,
55     kSection,
56     kEndOfFile,
57     kError,
58   };
59 
ConfigParser(std::string && content)60   explicit ConfigParser(std::string&& content)
61       : content_(content), p_(0), lineno_(0), was_end_of_file_(false) {}
62 
63   /*
64    * Possible return values
65    * kPropertyAssign: name is set to property name and value is set to property value
66    * kPropertyAppend: same as kPropertyAssign, but the value should be appended
67    * kSection: name is set to section name.
68    * kEndOfFile: reached end of file.
69    * kError: error_msg is set.
70    */
next_token(std::string * name,std::string * value,std::string * error_msg)71   int next_token(std::string* name, std::string* value, std::string* error_msg) {
72     std::string line;
73     while(NextLine(&line)) {
74       size_t found = line.find('#');
75       line = android::base::Trim(line.substr(0, found));
76 
77       if (line.empty()) {
78         continue;
79       }
80 
81       if (line[0] == '[' && line[line.size() - 1] == ']') {
82         *name = line.substr(1, line.size() - 2);
83         return kSection;
84       }
85 
86       size_t found_assign = line.find('=');
87       size_t found_append = line.find("+=");
88       if (found_assign != std::string::npos && found_append == std::string::npos) {
89         *name = android::base::Trim(line.substr(0, found_assign));
90         *value = android::base::Trim(line.substr(found_assign + 1));
91         return kPropertyAssign;
92       }
93 
94       if (found_append != std::string::npos) {
95         *name = android::base::Trim(line.substr(0, found_append));
96         *value = android::base::Trim(line.substr(found_append + 2));
97         return kPropertyAppend;
98       }
99 
100       *error_msg = std::string("invalid format: ") +
101                    line +
102                    ", expected \"name = property\", \"name += property\", or \"[section]\"";
103       return kError;
104     }
105 
106     // to avoid infinite cycles when programmer makes a mistake
107     CHECK(!was_end_of_file_);
108     was_end_of_file_ = true;
109     return kEndOfFile;
110   }
111 
lineno() const112   size_t lineno() const {
113     return lineno_;
114   }
115 
116  private:
NextLine(std::string * line)117   bool NextLine(std::string* line) {
118     if (p_ == std::string::npos) {
119       return false;
120     }
121 
122     size_t found = content_.find('\n', p_);
123     if (found != std::string::npos) {
124       *line = content_.substr(p_, found - p_);
125       p_ = found + 1;
126     } else {
127       *line = content_.substr(p_);
128       p_ = std::string::npos;
129     }
130 
131     lineno_++;
132     return true;
133   }
134 
135   std::string content_;
136   size_t p_;
137   size_t lineno_;
138   bool was_end_of_file_;
139 
140   DISALLOW_IMPLICIT_CONSTRUCTORS(ConfigParser);
141 };
142 
143 class PropertyValue {
144  public:
145   PropertyValue() = default;
146 
PropertyValue(std::string && value,size_t lineno)147   PropertyValue(std::string&& value, size_t lineno)
148     : value_(value), lineno_(lineno) {}
149 
value() const150   const std::string& value() const {
151     return value_;
152   }
153 
append_value(std::string && value)154   void append_value(std::string&& value) {
155     value_ = value_ + value;
156     // lineno isn't updated as we might have cases like this:
157     // property.x = blah
158     // property.y = blah
159     // property.x += blah
160   }
161 
lineno() const162   size_t lineno() const {
163     return lineno_;
164   }
165 
166  private:
167   std::string value_;
168   size_t lineno_;
169 };
170 
create_error_msg(const char * file,size_t lineno,const std::string & msg)171 static std::string create_error_msg(const char* file,
172                                     size_t lineno,
173                                     const std::string& msg) {
174   char buf[1024];
175   async_safe_format_buffer(buf, sizeof(buf), "%s:%zu: error: %s", file, lineno, msg.c_str());
176 
177   return std::string(buf);
178 }
179 
parse_config_file(const char * ld_config_file_path,const char * binary_realpath,std::unordered_map<std::string,PropertyValue> * properties,std::string * error_msg)180 static bool parse_config_file(const char* ld_config_file_path,
181                               const char* binary_realpath,
182                               std::unordered_map<std::string, PropertyValue>* properties,
183                               std::string* error_msg) {
184   std::string content;
185   if (!android::base::ReadFileToString(ld_config_file_path, &content)) {
186     if (errno != ENOENT) {
187       *error_msg = std::string("error reading file \"") +
188                    ld_config_file_path + "\": " + strerror(errno);
189     }
190     return false;
191   }
192 
193   ConfigParser cp(std::move(content));
194 
195   std::string section_name;
196 
197   while (true) {
198     std::string name;
199     std::string value;
200     std::string error;
201 
202     int result = cp.next_token(&name, &value, &error);
203     if (result == ConfigParser::kError) {
204       DL_WARN("%s:%zd: warning: couldn't parse %s (ignoring this line)",
205               ld_config_file_path,
206               cp.lineno(),
207               error.c_str());
208       continue;
209     }
210 
211     if (result == ConfigParser::kSection || result == ConfigParser::kEndOfFile) {
212       return false;
213     }
214 
215     if (result == ConfigParser::kPropertyAssign) {
216       if (!android::base::StartsWith(name, "dir.")) {
217         DL_WARN("%s:%zd: warning: unexpected property name \"%s\", "
218                 "expected format dir.<section_name> (ignoring this line)",
219                 ld_config_file_path,
220                 cp.lineno(),
221                 name.c_str());
222         continue;
223       }
224 
225       // remove trailing '/'
226       while (value[value.size() - 1] == '/') {
227         value = value.substr(0, value.size() - 1);
228       }
229 
230       if (value.empty()) {
231         DL_WARN("%s:%zd: warning: property value is empty (ignoring this line)",
232                 ld_config_file_path,
233                 cp.lineno());
234         continue;
235       }
236 
237       if (file_is_under_dir(binary_realpath, value)) {
238         section_name = name.substr(4);
239         break;
240       }
241     }
242   }
243 
244   // skip everything until we meet a correct section
245   while (true) {
246     std::string name;
247     std::string value;
248     std::string error;
249 
250     int result = cp.next_token(&name, &value, &error);
251 
252     if (result == ConfigParser::kSection && name == section_name) {
253       break;
254     }
255 
256     if (result == ConfigParser::kEndOfFile) {
257       *error_msg = create_error_msg(ld_config_file_path,
258                                     cp.lineno(),
259                                     std::string("section \"") + section_name + "\" not found");
260       return false;
261     }
262   }
263 
264   // found the section - parse it
265   while (true) {
266     std::string name;
267     std::string value;
268     std::string error;
269 
270     int result = cp.next_token(&name, &value, &error);
271 
272     if (result == ConfigParser::kEndOfFile || result == ConfigParser::kSection) {
273       break;
274     }
275 
276     if (result == ConfigParser::kPropertyAssign) {
277       if (properties->find(name) != properties->end()) {
278         DL_WARN("%s:%zd: warning: redefining property \"%s\" (overriding previous value)",
279                 ld_config_file_path,
280                 cp.lineno(),
281                 name.c_str());
282       }
283 
284       (*properties)[name] = PropertyValue(std::move(value), cp.lineno());
285     } else if (result == ConfigParser::kPropertyAppend) {
286       if (properties->find(name) == properties->end()) {
287         DL_WARN("%s:%zd: warning: appending to undefined property \"%s\" (treating as assignment)",
288                 ld_config_file_path,
289                 cp.lineno(),
290                 name.c_str());
291         (*properties)[name] = PropertyValue(std::move(value), cp.lineno());
292       } else {
293         if (android::base::EndsWith(name, ".links") ||
294             android::base::EndsWith(name, ".namespaces")) {
295           value = "," + value;
296           (*properties)[name].append_value(std::move(value));
297         } else if (android::base::EndsWith(name, ".paths") ||
298                    android::base::EndsWith(name, ".shared_libs")) {
299           value = ":" + value;
300           (*properties)[name].append_value(std::move(value));
301         } else {
302           DL_WARN("%s:%zd: warning: += isn't allowed for property \"%s\" (ignoring)",
303                   ld_config_file_path,
304                   cp.lineno(),
305                   name.c_str());
306         }
307       }
308     }
309 
310     if (result == ConfigParser::kError) {
311       DL_WARN("%s:%zd: warning: couldn't parse %s (ignoring this line)",
312               ld_config_file_path,
313               cp.lineno(),
314               error.c_str());
315       continue;
316     }
317   }
318 
319   return true;
320 }
321 
322 static Config g_config;
323 
324 static constexpr const char* kDefaultConfigName = "default";
325 static constexpr const char* kPropertyAdditionalNamespaces = "additional.namespaces";
326 #if defined(__LP64__)
327 static constexpr const char* kLibParamValue = "lib64";
328 #else
329 static constexpr const char* kLibParamValue = "lib";
330 #endif
331 
332 class Properties {
333  public:
Properties(std::unordered_map<std::string,PropertyValue> && properties)334   explicit Properties(std::unordered_map<std::string, PropertyValue>&& properties)
335       : properties_(properties), target_sdk_version_(__ANDROID_API__) {}
336 
get_strings(const std::string & name,size_t * lineno=nullptr) const337   std::vector<std::string> get_strings(const std::string& name, size_t* lineno = nullptr) const {
338     auto it = find_property(name, lineno);
339     if (it == properties_.end()) {
340       // return empty vector
341       return std::vector<std::string>();
342     }
343 
344     std::vector<std::string> strings = android::base::Split(it->second.value(), ",");
345 
346     for (size_t i = 0; i < strings.size(); ++i) {
347       strings[i] = android::base::Trim(strings[i]);
348     }
349 
350     return strings;
351   }
352 
get_bool(const std::string & name,size_t * lineno=nullptr) const353   bool get_bool(const std::string& name, size_t* lineno = nullptr) const {
354     auto it = find_property(name, lineno);
355     if (it == properties_.end()) {
356       return false;
357     }
358 
359     return it->second.value() == "true";
360   }
361 
get_string(const std::string & name,size_t * lineno=nullptr) const362   std::string get_string(const std::string& name, size_t* lineno = nullptr) const {
363     auto it = find_property(name, lineno);
364     return (it == properties_.end()) ? "" : it->second.value();
365   }
366 
get_paths(const std::string & name,bool resolve,size_t * lineno=nullptr)367   std::vector<std::string> get_paths(const std::string& name, bool resolve, size_t* lineno = nullptr) {
368     std::string paths_str = get_string(name, lineno);
369 
370     std::vector<std::string> paths;
371     split_path(paths_str.c_str(), ":", &paths);
372 
373     std::vector<std::pair<std::string, std::string>> params;
374     params.push_back({ "LIB", kLibParamValue });
375     if (target_sdk_version_ != 0) {
376       char buf[16];
377       async_safe_format_buffer(buf, sizeof(buf), "%d", target_sdk_version_);
378       params.push_back({ "SDK_VER", buf });
379     }
380 
381     static std::string vndk = Config::get_vndk_version_string('-');
382     params.push_back({ "VNDK_VER", vndk });
383 
384     for (auto&& path : paths) {
385       format_string(&path, params);
386     }
387 
388     if (resolve) {
389       std::vector<std::string> resolved_paths;
390 
391       // do not remove paths that do not exist
392       resolve_paths(paths, &resolved_paths);
393 
394       return resolved_paths;
395     } else {
396       return paths;
397     }
398   }
399 
set_target_sdk_version(int target_sdk_version)400   void set_target_sdk_version(int target_sdk_version) {
401     target_sdk_version_ = target_sdk_version;
402   }
403 
404  private:
405   std::unordered_map<std::string, PropertyValue>::const_iterator
find_property(const std::string & name,size_t * lineno) const406   find_property(const std::string& name, size_t* lineno) const {
407     auto it = properties_.find(name);
408     if (it != properties_.end() && lineno != nullptr) {
409       *lineno = it->second.lineno();
410     }
411 
412     return it;
413   }
414   std::unordered_map<std::string, PropertyValue> properties_;
415   int target_sdk_version_;
416 
417   DISALLOW_IMPLICIT_CONSTRUCTORS(Properties);
418 };
419 
read_binary_config(const char * ld_config_file_path,const char * binary_realpath,bool is_asan,const Config ** config,std::string * error_msg)420 bool Config::read_binary_config(const char* ld_config_file_path,
421                                       const char* binary_realpath,
422                                       bool is_asan,
423                                       const Config** config,
424                                       std::string* error_msg) {
425   g_config.clear();
426 
427   std::unordered_map<std::string, PropertyValue> property_map;
428   if (!parse_config_file(ld_config_file_path, binary_realpath, &property_map, error_msg)) {
429     return false;
430   }
431 
432   Properties properties(std::move(property_map));
433 
434   auto failure_guard = android::base::make_scope_guard([] { g_config.clear(); });
435 
436   std::unordered_map<std::string, NamespaceConfig*> namespace_configs;
437 
438   namespace_configs[kDefaultConfigName] = g_config.create_namespace_config(kDefaultConfigName);
439 
440   std::vector<std::string> additional_namespaces = properties.get_strings(kPropertyAdditionalNamespaces);
441   for (const auto& name : additional_namespaces) {
442     namespace_configs[name] = g_config.create_namespace_config(name);
443   }
444 
445   bool versioning_enabled = properties.get_bool("enable.target.sdk.version");
446   int target_sdk_version = __ANDROID_API__;
447   if (versioning_enabled) {
448     std::string version_file = dirname(binary_realpath) + "/.version";
449     std::string content;
450     if (!android::base::ReadFileToString(version_file, &content)) {
451       if (errno != ENOENT) {
452         *error_msg = std::string("error reading version file \"") +
453                      version_file + "\": " + strerror(errno);
454         return false;
455       }
456     } else {
457       content = android::base::Trim(content);
458       errno = 0;
459       char* end = nullptr;
460       const char* content_str = content.c_str();
461       int result = strtol(content_str, &end, 10);
462       if (errno == 0 && *end == '\0' && result > 0) {
463         target_sdk_version = result;
464         properties.set_target_sdk_version(target_sdk_version);
465       } else {
466         *error_msg = std::string("invalid version \"") + version_file + "\": \"" + content +"\"";
467         return false;
468       }
469     }
470   }
471 
472   g_config.set_target_sdk_version(target_sdk_version);
473 
474   for (auto ns_config_it : namespace_configs) {
475     auto& name = ns_config_it.first;
476     NamespaceConfig* ns_config = ns_config_it.second;
477 
478     std::string property_name_prefix = std::string("namespace.") + name;
479 
480     size_t lineno = 0;
481     std::vector<std::string> linked_namespaces =
482         properties.get_strings(property_name_prefix + ".links", &lineno);
483 
484     for (const auto& linked_ns_name : linked_namespaces) {
485       if (namespace_configs.find(linked_ns_name) == namespace_configs.end()) {
486         *error_msg = create_error_msg(ld_config_file_path,
487                                       lineno,
488                                       std::string("undefined namespace: ") + linked_ns_name);
489         return false;
490       }
491 
492       bool allow_all_shared_libs = properties.get_bool(property_name_prefix + ".link." +
493                                                        linked_ns_name + ".allow_all_shared_libs");
494 
495       std::string shared_libs = properties.get_string(property_name_prefix +
496                                                       ".link." +
497                                                       linked_ns_name +
498                                                       ".shared_libs", &lineno);
499 
500       if (!allow_all_shared_libs && shared_libs.empty()) {
501         *error_msg = create_error_msg(ld_config_file_path,
502                                       lineno,
503                                       std::string("list of shared_libs for ") +
504                                       name +
505                                       "->" +
506                                       linked_ns_name +
507                                       " link is not specified or is empty.");
508         return false;
509       }
510 
511       if (allow_all_shared_libs && !shared_libs.empty()) {
512         *error_msg = create_error_msg(ld_config_file_path, lineno,
513                                       std::string("both shared_libs and allow_all_shared_libs "
514                                                   "are set for ") +
515                                       name + "->" + linked_ns_name + " link.");
516         return false;
517       }
518 
519       ns_config->add_namespace_link(linked_ns_name, shared_libs, allow_all_shared_libs);
520     }
521 
522     ns_config->set_isolated(properties.get_bool(property_name_prefix + ".isolated"));
523     ns_config->set_visible(properties.get_bool(property_name_prefix + ".visible"));
524 
525     // these are affected by is_asan flag
526     if (is_asan) {
527       property_name_prefix += ".asan";
528     }
529 
530     // search paths are resolved (canonicalized). This is required mainly for
531     // the case when /vendor is a symlink to /system/vendor, which is true for
532     // non Treble-ized legacy devices.
533     ns_config->set_search_paths(properties.get_paths(property_name_prefix + ".search.paths", true));
534 
535     // However, for permitted paths, we are not required to resolve the paths
536     // since they are only set for isolated namespaces, which implies the device
537     // is Treble-ized (= /vendor is not a symlink to /system/vendor).
538     // In fact, the resolving is causing an unexpected side effect of selinux
539     // denials on some executables which are not allowed to access some of the
540     // permitted paths.
541     ns_config->set_permitted_paths(properties.get_paths(property_name_prefix + ".permitted.paths", false));
542   }
543 
544   failure_guard.Disable();
545   *config = &g_config;
546   return true;
547 }
548 
get_vndk_version_string(const char delimiter)549 std::string Config::get_vndk_version_string(const char delimiter) {
550   std::string version = android::base::GetProperty("ro.vndk.version", "");
551   if (version != "" && version != "current") {
552     //add the delimiter char in front of the string and return it.
553     return version.insert(0, 1, delimiter);
554   }
555   return "";
556 }
557 
create_namespace_config(const std::string & name)558 NamespaceConfig* Config::create_namespace_config(const std::string& name) {
559   namespace_configs_.push_back(std::unique_ptr<NamespaceConfig>(new NamespaceConfig(name)));
560   NamespaceConfig* ns_config_ptr = namespace_configs_.back().get();
561   namespace_configs_map_[name] = ns_config_ptr;
562   return ns_config_ptr;
563 }
564 
clear()565 void Config::clear() {
566   namespace_configs_.clear();
567   namespace_configs_map_.clear();
568 }
569