Fix unused DT entry warnings.
DT_STRSZ Implement strtab boundary checks
DT_FLAGS_1 Warn if flags other than DF_1_NOW|DF_1_GLOBAL are set
Bug: 17552334
Change-Id: Iaad29cd52f5b2d7d2f785fb351697906dc1617d9
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index c930ce9..98931c7 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -147,7 +147,7 @@
// Determine if any symbol in the library contains the specified address.
ElfW(Sym)* sym = dladdr_find_symbol(si, addr);
if (sym != nullptr) {
- info->dli_sname = si->strtab + sym->st_name;
+ info->dli_sname = si->get_string(sym->st_name);
info->dli_saddr = reinterpret_cast<void*>(si->resolve_symbol_address(sym));
}
@@ -245,6 +245,7 @@
__libdl_info.bucket = g_libdl_buckets;
__libdl_info.chain = g_libdl_chains;
__libdl_info.ref_count = 1;
+ __libdl_info.strtab_size = sizeof(ANDROID_LIBDL_STRTAB);
}
return &__libdl_info;
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 5b39668..4f42c82 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -417,14 +417,13 @@
static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) {
ElfW(Sym)* symtab = si->symtab;
- const char* strtab = si->strtab;
TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p %x %zd",
name, si->name, reinterpret_cast<void*>(si->base), hash, hash % si->nbucket);
for (unsigned n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) {
ElfW(Sym)* s = symtab + n;
- if (strcmp(strtab + s->st_name, name)) continue;
+ if (strcmp(si->get_string(s->st_name), name)) continue;
// only concern ourselves with global and weak symbol definitions
switch (ELF_ST_BIND(s->st_info)) {
@@ -775,7 +774,7 @@
static void for_each_dt_needed(const soinfo* si, F action) {
for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
if (d->d_tag == DT_NEEDED) {
- action(si->strtab + d->d_un.d_val);
+ action(si->get_string(d->d_un.d_val));
}
}
}
@@ -1085,7 +1084,7 @@
soinfo* lsi = nullptr;
if (sym != 0) {
- sym_name = reinterpret_cast<const char*>(strtab + symtab[sym].st_name);
+ sym_name = get_string(symtab[sym].st_name);
s = soinfo_do_lookup(this, sym_name, &lsi);
if (s == nullptr) {
// We only allow an undefined symbol if this is a weak reference...
@@ -1363,7 +1362,7 @@
soinfo* lsi = nullptr;
if (sym != 0) {
- sym_name = reinterpret_cast<const char*>(strtab + symtab[sym].st_name);
+ sym_name = get_string(symtab[sym].st_name);
s = soinfo_do_lookup(this, sym_name, &lsi);
if (s == nullptr) {
// We only allow an undefined symbol if this is a weak reference...
@@ -1581,7 +1580,7 @@
got = si->plt_got + local_gotno;
for (size_t g = gotsym; g < symtabno; g++, sym++, got++) {
// This is an undefined reference... try to locate it.
- const char* sym_name = si->strtab + sym->st_name;
+ const char* sym_name = si->get_string(sym->st_name);
soinfo* lsi = nullptr;
ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi);
if (s == nullptr) {
@@ -1787,6 +1786,14 @@
return static_cast<ElfW(Addr)>(s->st_value + load_bias);
}
+const char* soinfo::get_string(ElfW(Word) index) const {
+ if (has_min_version(1) && (index >= strtab_size)) {
+ __libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d", name, strtab_size, index);
+ }
+
+ return strtab + index;
+}
+
/* Force any of the closed stdin, stdout and stderr to be associated with
/dev/null. */
static int nullify_closed_stdio() {
@@ -1895,6 +1902,9 @@
case DT_STRTAB:
strtab = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
break;
+ case DT_STRSZ:
+ strtab_size = d->d_un.d_val;
+ break;
case DT_SYMTAB:
symtab = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
break;
@@ -2048,6 +2058,16 @@
has_DT_SYMBOLIC = true;
}
break;
+ case DT_FLAGS_1:
+ if ((d->d_un.d_val & DF_1_GLOBAL) != 0) {
+ rtld_flags |= RTLD_GLOBAL;
+ }
+ // TODO: Implement other flags
+
+ if ((d->d_un.d_val & ~(DF_1_NOW | DF_1_GLOBAL)) != 0) {
+ DL_WARN("Unsupported flags DT_FLAGS_1=%p", reinterpret_cast<void*>(d->d_un.d_val));
+ }
+ break;
#if defined(__mips__)
case DT_STRSZ:
break;
@@ -2079,7 +2099,7 @@
default:
if (!relocating_linker) {
- DEBUG("%s: unused DT entry: type %p arg %p", name,
+ DL_WARN("%s: unused DT entry: type %p arg %p", name,
reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
}
break;
diff --git a/linker/linker.h b/linker/linker.h
index 2896933..f6e3a48 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -136,7 +136,9 @@
soinfo* next;
unsigned flags;
+ private:
const char* strtab;
+ public:
ElfW(Sym)* symtab;
size_t nbucket;
@@ -222,7 +224,9 @@
ElfW(Addr) resolve_symbol_address(ElfW(Sym)* s);
- bool inline has_min_version(uint32_t min_version) {
+ const char* get_string(ElfW(Word) index) const;
+
+ bool inline has_min_version(uint32_t min_version) const {
return (flags & FLAG_NEW_SOINFO) != 0 && version >= min_version;
}
private:
@@ -249,6 +253,9 @@
// version >= 1
int rtld_flags;
+ size_t strtab_size;
+
+ friend soinfo* get_libdl_info();
};
extern soinfo* get_libdl_info();