Commit 545e9325 authored by David 'Digit' Turner's avatar David 'Digit' Turner Committed by Commit Bot

android: crazy_linker: Read library DT_SONAME entry.

This CL slightly modifies the crazy linker to extract the DT_SONAME
of a given shared library. The goal is to use the soname as the unique
identifier for a library during dependency resolution, as this matches
the behaviour of the system linker.

More precisely:

- Before this CL, each library loaded by the linker is identified
  by a "name" that was the library path (with any directory sub-path)
  used to load the library.

  This prevents properly resolving DT_NEEDED entries, which explains
  one of the reasons why the crazy linker doesn't support the
  component build at the moment.

- After this CL, system libraries are identified by their basename
  only (which was already the case when they were loaded through
  DT_NEEDED entries, but changes what happens when they are loaded
  through the dlopen() wrapper).

  Ideally, non-system libraries should be identified by the soname,
  but this currently doesn't work, because it breaks RELRO sharing.
  The reason for this is that, when loading libraries directly from
  a zip file, the current client code (chromium_android_linker)
  passes and relies on the path to the host APK directly
  (e.g. something like /data/data/<package-name>-<number>/base.apk
  and a file offset. This will be addressed in a future CL.

BUG=802068
R=lizeb@chromium.org, pasko@chromium.org, agrieve@chromium.org

Change-Id: Ia282c29e80e8729c4079a80de7acf66975b7d1ee
Reviewed-on: https://chromium-review.googlesource.com/1042406
Commit-Queue: David Turner <digit@chromium.org>
Reviewed-by: default avataragrieve <agrieve@chromium.org>
Cr-Commit-Position: refs/heads/master@{#557175}
parent 9360348e
......@@ -356,8 +356,7 @@ LibraryView* LibraryList::LoadLibrary(const char* lib_name,
return NULL;
}
LibraryView* wrap = new LibraryView();
wrap->SetSystem(system_lib, lib_name);
LibraryView* wrap = new LibraryView(system_lib, base_name);
known_libraries_.PushBack(wrap);
LOG("System library %s loaded at %p", lib_name, wrap);
......@@ -430,8 +429,12 @@ LibraryView* LibraryList::LoadLibrary(const char* lib_name,
head_ = lib.Get();
// Then create a new LibraryView for it.
wrap = new LibraryView();
wrap->SetCrazy(lib.Get(), lib_name);
// TODO(digit): Use the library's soname() instead of |lib_name| here.
// This is not possible yet because the current code relies on the fact
// that lib_name is /data/data/..../base.apk + a file offset at the moment
// to perform RELRO sharing properly. This will be fixed in a future CL
// that also modifies the client code in chromium_android_linker.
wrap = new LibraryView(lib.Get(), lib_name);
known_libraries_.PushBack(wrap);
LOG("Running constructors for %s", base_name);
......
......@@ -11,6 +11,9 @@
namespace crazy {
LibraryView::LibraryView(SharedLibrary* crazy_lib)
: type_(TYPE_CRAZY), crazy_(crazy_lib), name_(crazy_lib->soname()) {}
LibraryView::~LibraryView() {
LOG("Destroying %s", name_.c_str());
if (type_ == TYPE_SYSTEM) {
......
......@@ -16,8 +16,9 @@ class SharedLibrary;
// crazy::SharedLibrary object or a library handle returned by the system's
// dlopen() function.
//
// It has a name, which is always a base name, because only one
// library with a given base name can be loaded in the system.
// It has a name, which normally corresponds to the DT_SONAME entry in the
// dynamic table (i.e. the name embedded within the ELF file, which does not
// always matches its file path name).
class LibraryView {
public:
enum {
......@@ -26,33 +27,39 @@ class LibraryView {
TYPE_CRAZY = 0xcdef2387,
};
LibraryView()
: type_(TYPE_NONE), crazy_(NULL), system_(NULL), name_(), ref_count_(1) {}
// Constructor for wrapping a system library handle.
// |system_lib| is the dlopen() handle, and |lib_name| should be the
// library soname for it.
LibraryView(void* system_handle, const char* lib_name)
: type_(TYPE_SYSTEM), system_(system_handle), name_(lib_name) {}
// Constructor for wrapping a crazy::SharedLibrary instance.
LibraryView(SharedLibrary* crazy_lib, const char* lib_name)
: type_(TYPE_CRAZY), crazy_(crazy_lib), name_(lib_name) {}
// Constructor for warpping a crazy::SharedLibrary instance.
// This version takes the library name from the its soname() value.
LibraryView(SharedLibrary* crazy_lib);
// Destructor, this will either dlclose() a system library, or delete
// a SharedLibrary instance.
~LibraryView();
// Returns true iff this is a system library handle.
bool IsSystem() const { return type_ == TYPE_SYSTEM; }
// Returns true iff this is a SharedLibrary instance.
bool IsCrazy() const { return type_ == TYPE_CRAZY; }
void SetSystem(void* system_lib, const char* name) {
type_ = TYPE_SYSTEM;
system_ = system_lib;
name_ = name;
}
void SetCrazy(SharedLibrary* crazy_lib, const char* name) {
type_ = TYPE_CRAZY;
crazy_ = crazy_lib;
name_ = name;
}
// Returns the soname of the current library (or its base name if not
// available).
const char* GetName() { return name_.c_str(); }
SharedLibrary* GetCrazy() { return IsCrazy() ? crazy_ : NULL; }
void* GetSystem() { return IsSystem() ? system_ : NULL; }
// Increment reference count for this LibraryView.
void AddRef() { ref_count_++; }
// Decrement reference count. Returns true iff it reaches 0.
......@@ -75,13 +82,15 @@ class LibraryView {
int ref_count() const { return ref_count_; }
private:
uint32_t type_;
SharedLibrary* crazy_;
void* system_;
uint32_t type_ = TYPE_NONE;
int ref_count_ = 1;
union {
SharedLibrary* crazy_ = nullptr;
void* system_;
};
String name_;
int ref_count_;
};
} // namespace crazy
#endif // CRAZY_LINKER_LIBRARY_VIEW_H
\ No newline at end of file
#endif // CRAZY_LINKER_LIBRARY_VIEW_H
......@@ -219,6 +219,13 @@ bool SharedLibrary::Load(const char* full_path,
strlcpy(full_path_, full_path, sizeof(full_path_));
base_name_ = GetBaseNamePtr(full_path_);
// Default value of |soname_| will be |base_name_| unless overidden
// by a DT_SONAME entry. This helps deal with broken libraries that don't
// have one. Note that starting with Android N, the system linker requires
// every library to have a DT_SONAME, as these are used to uniquely identify
// libraries for dependency resolution (barring namespace isolation).
soname_ = base_name_;
// Load the ELF binary in memory.
LOG("Loading ELF segments for %s", base_name_);
......@@ -318,6 +325,11 @@ bool SharedLibrary::Load(const char* full_path,
reinterpret_cast<ELF::Addr>(rdebug->GetAddress());
break;
#endif
case DT_SONAME:
soname_ = symbols_.string_table() + dyn_value;
LOG(" DT_SONAME %s", soname_);
break;
default:
;
}
......
......@@ -40,6 +40,10 @@ class SharedLibrary {
size_t phdr_count() const { return view_.phdr_count(); }
const char* base_name() const { return base_name_; }
// Return name of the library as found in DT_SONAME entry, or same
// as base_name() if not available.
const char* soname() const { return soname_; }
// Load a library (without its dependents) from an ELF file.
// Note: This does not apply relocations, nor runs constructors.
// |full_path| if the file full path.
......@@ -200,6 +204,7 @@ class SharedLibrary {
void* java_vm_;
const char* soname_;
const char* base_name_;
char full_path_[512];
};
......
......@@ -112,8 +112,7 @@ void* WrapDlopen(const char* path, int mode) {
return NULL;
}
LibraryView* wrap_lib = new LibraryView();
wrap_lib->SetSystem(system_lib, path ? path : "<executable>");
auto* wrap_lib = new LibraryView(system_lib, path ? path : "<executable>");
globals->libraries()->AddLibrary(wrap_lib);
globals->valid_handles()->Add(wrap_lib);
return wrap_lib;
......
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