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