Commit c9bffc92 authored by David 'Digit' Turner's avatar David 'Digit' Turner Committed by Commit Bot

android: crazy_linker: Load system libraries with system linker.

Add a way to detect system libraries, and fallback to the system
linker whenever they need to be loaded. This is needed because

Chrome probes a few system libraries like libEGL.so to check that
certain GL-related symbols are available. It does that by using
dlopen() + multiple dlsym() + dlclose(), which end up being
performed through the crazy linker wrappers (e.g. WrapDlopen()).

When enabling the crazy linker, it seems this happens everytime
the user navigates to a different web page!

Due to the way the code works before this CL, this ended up
loading said system libraries with the crazy linker, which
is problematic because:

- If the system library was already loaded in the Zygote,
  this would create a duplicate copy, loaded at a different
  address. Also this is much slower than simply incrementing
  the reference-count of an existing system library entry.

- This creates pending RDebug-related tasks, which happen to
  be racy, and the source of runtime crashes.

By detecting system libraries properly, the code can now
always fall back to use the system linker to load them,
avoiding these two problems entirely.

In particular, it is hoped that this will decrease the
amount of runtime crashes described in 831403.

BUG=843987,831403

R=pasko@chromium.org, agrieve@chromium.org, rcmilroy@chromium.org

Change-Id: I86d89d6a812b778cf962aa5da028449b2b79f1fa
Reviewed-on: https://chromium-review.googlesource.com/1236656Reviewed-by: default avataragrieve <agrieve@chromium.org>
Commit-Queue: David Turner <digit@chromium.org>
Cr-Commit-Position: refs/heads/master@{#592861}
parent 250d247e
......@@ -291,8 +291,6 @@ void LibraryList::UnloadLibrary(LibraryView* wrap) {
LibraryView* LibraryList::LoadLibraryWithSystemLinker(const char* lib_name,
int dlopen_mode,
Error* error) {
LOG("lib_name='%s'", lib_name);
// First check whether a library with the same base name was
// already loaded.
LibraryView* view = FindKnownLibrary(lib_name);
......@@ -301,7 +299,6 @@ LibraryView* LibraryList::LoadLibraryWithSystemLinker(const char* lib_name,
return view;
}
LOG("Loading system library '%s'", lib_name);
void* system_lib = SystemLinker::Open(lib_name, dlopen_mode);
if (!system_lib) {
error->Format("Can't load system library %s: %s", lib_name,
......@@ -314,7 +311,6 @@ LibraryView* LibraryList::LoadLibraryWithSystemLinker(const char* lib_name,
known_libraries_.PushBack(view);
LOG("System library %s loaded at %p", lib_name, view);
LOG(" name=%s\n", view->GetName());
return view;
}
......@@ -361,7 +357,11 @@ LibraryView* LibraryList::LoadLibrary(const char* lib_name,
}
LOG("Found library: path %s @ 0x%x", probe.path.c_str(), probe.offset);
// Load the library
if (IsSystemLibraryPath(probe.path.c_str())) {
return LoadLibraryWithSystemLinker(probe.path.c_str(), RTLD_NOW, error);
}
// Load the library with the crazy linker.
ScopedPtr<SharedLibrary> lib(new SharedLibrary());
if (!lib->Load(probe.path.c_str(), load_address, probe.offset, error))
return nullptr;
......
......@@ -51,6 +51,32 @@ String MakeAbsolutePathFrom(const char* path, size_t path_len) {
}
}
bool IsSystemLibraryPath(const char* lib_path) {
static const char* kSystemPrefixes[] = {
#ifdef __ANDROID__
// From recent Android linker sources ($AOSP/bionic/linker/linker.cpp).
"/system/lib64/", "/odm/lib64/", "/vendor/lib64/",
"/data/asan/system/lib64/", "/data/asan/odm/lib64/",
"/data/asan/vendor/lib64/",
// It's ok to mix 32-bit and 64-bit paths in the same list here.
"/system/lib/", "/odm/lib/", "/vendor/lib/", "/data/asan/system/lib/",
"/data/asan/odm/lib/", "/data/asan/vendor/lib/",
#else
// Typical system library directories for Linux systems.
"/lib/", "/lib32/", "/lib64/",
"/libx32/", "/usr/lib/", "/usr/lib32/",
"/usr/lib64/", "/usr/libx32/", "/usr/local/lib/",
#endif
};
size_t lib_path_len = ::strlen(lib_path);
for (const char* prefix : kSystemPrefixes) {
size_t prefix_len = ::strlen(prefix);
if (prefix_len < lib_path_len && !::memcmp(prefix, lib_path, prefix_len))
return true;
}
return false;
}
} // namespace crazy
#ifndef UNIT_TEST
......
......@@ -149,6 +149,12 @@ String MakeAbsolutePathFrom(const char* path, size_t path_len);
// Returns the value of a given environment variable.
const char* GetEnv(const char* var_name);
// Returns true iff |lib_path| corresponds to the path of a system library,
// which should always be loaded through the system linker, and not the
// crazy one. Note that |lib_path| must be an absolute path, not a relative
// one.
bool IsSystemLibraryPath(const char* lib_path);
} // namespace crazy
#endif // CRAZY_LINKER_SYSTEM_H
......@@ -97,4 +97,26 @@ TEST(System, PathExistsWithBadPath) {
EXPECT_FALSE(PathExists("/tmp/foo"));
}
TEST(System, IsSystemLibraryPath) {
static const struct TestPath {
bool expected;
const char* path;
} kTestPaths[] = {
#ifdef __ANDROID__
{true, "/system/lib/libfoo.so"},
{true, "/system/lib64/libbar.so"},
{true, "/system/lib/egl/libEGL_emulation.so"},
{true, "/vendor/lib/egl/libEGL_swiftshader.so"},
{true, "/vendor/lib64/libfirmware.so"},
{false, "/system/app/Foo/lib/libfoo.so"},
{false, "/system/app/Foo/Foo.apk!lib/x86/libfoo.so"},
#else
{true, "/usr/lib/libfoo.so"}, {false, "/opt/foo/lib/libfoo.so"},
#endif
};
for (const TestPath& path : kTestPaths) {
EXPECT_EQ(path.expected, IsSystemLibraryPath(path.path)) << path.path;
}
}
} // namespace crazy
......@@ -149,8 +149,8 @@ void* WrapDlsym(void* lib_handle, const char* symbol_name) {
SystemLinker::Resolve(lib_handle, symbol_name);
if (!sym.IsValid()) {
SaveSystemError();
LOG("dlsym: could not find symbol '%s' from foreign library\n",
symbol_name, GetThreadData()->GetError());
LOG("Could not find symbol '%s' from foreign library [%s]", symbol_name,
GetThreadData()->GetError());
}
return sym.address;
}
......@@ -160,10 +160,8 @@ void* WrapDlsym(void* lib_handle, const char* symbol_name) {
LibraryView::SearchResult sym = wrap_lib->LookupSymbol(symbol_name);
if (!sym.IsValid()) {
SaveSystemError();
LOG("dlsym:%s: could not find symbol '%s' from system library\n%s",
wrap_lib->GetName(),
symbol_name,
GetThreadData()->GetError());
LOG("Could not find symbol '%s' from system library %s [%s]", symbol_name,
wrap_lib->GetName(), GetThreadData()->GetError());
}
return sym.address;
}
......@@ -223,7 +221,7 @@ int WrapDlclose(void* lib_handle) {
// Fall-back to the system in this case.
if (SystemLinker::Close(lib_handle) != 0) {
SaveSystemError();
LOG("dlclose: could not close foreign library handle %p\n%s", lib_handle,
LOG("Could not close foreign library handle %p\n%s", lib_handle,
GetThreadData()->GetError());
return -1;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment