Merge "Introduce anonymous namespace"
This commit is contained in:
commit
db8caa740a
@ -131,12 +131,16 @@ typedef struct {
|
||||
extern void* android_dlopen_ext(const char* filename, int flag, const android_dlextinfo* extinfo);
|
||||
|
||||
/*
|
||||
* Initializes public namespace. The path is the list of sonames
|
||||
* separated by colon. Example: "libc.so:libm.so:libdl.so".
|
||||
*
|
||||
* Initializes public and anonymous namespaces. The public_ns_sonames is the list of sonames
|
||||
* to be included into public namespace separated by colon. Example: "libc.so:libm.so:libdl.so".
|
||||
* The libraries in this list should be loaded prior to this call.
|
||||
*
|
||||
* The anon_ns_library_path is the search path for anonymous namespace. The anonymous namespace
|
||||
* is used in the case when linker cannot identify the caller of dlopen/dlsym. This happens
|
||||
* for the code not loaded by dynamic linker; for example calls from the mono-compiled code.
|
||||
*/
|
||||
extern bool android_init_public_namespace(const char* path);
|
||||
extern bool android_init_namespaces(const char* public_ns_sonames,
|
||||
const char* anon_ns_library_path);
|
||||
|
||||
/*
|
||||
* Creates new linker namespace.
|
||||
|
@ -33,7 +33,13 @@ LOCAL_CFLAGS := -Wall -Wextra -Wunused -Werror
|
||||
LOCAL_CXX_STL := none
|
||||
|
||||
LOCAL_MODULE := libdl
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk \
|
||||
$(LOCAL_PATH)/libdl.arm.map \
|
||||
$(LOCAL_PATH)/libdl.arm64.map \
|
||||
$(LOCAL_PATH)/libdl.mips.map \
|
||||
$(LOCAL_PATH)/libdl.mips64.map \
|
||||
$(LOCAL_PATH)/libdl.x86.map \
|
||||
$(LOCAL_PATH)/libdl.x86_64.map \
|
||||
|
||||
# NOTE: libdl needs __aeabi_unwind_cpp_pr0 from libgcc.a but libgcc.a needs a
|
||||
# few symbols from libc. Using --no-undefined here results in having to link
|
||||
|
@ -16,7 +16,7 @@ LIBC {
|
||||
|
||||
LIBC_N {
|
||||
global:
|
||||
android_init_public_namespace;
|
||||
android_init_namespaces;
|
||||
android_create_namespace;
|
||||
} LIBC;
|
||||
|
||||
|
@ -15,7 +15,7 @@ LIBC {
|
||||
|
||||
LIBC_N {
|
||||
global:
|
||||
android_init_public_namespace;
|
||||
android_init_namespaces;
|
||||
android_create_namespace;
|
||||
} LIBC;
|
||||
|
||||
|
@ -49,7 +49,11 @@ void* android_dlopen_ext(const char* filename __unused, int flag __unused,
|
||||
void android_set_application_target_sdk_version(uint32_t target __unused) { }
|
||||
uint32_t android_get_application_target_sdk_version() { return 0; }
|
||||
|
||||
bool android_init_public_namespace(const char* paths __unused) { return false; }
|
||||
bool android_init_namespaces(const char* public_ns_sonames __unused,
|
||||
const char* anon_ns_library_path __unused) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct android_namespace_t* android_create_namespace(const char* name __unused,
|
||||
const char* ld_library_path __unused,
|
||||
const char* default_library_path __unused,
|
||||
|
@ -30,7 +30,7 @@ LIBC {
|
||||
|
||||
LIBC_N {
|
||||
global:
|
||||
android_init_public_namespace;
|
||||
android_init_namespaces;
|
||||
android_create_namespace;
|
||||
} LIBC;
|
||||
|
||||
|
@ -15,7 +15,7 @@ LIBC {
|
||||
|
||||
LIBC_N {
|
||||
global:
|
||||
android_init_public_namespace;
|
||||
android_init_namespaces;
|
||||
android_create_namespace;
|
||||
} LIBC;
|
||||
|
||||
|
@ -15,7 +15,7 @@ LIBC {
|
||||
|
||||
LIBC_N {
|
||||
global:
|
||||
android_init_public_namespace;
|
||||
android_init_namespaces;
|
||||
android_create_namespace;
|
||||
} LIBC;
|
||||
|
||||
|
@ -15,7 +15,7 @@ LIBC {
|
||||
|
||||
LIBC_N {
|
||||
global:
|
||||
android_init_public_namespace;
|
||||
android_init_namespaces;
|
||||
android_create_namespace;
|
||||
} LIBC;
|
||||
|
||||
|
@ -15,7 +15,7 @@ LIBC {
|
||||
|
||||
LIBC_N {
|
||||
global:
|
||||
android_init_public_namespace;
|
||||
android_init_namespaces;
|
||||
android_create_namespace;
|
||||
} LIBC;
|
||||
|
||||
|
@ -89,9 +89,12 @@ void* dlopen(const char* filename, int flags) {
|
||||
return dlopen_ext(filename, flags, nullptr, caller_addr);
|
||||
}
|
||||
|
||||
extern android_namespace_t* g_anonymous_namespace;
|
||||
|
||||
void* dlsym(void* handle, const char* symbol) {
|
||||
ScopedPthreadMutexLocker locker(&g_dl_mutex);
|
||||
|
||||
// TODO(dimitry): move (most of) the code below to linker.cpp
|
||||
#if !defined(__LP64__)
|
||||
if (handle == nullptr) {
|
||||
__bionic_format_dlerror("dlsym library handle is null", nullptr);
|
||||
@ -108,16 +111,10 @@ void* dlsym(void* handle, const char* symbol) {
|
||||
const ElfW(Sym)* sym = nullptr;
|
||||
void* caller_addr = __builtin_return_address(0);
|
||||
soinfo* caller = find_containing_library(caller_addr);
|
||||
if (caller == nullptr) {
|
||||
char buf[256];
|
||||
__libc_format_buffer(buf, sizeof(buf), "dlsym couldn't locate its caller address=%p; "
|
||||
"the caller was code not loaded by the dynamic linker", caller_addr);
|
||||
__bionic_format_dlerror(buf, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
android_namespace_t* ns = caller != nullptr ? caller->get_namespace() : g_anonymous_namespace;
|
||||
|
||||
if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
|
||||
sym = dlsym_linear_lookup(caller->get_namespace(), symbol, &found, caller, handle);
|
||||
sym = dlsym_linear_lookup(ns, symbol, &found, caller, handle);
|
||||
} else {
|
||||
sym = dlsym_handle_lookup(reinterpret_cast<soinfo*>(handle), &found, symbol);
|
||||
}
|
||||
@ -184,11 +181,12 @@ uint32_t android_get_application_target_sdk_version() {
|
||||
return get_application_target_sdk_version();
|
||||
}
|
||||
|
||||
bool android_init_public_namespace(const char* path) {
|
||||
bool android_init_namespaces(const char* public_ns_sonames,
|
||||
const char* anon_ns_library_path) {
|
||||
ScopedPthreadMutexLocker locker(&g_dl_mutex);
|
||||
bool success = init_public_namespace(path);
|
||||
bool success = init_namespaces(public_ns_sonames, anon_ns_library_path);
|
||||
if (!success) {
|
||||
__bionic_format_dlerror("android_init_public_namespace failed", linker_get_error_buffer());
|
||||
__bionic_format_dlerror("android_init_namespaces failed", linker_get_error_buffer());
|
||||
}
|
||||
|
||||
return success;
|
||||
@ -234,11 +232,11 @@ static const char ANDROID_LIBDL_STRTAB[] =
|
||||
// 00000000001 1111111112222222222 3333333333444444444455555555556666666666777 777777788888888889999999999
|
||||
// 01234567890 1234567890123456789 0123456789012345678901234567890123456789012 345678901234567890123456789
|
||||
"erate_phdr\0android_dlopen_ext\0android_set_application_target_sdk_version\0android_get_application_tar"
|
||||
// 0000000000111111 111122222222223333333333444444 4444555555555566666666667
|
||||
// 0123456789012345 678901234567890123456789012345 6789012345678901234567890
|
||||
"get_sdk_version\0android_init_public_namespace\0android_create_namespace\0"
|
||||
// 0000000000111111 111122222222223333333333 4444444444555555555566666
|
||||
// 0123456789012345 678901234567890123456789 0123456789012345678901234
|
||||
"get_sdk_version\0android_init_namespaces\0android_create_namespace\0"
|
||||
#if defined(__arm__)
|
||||
// 271
|
||||
// 265
|
||||
"dl_unwind_find_exidx\0"
|
||||
#endif
|
||||
;
|
||||
@ -260,10 +258,10 @@ static ElfW(Sym) g_libdl_symtab[] = {
|
||||
ELFW(SYM_INITIALIZER)(111, &android_dlopen_ext, 1),
|
||||
ELFW(SYM_INITIALIZER)(130, &android_set_application_target_sdk_version, 1),
|
||||
ELFW(SYM_INITIALIZER)(173, &android_get_application_target_sdk_version, 1),
|
||||
ELFW(SYM_INITIALIZER)(216, &android_init_public_namespace, 1),
|
||||
ELFW(SYM_INITIALIZER)(246, &android_create_namespace, 1),
|
||||
ELFW(SYM_INITIALIZER)(216, &android_init_namespaces, 1),
|
||||
ELFW(SYM_INITIALIZER)(240, &android_create_namespace, 1),
|
||||
#if defined(__arm__)
|
||||
ELFW(SYM_INITIALIZER)(271, &dl_unwind_find_exidx, 1),
|
||||
ELFW(SYM_INITIALIZER)(265, &dl_unwind_find_exidx, 1),
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -111,6 +111,7 @@ struct android_namespace_t {
|
||||
};
|
||||
|
||||
android_namespace_t g_default_namespace;
|
||||
android_namespace_t* g_anonymous_namespace = &g_default_namespace;
|
||||
|
||||
static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
|
||||
|
||||
@ -2201,7 +2202,7 @@ soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
android_namespace_t* ns = caller->get_namespace();
|
||||
android_namespace_t* ns = caller != nullptr ? caller->get_namespace() : g_anonymous_namespace;
|
||||
|
||||
if (extinfo != nullptr) {
|
||||
if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
|
||||
@ -2246,14 +2247,14 @@ void do_dlclose(soinfo* si) {
|
||||
soinfo_unload(si);
|
||||
}
|
||||
|
||||
bool init_public_namespace(const char* libs) {
|
||||
CHECK(libs != nullptr);
|
||||
bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path) {
|
||||
CHECK(public_ns_sonames != nullptr);
|
||||
if (g_public_namespace_initialized) {
|
||||
DL_ERR("Public namespace has already been initialized.");
|
||||
DL_ERR("public namespace has already been initialized.");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> sonames = android::base::Split(libs, ":");
|
||||
std::vector<std::string> sonames = android::base::Split(public_ns_sonames, ":");
|
||||
|
||||
ProtectedDataGuard guard;
|
||||
|
||||
@ -2267,7 +2268,7 @@ bool init_public_namespace(const char* libs) {
|
||||
find_loaded_library_by_soname(&g_default_namespace, soname.c_str(), &candidate);
|
||||
|
||||
if (candidate == nullptr) {
|
||||
DL_ERR("Error initializing public namespace: \"%s\" was not found"
|
||||
DL_ERR("error initializing public namespace: \"%s\" was not found"
|
||||
" in the default namespace", soname.c_str());
|
||||
return false;
|
||||
}
|
||||
@ -2276,8 +2277,18 @@ bool init_public_namespace(const char* libs) {
|
||||
g_public_namespace.push_back(candidate);
|
||||
}
|
||||
|
||||
failure_guard.disable();
|
||||
g_public_namespace_initialized = true;
|
||||
|
||||
// create anonymous namespace
|
||||
android_namespace_t* anon_ns =
|
||||
create_namespace("(anonymous)", nullptr, anon_ns_library_path, false);
|
||||
|
||||
if (anon_ns == nullptr) {
|
||||
g_public_namespace_initialized = false;
|
||||
return false;
|
||||
}
|
||||
g_anonymous_namespace = anon_ns;
|
||||
failure_guard.disable();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2286,7 +2297,7 @@ android_namespace_t* create_namespace(const char* name,
|
||||
const char* default_library_path,
|
||||
bool is_isolated) {
|
||||
if (!g_public_namespace_initialized) {
|
||||
DL_ERR("Cannot create namespace: public namespace is not initialized.");
|
||||
DL_ERR("cannot create namespace: public namespace is not initialized.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -444,7 +444,7 @@ size_t linker_get_error_buffer_size();
|
||||
void set_application_target_sdk_version(uint32_t target);
|
||||
uint32_t get_application_target_sdk_version();
|
||||
|
||||
bool init_public_namespace(const char* path);
|
||||
bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path);
|
||||
android_namespace_t* create_namespace(const char* name, const char* ld_library_path,
|
||||
const char* default_library_path, bool is_isolated);
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <pagemap/pagemap.h>
|
||||
|
||||
#include "TemporaryFile.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define ASSERT_DL_NOTNULL(ptr) \
|
||||
ASSERT_TRUE(ptr != nullptr) << "dlerror: " << dlerror()
|
||||
@ -610,8 +611,8 @@ TEST(dlext, ns_smoke) {
|
||||
static const char* root_lib = "libnstest_root.so";
|
||||
std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
|
||||
|
||||
ASSERT_FALSE(android_init_public_namespace(path.c_str()));
|
||||
ASSERT_STREQ("android_init_public_namespace failed: Error initializing public namespace: "
|
||||
ASSERT_FALSE(android_init_namespaces(path.c_str(), nullptr));
|
||||
ASSERT_STREQ("android_init_namespaces failed: error initializing public namespace: "
|
||||
"\"libnstest_public.so\" was not found in the default namespace", dlerror());
|
||||
|
||||
const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
|
||||
@ -619,7 +620,7 @@ TEST(dlext, ns_smoke) {
|
||||
void* handle_public = dlopen((lib_path + "/public_namespace_libs/" + g_public_lib).c_str(), RTLD_NOW);
|
||||
ASSERT_TRUE(handle_public != nullptr) << dlerror();
|
||||
|
||||
ASSERT_TRUE(android_init_public_namespace(path.c_str())) << dlerror();
|
||||
ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
|
||||
|
||||
// Check that libraries added to public namespace are NODELETE
|
||||
dlclose(handle_public);
|
||||
@ -719,7 +720,7 @@ TEST(dlext, ns_isolated) {
|
||||
|
||||
android_set_application_target_sdk_version(42U); // something > 23
|
||||
|
||||
ASSERT_TRUE(android_init_public_namespace(path.c_str())) << dlerror();
|
||||
ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
|
||||
|
||||
android_namespace_t* ns_not_isolated = android_create_namespace("private", nullptr, (lib_path + "/private_namespace_libs").c_str(), false);
|
||||
ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror();
|
||||
@ -795,3 +796,94 @@ TEST(dlext, ns_isolated) {
|
||||
|
||||
dlclose(handle1);
|
||||
}
|
||||
|
||||
TEST(dlext, ns_anonymous) {
|
||||
static const char* root_lib = "libnstest_root.so";
|
||||
std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
|
||||
|
||||
const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
|
||||
|
||||
void* handle_public = dlopen((lib_path + "/public_namespace_libs/" + g_public_lib).c_str(),
|
||||
RTLD_NOW);
|
||||
ASSERT_TRUE(handle_public != nullptr) << dlerror();
|
||||
|
||||
ASSERT_TRUE(android_init_namespaces(path.c_str(), (lib_path + "/private_namespace_libs").c_str()))
|
||||
<< dlerror();
|
||||
|
||||
android_namespace_t* ns = android_create_namespace(
|
||||
"private", nullptr,
|
||||
(lib_path + "/private_namespace_libs").c_str(),
|
||||
false);
|
||||
|
||||
ASSERT_TRUE(ns != nullptr) << dlerror();
|
||||
|
||||
std::string private_library_absolute_path = lib_path + "/private_namespace_libs/" + root_lib;
|
||||
|
||||
android_dlextinfo extinfo;
|
||||
extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
|
||||
extinfo.library_namespace = ns;
|
||||
|
||||
// we are going to copy this library to anonymous mmap and call the copy of ns_get_dlopened_string
|
||||
void* handle = android_dlopen_ext(private_library_absolute_path.c_str(), RTLD_NOW, &extinfo);
|
||||
ASSERT_TRUE(handle != nullptr) << dlerror();
|
||||
|
||||
uintptr_t ns_get_dlopened_string_addr =
|
||||
reinterpret_cast<uintptr_t>(dlsym(handle, "ns_get_dlopened_string"));
|
||||
ASSERT_TRUE(ns_get_dlopened_string_addr != 0) << dlerror();
|
||||
typedef const char* (*fn_t)();
|
||||
fn_t ns_get_dlopened_string_private = reinterpret_cast<fn_t>(ns_get_dlopened_string_addr);
|
||||
|
||||
std::vector<map_record> maps;
|
||||
Maps::parse_maps(&maps);
|
||||
|
||||
uintptr_t addr_start = 0;
|
||||
uintptr_t addr_end = 0;
|
||||
std::vector<map_record> maps_to_copy;
|
||||
|
||||
for (const auto& rec : maps) {
|
||||
if (rec.pathname == private_library_absolute_path) {
|
||||
if (addr_start == 0) {
|
||||
addr_start = rec.addr_start;
|
||||
}
|
||||
addr_end = rec.addr_end;
|
||||
|
||||
maps_to_copy.push_back(rec);
|
||||
}
|
||||
}
|
||||
|
||||
// some sanity checks..
|
||||
ASSERT_TRUE(addr_start > 0);
|
||||
ASSERT_TRUE(addr_end > 0);
|
||||
ASSERT_EQ(3U, maps_to_copy.size());
|
||||
ASSERT_TRUE(ns_get_dlopened_string_addr > addr_start);
|
||||
ASSERT_TRUE(ns_get_dlopened_string_addr < addr_end);
|
||||
|
||||
// copy
|
||||
uintptr_t reserved_addr = reinterpret_cast<uintptr_t>(mmap(nullptr, addr_end - addr_start,
|
||||
PROT_NONE, MAP_ANON | MAP_PRIVATE,
|
||||
-1, 0));
|
||||
ASSERT_TRUE(reinterpret_cast<void*>(reserved_addr) != MAP_FAILED);
|
||||
|
||||
for (const auto& rec : maps_to_copy) {
|
||||
uintptr_t offset = rec.addr_start - addr_start;
|
||||
size_t size = rec.addr_end - rec.addr_start;
|
||||
void* addr = reinterpret_cast<void*>(reserved_addr + offset);
|
||||
void* map = mmap(addr, size, PROT_READ | PROT_WRITE,
|
||||
MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
|
||||
ASSERT_TRUE(map != MAP_FAILED);
|
||||
memcpy(map, reinterpret_cast<void*>(rec.addr_start), size);
|
||||
mprotect(map, size, rec.perms);
|
||||
}
|
||||
|
||||
// call the function copy
|
||||
uintptr_t ns_get_dlopened_string_offset = ns_get_dlopened_string_addr - addr_start;
|
||||
fn_t ns_get_dlopened_string_anon = reinterpret_cast<fn_t>(reserved_addr + ns_get_dlopened_string_offset);
|
||||
ASSERT_STREQ("This string is from private namespace (dlopened library)",
|
||||
ns_get_dlopened_string_anon());
|
||||
|
||||
// They should belong to different namespaces (private and anonymous)
|
||||
ASSERT_STREQ("This string is from private namespace (dlopened library)",
|
||||
ns_get_dlopened_string_private());
|
||||
|
||||
ASSERT_TRUE(ns_get_dlopened_string_anon() != ns_get_dlopened_string_private());
|
||||
}
|
||||
|
@ -40,10 +40,12 @@ extern "C" const char* ns_get_dlopened_string() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* result = *static_cast<const char**>(dlsym(handle, "g_private_dlopened_string"));
|
||||
if (result != nullptr) {
|
||||
const char** result = static_cast<const char**>(dlsym(handle, "g_private_dlopened_string"));
|
||||
if (result == nullptr) {
|
||||
return nullptr;
|
||||
} else {
|
||||
g_dlopened = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
return *result;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user