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