Sync linker with internal branch
This change includes dlwarning implementation and
the compatibility greylist for apps targeting pre-N.
Change-Id: Ibf02a07cc58cbbb1a5aef4ac34558c5d43e4305f
Test: Run bionic-unit-tests --gtest_filter=dl*:Dl*
diff --git a/linker/Android.bp b/linker/Android.bp
index d7e97f0..a35eb45 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -18,6 +18,7 @@
"dlfcn.cpp",
"linker.cpp",
"linker_block_allocator.cpp",
+ "linker_dlwarning.cpp",
"linker_gdb_support.cpp",
"linker_libc_support.c",
"linker_logger.cpp",
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 110846d..c03ffa8 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -15,6 +15,7 @@
*/
#include "linker.h"
+#include "linker_dlwarning.h"
#include <pthread.h>
#include <stdio.h>
@@ -138,6 +139,11 @@
return get_application_target_sdk_version();
}
+void android_dlwarning(void* obj, void (*f)(void*, const char*)) {
+ ScopedPthreadMutexLocker locker(&g_dl_mutex);
+ get_dlwarning(obj, f);
+}
+
bool android_init_namespaces(const char* public_ns_sonames,
const char* anon_ns_library_path) {
ScopedPthreadMutexLocker locker(&g_dl_mutex);
@@ -199,11 +205,11 @@
// 00000000001 1111111112222222222 3333333333444444444455555555556666666666777 777777788888888889999999999
// 01234567890 1234567890123456789 0123456789012345678901234567890123456789012 345678901234567890123456789
"erate_phdr\0android_dlopen_ext\0android_set_application_target_sdk_version\0android_get_application_tar"
- // 0000000000111111 111122222222223333333333 4444444444555555555566666 6666677
- // 0123456789012345 678901234567890123456789 0123456789012345678901234 5678901
- "get_sdk_version\0android_init_namespaces\0android_create_namespace\0dlvsym\0"
+ // 0000000000111111 111122222222223333333333 4444444444555555555566666 6666677 777777778888888888
+ // 0123456789012345 678901234567890123456789 0123456789012345678901234 5678901 234567890123456789
+ "get_sdk_version\0android_init_namespaces\0android_create_namespace\0dlvsym\0android_dlwarning\0"
#if defined(__arm__)
- // 272
+ // 290
"dl_unwind_find_exidx\0"
#endif
;
@@ -228,8 +234,9 @@
ELFW(SYM_INITIALIZER)(216, &android_init_namespaces, 1),
ELFW(SYM_INITIALIZER)(240, &android_create_namespace, 1),
ELFW(SYM_INITIALIZER)(265, &dlvsym, 1),
+ ELFW(SYM_INITIALIZER)(272, &android_dlwarning, 1),
#if defined(__arm__)
- ELFW(SYM_INITIALIZER)(272, &dl_unwind_find_exidx, 1),
+ ELFW(SYM_INITIALIZER)(290, &dl_unwind_find_exidx, 1),
#endif
};
@@ -246,9 +253,9 @@
// Note that adding any new symbols here requires stubbing them out in libdl.
static unsigned g_libdl_buckets[1] = { 1 };
#if defined(__arm__)
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0 };
#else
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0 };
#endif
static uint8_t __libdl_info_buf[sizeof(soinfo)] __attribute__((aligned(8)));
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 71e3774..68b3a53 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -54,6 +54,7 @@
#include "linker_block_allocator.h"
#include "linker_gdb_support.h"
#include "linker_debug.h"
+#include "linker_dlwarning.h"
#include "linker_sleb128.h"
#include "linker_phdr.h"
#include "linker_relocs.h"
@@ -182,6 +183,73 @@
nullptr
};
+static bool is_system_library(const std::string& realpath) {
+ for (const auto& dir : g_default_namespace.get_default_library_paths()) {
+ if (file_is_in_dir(realpath, dir)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+#if defined(__LP64__)
+static const char* const kSystemLibDir = "/system/lib64";
+#else
+static const char* const kSystemLibDir = "/system/lib";
+#endif
+
+static std::string dirname(const char *path);
+
+// TODO(dimitry): The grey-list is a workaround for http://b/26394120 ---
+// gradually remove libraries from this list until it is gone.
+static bool is_greylisted(const char* name, const soinfo* needed_by) {
+ static const char* const kLibraryGreyList[] = {
+ "libandroid_runtime.so",
+ "libbinder.so",
+ "libcrypto.so",
+ "libcutils.so",
+ "libexpat.so",
+ "libgui.so",
+ "libmedia.so",
+ "libnativehelper.so",
+ "libskia.so",
+ "libssl.so",
+ "libstagefright.so",
+ "libsqlite.so",
+ "libui.so",
+ "libutils.so",
+ "libvorbisidec.so",
+ nullptr
+ };
+
+ // limit greylisting to apps targeting sdk version 23 and below
+ if (get_application_target_sdk_version() > 23) {
+ return false;
+ }
+
+ // if the library needed by a system library - implicitly assume it
+ // is greylisted
+
+ if (needed_by != nullptr && is_system_library(needed_by->get_realpath())) {
+ return true;
+ }
+
+ // if this is an absolute path - make sure it points to /system/lib(64)
+ if (name[0] == '/' && dirname(name) == kSystemLibDir) {
+ // and reduce the path to basename
+ name = basename(name);
+ }
+
+ for (size_t i = 0; kLibraryGreyList[i] != nullptr; ++i) {
+ if (strcmp(name, kLibraryGreyList[i]) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+// END OF WORKAROUND
+
static const ElfW(Versym) kVersymNotNeeded = 0;
static const ElfW(Versym) kVersymGlobal = 1;
@@ -491,7 +559,7 @@
std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
__libc_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
- PRINT("readlink('%s') failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
+ PRINT("readlink(\"%s\") failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
return false;
}
@@ -672,8 +740,8 @@
ELF_ST_BIND(s->st_info) == STB_WEAK) {
return s->st_shndx != SHN_UNDEF;
} else if (ELF_ST_BIND(s->st_info) != STB_LOCAL) {
- DL_WARN("unexpected ST_BIND value: %d for '%s' in '%s'",
- ELF_ST_BIND(s->st_info), si->get_string(s->st_name), si->get_realpath());
+ DL_WARN("unexpected ST_BIND value: %d for \"%s\" in \"%s\"",
+ ELF_ST_BIND(s->st_info), si->get_string(s->st_name), si->get_realpath());
}
return false;
@@ -1081,6 +1149,14 @@
extinfo_ = extinfo;
}
+ bool is_dt_needed() const {
+ return is_dt_needed_;
+ }
+
+ void set_dt_needed(bool is_dt_needed) {
+ is_dt_needed_ = is_dt_needed;
+ }
+
const ElfReader& get_elf_reader() const {
CHECK(si_ != nullptr);
return (*elf_readers_map_)[si_];
@@ -1120,7 +1196,8 @@
LoadTask(const char* name, soinfo* needed_by,
std::unordered_map<const soinfo*, ElfReader>* readers_map)
: name_(name), needed_by_(needed_by), si_(nullptr),
- fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map) {}
+ fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map),
+ is_dt_needed_(false) {}
~LoadTask() {
if (fd_ != -1 && close_fd_) {
@@ -1136,6 +1213,9 @@
bool close_fd_;
off64_t file_offset_;
std::unordered_map<const soinfo*, ElfReader>* elf_readers_map_;
+ // TODO(dimitry): needed by workaround for http://b/26394120 (the grey-list)
+ bool is_dt_needed_;
+ // END OF WORKAROUND
DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
};
@@ -1412,7 +1492,7 @@
}
const char* const path = normalized_path.c_str();
- TRACE("Trying zip file open from path '%s' -> normalized '%s'", input_path, path);
+ TRACE("Trying zip file open from path \"%s\" -> normalized \"%s\"", input_path, path);
// Treat an '!/' separator inside a path as the separator between the name
// of the zip file on disk and the subdirectory to search within it.
@@ -1558,6 +1638,14 @@
fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_default_library_paths(), realpath);
}
+ // TODO(dimitry): workaround for http://b/26394120 (the grey-list)
+ if (fd == -1 && ns != &g_default_namespace && is_greylisted(name, needed_by)) {
+ // try searching for it on default_namespace default_library_path
+ fd = open_library_on_paths(zip_archive_cache, name, file_offset,
+ g_default_namespace.get_default_library_paths(), realpath);
+ }
+ // END OF WORKAROUND
+
return fd;
}
@@ -1567,7 +1655,8 @@
if (get_application_target_sdk_version() <= 22) {
const char* bname = basename(dt_needed);
if (bname != dt_needed) {
- DL_WARN("'%s' library has invalid DT_NEEDED entry '%s'", sopath, dt_needed);
+ DL_WARN("library \"%s\" has invalid DT_NEEDED entry \"%s\"", sopath, dt_needed);
+ add_dlwarning(sopath, "invalid DT_NEEDED entry", dt_needed);
}
return bname;
@@ -1658,25 +1747,40 @@
}
if (!ns->is_accessible(realpath)) {
- // do not load libraries if they are not accessible for the specified namespace.
- const char* needed_or_dlopened_by = task->get_needed_by() == nullptr ?
- "(unknown)" :
- task->get_needed_by()->get_realpath();
+ // TODO(dimitry): workaround for http://b/26394120 - the grey-list
+ const soinfo* needed_by = task->is_dt_needed() ? task->get_needed_by() : nullptr;
+ if (is_greylisted(name, needed_by)) {
+ // print warning only if needed by non-system library
+ if (needed_by == nullptr || !is_system_library(needed_by->get_realpath())) {
+ const soinfo* needed_or_dlopened_by = task->get_needed_by();
+ const char* sopath = needed_or_dlopened_by == nullptr ? "(unknown)" :
+ needed_or_dlopened_by->get_realpath();
+ DL_WARN("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the namespace \"%s\""
+ " - the access is temporarily granted as a workaround for http://b/26394120, note that the access"
+ " will be removed in future releases of Android.",
+ name, realpath.c_str(), sopath, ns->get_name());
+ add_dlwarning(sopath, "unauthorized access to", name);
+ }
+ } else {
+ // do not load libraries if they are not accessible for the specified namespace.
+ const char* needed_or_dlopened_by = task->get_needed_by() == nullptr ?
+ "(unknown)" :
+ task->get_needed_by()->get_realpath();
- DL_ERR("library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"",
- name, needed_or_dlopened_by, ns->get_name());
+ DL_ERR("library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"",
+ name, needed_or_dlopened_by, ns->get_name());
- PRINT("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the"
- " namespace: [name=\"%s\", ld_library_paths=\"%s\", default_library_paths=\"%s\","
- " permitted_paths=\"%s\"]",
- name, realpath.c_str(),
- needed_or_dlopened_by,
- ns->get_name(),
- android::base::Join(ns->get_ld_library_paths(), ':').c_str(),
- android::base::Join(ns->get_default_library_paths(), ':').c_str(),
- android::base::Join(ns->get_permitted_paths(), ':').c_str());
-
- return false;
+ PRINT("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the"
+ " namespace: [name=\"%s\", ld_library_paths=\"%s\", default_library_paths=\"%s\","
+ " permitted_paths=\"%s\"]",
+ name, realpath.c_str(),
+ needed_or_dlopened_by,
+ ns->get_name(),
+ android::base::Join(ns->get_ld_library_paths(), ':').c_str(),
+ android::base::Join(ns->get_default_library_paths(), ':').c_str(),
+ android::base::Join(ns->get_permitted_paths(), ':').c_str());
+ return false;
+ }
}
soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
@@ -1822,7 +1926,7 @@
// Library might still be loaded, the accurate detection
// of this fact is done by load_library.
- TRACE("[ '%s' find_loaded_library_by_soname returned false (*candidate=%s@%p). Trying harder...]",
+ TRACE("[ \"%s\" find_loaded_library_by_soname failed (*candidate=%s@%p). Trying harder...]",
task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags)) {
@@ -1950,6 +2054,7 @@
bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
task->set_extinfo(is_dt_needed ? nullptr : extinfo);
+ task->set_dt_needed(is_dt_needed);
if(!find_library_internal(ns, task, &zip_archive_cache, &load_tasks, rtld_flags)) {
return false;
@@ -2079,7 +2184,7 @@
}
if (!root->can_unload()) {
- TRACE("not unloading '%s' - the binary is flagged with NODELETE", root->get_realpath());
+ TRACE("not unloading \"%s\" - the binary is flagged with NODELETE", root->get_realpath());
return;
}
@@ -2677,7 +2782,7 @@
const char* sym_name = nullptr;
ElfW(Addr) addend = get_addend(rel, reloc);
- DEBUG("Processing '%s' relocation at index %zd", get_realpath(), idx);
+ DEBUG("Processing \"%s\" relocation at index %zd", get_realpath(), idx);
if (type == R_GENERIC_NONE) {
continue;
}
@@ -3435,7 +3540,7 @@
/* We can't log anything until the linker is relocated */
bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
if (!relocating_linker) {
- INFO("[ Linking '%s' ]", get_realpath());
+ INFO("[ Linking \"%s\" ]", get_realpath());
DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
}
@@ -3859,6 +3964,7 @@
soname_ = basename(realpath_.c_str());
DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
get_realpath(), soname_);
+ // Don't call add_dlwarning because a missing DT_SONAME isn't important enough to show in the UI
}
return true;
}
@@ -3893,6 +3999,7 @@
// phdr_table_protect_segments() after all of them are applied.
DL_WARN("%s has text relocations. This is wasting memory and prevents "
"security hardening. Please fix.", get_realpath());
+ add_dlwarning(get_realpath(), "text relocations");
if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
DL_ERR("can't unprotect loadable segments for \"%s\": %s",
get_realpath(), strerror(errno));
@@ -4156,11 +4263,11 @@
if (!getauxval(AT_SECURE)) {
ldpath_env = getenv("LD_LIBRARY_PATH");
if (ldpath_env != nullptr) {
- INFO("[ LD_LIBRARY_PATH set to '%s' ]", ldpath_env);
+ INFO("[ LD_LIBRARY_PATH set to \"%s\" ]", ldpath_env);
}
ldpreload_env = getenv("LD_PRELOAD");
if (ldpreload_env != nullptr) {
- INFO("[ LD_PRELOAD set to '%s' ]", ldpreload_env);
+ INFO("[ LD_PRELOAD set to \"%s\" ]", ldpreload_env);
}
}
@@ -4319,7 +4426,7 @@
#endif
ElfW(Addr) entry = args.getauxval(AT_ENTRY);
- TRACE("[ Ready to execute '%s' @ %p ]", si->get_realpath(), reinterpret_cast<void*>(entry));
+ TRACE("[ Ready to execute \"%s\" @ %p ]", si->get_realpath(), reinterpret_cast<void*>(entry));
return entry;
}
diff --git a/linker/linker_dlwarning.cpp b/linker/linker_dlwarning.cpp
new file mode 100644
index 0000000..c53ad66
--- /dev/null
+++ b/linker/linker_dlwarning.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "linker_dlwarning.h"
+
+#include <strings.h>
+
+#include <string>
+
+static std::string current_msg;
+
+void add_dlwarning(const char* sopath, const char* message, const char* value) {
+ if (!current_msg.empty()) {
+ current_msg += '\n';
+ }
+
+ current_msg = current_msg + basename(sopath) + ": " + message;
+
+ if (value != nullptr) {
+ current_msg = current_msg + " \"" + value + "\"";
+ }
+}
+
+// Resets the current one (like dlerror but instead of
+// being thread-local it is process-local).
+void get_dlwarning(void* obj, void (*f)(void*, const char*)) {
+ if (current_msg.empty()) {
+ f(obj, nullptr);
+ } else {
+ std::string msg = current_msg;
+ current_msg.clear();
+ f(obj, msg.c_str());
+ }
+}
diff --git a/linker/linker_dlwarning.h b/linker/linker_dlwarning.h
new file mode 100644
index 0000000..0263c72
--- /dev/null
+++ b/linker/linker_dlwarning.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LINKER_DLWARNING_H
+#define __LINKER_DLWARNING_H
+
+void add_dlwarning(const char* sopath, const char* message, const char* value = nullptr);
+
+// Resets the current one (like dlerror but instead of
+// being thread-local it is process-local). The user_data
+// is used to avoid forcing user into saving the message
+// to a global variable.
+void get_dlwarning(void* user_data, void (*f)(void*, const char*));
+
+#endif /* __LINKER_DLWARNING_H */
diff --git a/linker/linker_mips.cpp b/linker/linker_mips.cpp
index 8520c17..02375c4 100644
--- a/linker/linker_mips.cpp
+++ b/linker/linker_mips.cpp
@@ -67,7 +67,7 @@
ElfW(Addr) sym_addr = 0;
const char* sym_name = nullptr;
- DEBUG("Processing '%s' relocation at index %zd", get_realpath(), idx);
+ DEBUG("Processing \"%s\" relocation at index %zd", get_realpath(), idx);
if (type == R_GENERIC_NONE) {
continue;
}
diff --git a/linker/linker_utils.cpp b/linker/linker_utils.cpp
index 1b0c4e4..fb070ee 100644
--- a/linker/linker_utils.cpp
+++ b/linker/linker_utils.cpp
@@ -20,7 +20,7 @@
bool normalize_path(const char* path, std::string* normalized_path) {
// Input should be an absolute path
if (path[0] != '/') {
- PRINT("normalize_path - invalid input: '%s', the input path should be absolute", path);
+ PRINT("normalize_path - invalid input: \"%s\", the input path should be absolute", path);
return false;
}
@@ -89,7 +89,7 @@
}
const char* const path = normalized_path.c_str();
- TRACE("Trying zip file open from path '%s' -> normalized '%s'", input_path, path);
+ TRACE("Trying zip file open from path \"%s\" -> normalized \"%s\"", input_path, path);
// Treat an '!/' separator inside a path as the separator between the name
// of the zip file on disk and the subdirectory to search within it.