Merge "Add support for protected local symbol lookup."
This commit is contained in:
commit
176ccd4925
@ -100,30 +100,23 @@ void* dlsym(void* handle, const char* symbol) {
|
|||||||
|
|
||||||
soinfo* found = NULL;
|
soinfo* found = NULL;
|
||||||
ElfW(Sym)* sym = NULL;
|
ElfW(Sym)* sym = NULL;
|
||||||
if (handle == RTLD_DEFAULT) {
|
void* caller_addr = __builtin_return_address(0);
|
||||||
sym = dlsym_linear_lookup(symbol, &found, NULL);
|
soinfo* caller_si = find_containing_library(caller_addr);
|
||||||
} else if (handle == RTLD_NEXT) {
|
|
||||||
void* caller_addr = __builtin_return_address(0);
|
|
||||||
soinfo* si = find_containing_library(caller_addr);
|
|
||||||
|
|
||||||
|
if (handle == RTLD_DEFAULT) {
|
||||||
|
sym = dlsym_linear_lookup(symbol, &found, NULL, caller_si);
|
||||||
|
} else if (handle == RTLD_NEXT) {
|
||||||
sym = NULL;
|
sym = NULL;
|
||||||
if (si && si->next) {
|
if (caller_si && caller_si->next) {
|
||||||
sym = dlsym_linear_lookup(symbol, &found, si->next);
|
sym = dlsym_linear_lookup(symbol, &found, caller_si->next, caller_si);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
found = reinterpret_cast<soinfo*>(handle);
|
found = reinterpret_cast<soinfo*>(handle);
|
||||||
sym = dlsym_handle_lookup(found, symbol);
|
sym = dlsym_handle_lookup(found, symbol, caller_si);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sym != NULL) {
|
if (sym != NULL && sym->st_shndx != 0) {
|
||||||
unsigned bind = ELF_ST_BIND(sym->st_info);
|
return reinterpret_cast<void*>(sym->st_value + found->load_bias);
|
||||||
|
|
||||||
if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
|
|
||||||
return reinterpret_cast<void*>(sym->st_value + found->load_bias);
|
|
||||||
}
|
|
||||||
|
|
||||||
__bionic_format_dlerror("symbol found but not global", symbol);
|
|
||||||
return NULL;
|
|
||||||
} else {
|
} else {
|
||||||
__bionic_format_dlerror("undefined symbol", symbol);
|
__bionic_format_dlerror("undefined symbol", symbol);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -125,6 +125,11 @@ enum RelocationKind {
|
|||||||
kRelocMax
|
kRelocMax
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class SymbolLookupScope {
|
||||||
|
kAllowLocal,
|
||||||
|
kExcludeLocal,
|
||||||
|
};
|
||||||
|
|
||||||
#if STATS
|
#if STATS
|
||||||
struct linker_stats_t {
|
struct linker_stats_t {
|
||||||
int count[kRelocMax];
|
int count[kRelocMax];
|
||||||
@ -431,7 +436,7 @@ int dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) {
|
static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name, const SymbolLookupScope& lookup_scope) {
|
||||||
ElfW(Sym)* symtab = si->symtab;
|
ElfW(Sym)* symtab = si->symtab;
|
||||||
const char* strtab = si->strtab;
|
const char* strtab = si->strtab;
|
||||||
|
|
||||||
@ -442,18 +447,30 @@ static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name)
|
|||||||
ElfW(Sym)* s = symtab + n;
|
ElfW(Sym)* s = symtab + n;
|
||||||
if (strcmp(strtab + s->st_name, name)) continue;
|
if (strcmp(strtab + s->st_name, name)) continue;
|
||||||
|
|
||||||
/* only concern ourselves with global and weak symbol definitions */
|
|
||||||
switch (ELF_ST_BIND(s->st_info)) {
|
switch (ELF_ST_BIND(s->st_info)) {
|
||||||
case STB_GLOBAL:
|
case STB_GLOBAL:
|
||||||
case STB_WEAK:
|
case STB_WEAK:
|
||||||
if (s->st_shndx == SHN_UNDEF) {
|
if (s->st_shndx == SHN_UNDEF) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
|
TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
|
||||||
name, si->name, reinterpret_cast<void*>(s->st_value),
|
name, si->name, reinterpret_cast<void*>(s->st_value),
|
||||||
static_cast<size_t>(s->st_size));
|
static_cast<size_t>(s->st_size));
|
||||||
return s;
|
return s;
|
||||||
|
case STB_LOCAL:
|
||||||
|
if (lookup_scope != SymbolLookupScope::kAllowLocal) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
TRACE_TYPE(LOOKUP, "FOUND LOCAL %s in %s (%p) %zd",
|
||||||
|
name, si->name, reinterpret_cast<void*>(s->st_value),
|
||||||
|
static_cast<size_t>(s->st_size));
|
||||||
|
return s;
|
||||||
|
default:
|
||||||
|
const char* msg = "FATAL: Unexpected ST_BIND\n";
|
||||||
|
__libc_format_log(ANDROID_LOG_FATAL, "linker", "%s", msg);
|
||||||
|
write(2, msg, strlen(msg));
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -484,7 +501,7 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, s
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if (si == somain) {
|
if (si == somain) {
|
||||||
s = soinfo_elf_lookup(si, elf_hash, name);
|
s = soinfo_elf_lookup(si, elf_hash, name, SymbolLookupScope::kAllowLocal);
|
||||||
if (s != NULL) {
|
if (s != NULL) {
|
||||||
*lsi = si;
|
*lsi = si;
|
||||||
goto done;
|
goto done;
|
||||||
@ -501,7 +518,7 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, s
|
|||||||
if (!si->has_DT_SYMBOLIC) {
|
if (!si->has_DT_SYMBOLIC) {
|
||||||
DEBUG("%s: looking up %s in executable %s",
|
DEBUG("%s: looking up %s in executable %s",
|
||||||
si->name, name, somain->name);
|
si->name, name, somain->name);
|
||||||
s = soinfo_elf_lookup(somain, elf_hash, name);
|
s = soinfo_elf_lookup(somain, elf_hash, name, SymbolLookupScope::kExcludeLocal);
|
||||||
if (s != NULL) {
|
if (s != NULL) {
|
||||||
*lsi = somain;
|
*lsi = somain;
|
||||||
goto done;
|
goto done;
|
||||||
@ -518,7 +535,7 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, s
|
|||||||
* and some the first non-weak definition. This is system dependent.
|
* and some the first non-weak definition. This is system dependent.
|
||||||
* Here we return the first definition found for simplicity. */
|
* Here we return the first definition found for simplicity. */
|
||||||
|
|
||||||
s = soinfo_elf_lookup(si, elf_hash, name);
|
s = soinfo_elf_lookup(si, elf_hash, name, SymbolLookupScope::kAllowLocal);
|
||||||
if (s != NULL) {
|
if (s != NULL) {
|
||||||
*lsi = si;
|
*lsi = si;
|
||||||
goto done;
|
goto done;
|
||||||
@ -532,7 +549,7 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, s
|
|||||||
if (si->has_DT_SYMBOLIC) {
|
if (si->has_DT_SYMBOLIC) {
|
||||||
DEBUG("%s: looking up %s in executable %s after local scope",
|
DEBUG("%s: looking up %s in executable %s after local scope",
|
||||||
si->name, name, somain->name);
|
si->name, name, somain->name);
|
||||||
s = soinfo_elf_lookup(somain, elf_hash, name);
|
s = soinfo_elf_lookup(somain, elf_hash, name, SymbolLookupScope::kExcludeLocal);
|
||||||
if (s != NULL) {
|
if (s != NULL) {
|
||||||
*lsi = somain;
|
*lsi = somain;
|
||||||
goto done;
|
goto done;
|
||||||
@ -543,7 +560,7 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, s
|
|||||||
|
|
||||||
/* Next, look for it in the preloads list */
|
/* Next, look for it in the preloads list */
|
||||||
for (int i = 0; g_ld_preloads[i] != NULL; i++) {
|
for (int i = 0; g_ld_preloads[i] != NULL; i++) {
|
||||||
s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name);
|
s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name, SymbolLookupScope::kExcludeLocal);
|
||||||
if (s != NULL) {
|
if (s != NULL) {
|
||||||
*lsi = g_ld_preloads[i];
|
*lsi = g_ld_preloads[i];
|
||||||
goto done;
|
goto done;
|
||||||
@ -553,7 +570,7 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, s
|
|||||||
for (int i = 0; needed[i] != NULL; i++) {
|
for (int i = 0; needed[i] != NULL; i++) {
|
||||||
DEBUG("%s: looking up %s in %s",
|
DEBUG("%s: looking up %s in %s",
|
||||||
si->name, name, needed[i]->name);
|
si->name, name, needed[i]->name);
|
||||||
s = soinfo_elf_lookup(needed[i], elf_hash, name);
|
s = soinfo_elf_lookup(needed[i], elf_hash, name, SymbolLookupScope::kExcludeLocal);
|
||||||
if (s != NULL) {
|
if (s != NULL) {
|
||||||
*lsi = needed[i];
|
*lsi = needed[i];
|
||||||
goto done;
|
goto done;
|
||||||
@ -582,8 +599,9 @@ done:
|
|||||||
Binary Interface) where in Chapter 5 it discuss resolving "Shared
|
Binary Interface) where in Chapter 5 it discuss resolving "Shared
|
||||||
Object Dependencies" in breadth first search order.
|
Object Dependencies" in breadth first search order.
|
||||||
*/
|
*/
|
||||||
ElfW(Sym)* dlsym_handle_lookup(soinfo* si, const char* name) {
|
ElfW(Sym)* dlsym_handle_lookup(soinfo* si, const char* name, soinfo* caller) {
|
||||||
return soinfo_elf_lookup(si, elfhash(name), name);
|
return soinfo_elf_lookup(si, elfhash(name), name,
|
||||||
|
caller == si ? SymbolLookupScope::kAllowLocal : SymbolLookupScope::kExcludeLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is used by dlsym(3) to performs a global symbol lookup. If the
|
/* This is used by dlsym(3) to performs a global symbol lookup. If the
|
||||||
@ -591,7 +609,7 @@ ElfW(Sym)* dlsym_handle_lookup(soinfo* si, const char* name) {
|
|||||||
beginning of the global solist. Otherwise the search starts at the
|
beginning of the global solist. Otherwise the search starts at the
|
||||||
specified soinfo (for RTLD_NEXT).
|
specified soinfo (for RTLD_NEXT).
|
||||||
*/
|
*/
|
||||||
ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start) {
|
ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start, soinfo* caller) {
|
||||||
unsigned elf_hash = elfhash(name);
|
unsigned elf_hash = elfhash(name);
|
||||||
|
|
||||||
if (start == NULL) {
|
if (start == NULL) {
|
||||||
@ -600,7 +618,8 @@ ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start)
|
|||||||
|
|
||||||
ElfW(Sym)* s = NULL;
|
ElfW(Sym)* s = NULL;
|
||||||
for (soinfo* si = start; (s == NULL) && (si != NULL); si = si->next) {
|
for (soinfo* si = start; (s == NULL) && (si != NULL); si = si->next) {
|
||||||
s = soinfo_elf_lookup(si, elf_hash, name);
|
s = soinfo_elf_lookup(si, elf_hash, name,
|
||||||
|
caller == si ? SymbolLookupScope::kAllowLocal : SymbolLookupScope::kExcludeLocal);
|
||||||
if (s != NULL) {
|
if (s != NULL) {
|
||||||
*found = si;
|
*found = si;
|
||||||
break;
|
break;
|
||||||
|
@ -234,11 +234,11 @@ void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path);
|
|||||||
soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo);
|
soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo);
|
||||||
void do_dlclose(soinfo* si);
|
void do_dlclose(soinfo* si);
|
||||||
|
|
||||||
ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start);
|
ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start, soinfo* caller_si);
|
||||||
soinfo* find_containing_library(const void* addr);
|
soinfo* find_containing_library(const void* addr);
|
||||||
|
|
||||||
ElfW(Sym)* dladdr_find_symbol(soinfo* si, const void* addr);
|
ElfW(Sym)* dladdr_find_symbol(soinfo* si, const void* addr);
|
||||||
ElfW(Sym)* dlsym_handle_lookup(soinfo* si, const char* name);
|
ElfW(Sym)* dlsym_handle_lookup(soinfo* si, const char* name, soinfo* caller_si);
|
||||||
|
|
||||||
void debuggerd_init();
|
void debuggerd_init();
|
||||||
extern "C" abort_msg_t* g_abort_message;
|
extern "C" abort_msg_t* g_abort_message;
|
||||||
|
@ -50,6 +50,20 @@ TEST(dlfcn, dlsym_in_self) {
|
|||||||
ASSERT_EQ(0, dlclose(self));
|
ASSERT_EQ(0, dlclose(self));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(dlfcn, dlsym_local_symbol) {
|
||||||
|
void* handle = dlopen("libtest_local_symbol.so", RTLD_NOW);
|
||||||
|
ASSERT_TRUE(handle != NULL);
|
||||||
|
dlerror();
|
||||||
|
void* sym = dlsym(handle, "private_taxicab_number");
|
||||||
|
ASSERT_TRUE(sym == NULL);
|
||||||
|
ASSERT_STREQ("undefined symbol: private_taxicab_number", dlerror());
|
||||||
|
|
||||||
|
uint32_t (*f)(void);
|
||||||
|
f = reinterpret_cast<uint32_t (*)(void)>(dlsym(handle, "dlsym_local_symbol_get_taxicab_number_using_dlsym"));
|
||||||
|
ASSERT_TRUE(f != NULL);
|
||||||
|
ASSERT_EQ(1729, f());
|
||||||
|
}
|
||||||
|
|
||||||
TEST(dlfcn, dlopen_noload) {
|
TEST(dlfcn, dlopen_noload) {
|
||||||
void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
|
void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
|
||||||
ASSERT_TRUE(handle == NULL);
|
ASSERT_TRUE(handle == NULL);
|
||||||
|
@ -88,6 +88,20 @@ build_type := target
|
|||||||
build_target := SHARED_LIBRARY
|
build_target := SHARED_LIBRARY
|
||||||
include $(TEST_PATH)/Android.build.mk
|
include $(TEST_PATH)/Android.build.mk
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Library used to test local symbol lookup
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
libtest_local_symbol_src_files := \
|
||||||
|
dlsym_local_symbol_private.cpp \
|
||||||
|
dlsym_local_symbol_public.cpp
|
||||||
|
|
||||||
|
module := libtest_local_symbol
|
||||||
|
build_target := SHARED_LIBRARY
|
||||||
|
libtest_local_symbol_ldflags := -Wl,--version-script=$(LOCAL_PATH)/dlsym_local_symbol.map
|
||||||
|
libtest_local_symbol_cppflags := -std=gnu++11
|
||||||
|
libtest_local_symbol_shared_libraries_target := libdl
|
||||||
|
build_type := target
|
||||||
|
include $(TEST_PATH)/Android.build.mk
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Library used by atexit tests
|
# Library used by atexit tests
|
||||||
|
22
tests/libs/dlsym_local_symbol.map
Normal file
22
tests/libs/dlsym_local_symbol.map
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 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.
|
||||||
|
*/
|
||||||
|
LIBTEST_LOCAL_SYMBOL_1.0 {
|
||||||
|
global:
|
||||||
|
dlsym_local_symbol_get_taxicab_number;
|
||||||
|
dlsym_local_symbol_get_taxicab_number_using_dlsym;
|
||||||
|
local:
|
||||||
|
*;
|
||||||
|
};
|
24
tests/libs/dlsym_local_symbol_private.cpp
Normal file
24
tests/libs/dlsym_local_symbol_private.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 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 <stdlib.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// This symbol is declared local in
|
||||||
|
// the linker version map: libdlsym_local_symbol.map.
|
||||||
|
// It should not be visible from the outside.
|
||||||
|
extern "C" const uint32_t __attribute__ ((visibility ("protected"))) private_taxicab_number = 1729;
|
47
tests/libs/dlsym_local_symbol_public.cpp
Normal file
47
tests/libs/dlsym_local_symbol_public.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 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 <stdlib.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
extern const uint32_t private_taxicab_number;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
uint32_t dlsym_local_symbol_get_taxicab_number();
|
||||||
|
uint32_t dlsym_local_symbol_get_taxicab_number_using_dlsym();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t dlsym_local_symbol_get_taxicab_number() {
|
||||||
|
return private_taxicab_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let's make sure that dlsym works correctly for local symbol
|
||||||
|
uint32_t dlsym_local_symbol_get_taxicab_number_using_dlsym() {
|
||||||
|
dlerror();
|
||||||
|
uint32_t* ptr = reinterpret_cast<uint32_t*>(dlsym(RTLD_DEFAULT, "private_taxicab_number"));
|
||||||
|
if (ptr == nullptr) {
|
||||||
|
const char* dlerr = dlerror();
|
||||||
|
if (dlerr != nullptr) {
|
||||||
|
fprintf(stderr, "dlsym error: %s\n", dlerr);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "dlsym returned NULL with no dlerror.\n");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *ptr;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user