Introducing linker namespaces
Bug: http://b/22548808 Change-Id: Ia3af3c0a167f1d16447a3d83bb045d143319b1e1
This commit is contained in:
parent
ffe5c24c86
commit
42d5fcb9f4
26 changed files with 1122 additions and 152 deletions
|
@ -98,6 +98,11 @@ enum {
|
||||||
*/
|
*/
|
||||||
ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS = 0x100,
|
ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS = 0x100,
|
||||||
|
|
||||||
|
/* This flag used to load library in a different namespace. The namespace is
|
||||||
|
* specified in library_namespace.
|
||||||
|
*/
|
||||||
|
ANDROID_DLEXT_USE_NAMESPACE = 0x200,
|
||||||
|
|
||||||
/* Mask of valid bits */
|
/* Mask of valid bits */
|
||||||
ANDROID_DLEXT_VALID_FLAG_BITS = ANDROID_DLEXT_RESERVED_ADDRESS |
|
ANDROID_DLEXT_VALID_FLAG_BITS = ANDROID_DLEXT_RESERVED_ADDRESS |
|
||||||
ANDROID_DLEXT_RESERVED_ADDRESS_HINT |
|
ANDROID_DLEXT_RESERVED_ADDRESS_HINT |
|
||||||
|
@ -107,9 +112,12 @@ enum {
|
||||||
ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET |
|
ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET |
|
||||||
ANDROID_DLEXT_FORCE_LOAD |
|
ANDROID_DLEXT_FORCE_LOAD |
|
||||||
ANDROID_DLEXT_FORCE_FIXED_VADDR |
|
ANDROID_DLEXT_FORCE_FIXED_VADDR |
|
||||||
ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS,
|
ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS |
|
||||||
|
ANDROID_DLEXT_USE_NAMESPACE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct android_namespace_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint64_t flags;
|
uint64_t flags;
|
||||||
void* reserved_addr;
|
void* reserved_addr;
|
||||||
|
@ -117,10 +125,40 @@ typedef struct {
|
||||||
int relro_fd;
|
int relro_fd;
|
||||||
int library_fd;
|
int library_fd;
|
||||||
off64_t library_fd_offset;
|
off64_t library_fd_offset;
|
||||||
|
struct android_namespace_t* library_namespace;
|
||||||
} android_dlextinfo;
|
} android_dlextinfo;
|
||||||
|
|
||||||
extern void* android_dlopen_ext(const char* filename, int flag, const android_dlextinfo* extinfo);
|
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".
|
||||||
|
*
|
||||||
|
* The libraries in this list should be loaded prior to this call.
|
||||||
|
*/
|
||||||
|
extern bool android_init_public_namespace(const char* path);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Creates new linker namespace.
|
||||||
|
* ld_library_path and default_library_path represent the search path
|
||||||
|
* for the libraries in the namespace.
|
||||||
|
*
|
||||||
|
* The libraries in the namespace are searched by folowing order:
|
||||||
|
* 1. ld_library_path (Think of this as namespace-local LD_LIBRARY_PATH)
|
||||||
|
* 2. In directories specified by DT_RUNPATH of the "needed by" binary.
|
||||||
|
* 3. deault_library_path (This of this as namespace-local default library path)
|
||||||
|
*
|
||||||
|
* When is_isolated is true the resulted namespace requires all of the libraries
|
||||||
|
* to be on the search path; the search_path is ld_library_path:default_library_path.
|
||||||
|
*
|
||||||
|
* If a library or any of its dependencies are outside of the search path and not
|
||||||
|
* part of the public namespace dlopen will fail.
|
||||||
|
*/
|
||||||
|
extern struct android_namespace_t* android_create_namespace(const char* name,
|
||||||
|
const char* ld_library_path,
|
||||||
|
const char* default_library_path,
|
||||||
|
bool is_isolated);
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
#endif /* __ANDROID_DLEXT_H__ */
|
#endif /* __ANDROID_DLEXT_H__ */
|
||||||
|
|
|
@ -14,10 +14,16 @@ LIBC {
|
||||||
*;
|
*;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LIBC_N {
|
||||||
|
global:
|
||||||
|
android_init_public_namespace;
|
||||||
|
android_create_namespace;
|
||||||
|
} LIBC;
|
||||||
|
|
||||||
LIBC_PRIVATE {
|
LIBC_PRIVATE {
|
||||||
global:
|
global:
|
||||||
android_get_application_target_sdk_version;
|
android_get_application_target_sdk_version;
|
||||||
android_set_application_target_sdk_version;
|
android_set_application_target_sdk_version;
|
||||||
android_get_LD_LIBRARY_PATH;
|
android_get_LD_LIBRARY_PATH;
|
||||||
android_update_LD_LIBRARY_PATH;
|
android_update_LD_LIBRARY_PATH;
|
||||||
} LIBC;
|
} LIBC_N;
|
||||||
|
|
|
@ -13,10 +13,16 @@ LIBC {
|
||||||
*;
|
*;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LIBC_N {
|
||||||
|
global:
|
||||||
|
android_init_public_namespace;
|
||||||
|
android_create_namespace;
|
||||||
|
} LIBC;
|
||||||
|
|
||||||
LIBC_PRIVATE {
|
LIBC_PRIVATE {
|
||||||
global:
|
global:
|
||||||
android_get_application_target_sdk_version;
|
android_get_application_target_sdk_version;
|
||||||
android_set_application_target_sdk_version;
|
android_set_application_target_sdk_version;
|
||||||
android_get_LD_LIBRARY_PATH;
|
android_get_LD_LIBRARY_PATH;
|
||||||
android_update_LD_LIBRARY_PATH;
|
android_update_LD_LIBRARY_PATH;
|
||||||
} LIBC;
|
} LIBC_N;
|
||||||
|
|
|
@ -33,12 +33,26 @@ int dlclose(void* handle __unused) { return 0; }
|
||||||
_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc __unused, int* pcount __unused) { return 0; }
|
_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc __unused, int* pcount __unused) { return 0; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int dl_iterate_phdr(int (*cb)(struct dl_phdr_info* info, size_t size, void* data) __unused, void* data __unused) { return 0; }
|
int dl_iterate_phdr(int (*cb)(struct dl_phdr_info* info, size_t size, void* data) __unused,
|
||||||
|
void* data __unused) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void android_get_LD_LIBRARY_PATH(char* buffer __unused, size_t buffer_size __unused) { }
|
void android_get_LD_LIBRARY_PATH(char* buffer __unused, size_t buffer_size __unused) { }
|
||||||
void android_update_LD_LIBRARY_PATH(const char* ld_library_path __unused) { }
|
void android_update_LD_LIBRARY_PATH(const char* ld_library_path __unused) { }
|
||||||
|
|
||||||
void* android_dlopen_ext(const char* filename __unused, int flag __unused, const android_dlextinfo* extinfo __unused) { return 0; }
|
void* android_dlopen_ext(const char* filename __unused, int flag __unused,
|
||||||
|
const android_dlextinfo* extinfo __unused) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void android_set_application_target_sdk_version(uint32_t target __unused) { }
|
void android_set_application_target_sdk_version(uint32_t target __unused) { }
|
||||||
uint32_t android_get_application_target_sdk_version() { return 0; }
|
uint32_t android_get_application_target_sdk_version() { return 0; }
|
||||||
|
|
||||||
|
bool android_init_public_namespace(const char* paths __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,
|
||||||
|
bool isolated __unused) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -28,10 +28,16 @@ LIBC {
|
||||||
*;
|
*;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LIBC_N {
|
||||||
|
global:
|
||||||
|
android_init_public_namespace;
|
||||||
|
android_create_namespace;
|
||||||
|
} LIBC;
|
||||||
|
|
||||||
LIBC_PRIVATE {
|
LIBC_PRIVATE {
|
||||||
global:
|
global:
|
||||||
android_get_application_target_sdk_version;
|
android_get_application_target_sdk_version;
|
||||||
android_set_application_target_sdk_version;
|
android_set_application_target_sdk_version;
|
||||||
android_get_LD_LIBRARY_PATH;
|
android_get_LD_LIBRARY_PATH;
|
||||||
android_update_LD_LIBRARY_PATH;
|
android_update_LD_LIBRARY_PATH;
|
||||||
} LIBC;
|
} LIBC_N;
|
||||||
|
|
|
@ -13,10 +13,16 @@ LIBC {
|
||||||
*;
|
*;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LIBC_N {
|
||||||
|
global:
|
||||||
|
android_init_public_namespace;
|
||||||
|
android_create_namespace;
|
||||||
|
} LIBC;
|
||||||
|
|
||||||
LIBC_PRIVATE {
|
LIBC_PRIVATE {
|
||||||
global:
|
global:
|
||||||
android_get_application_target_sdk_version;
|
android_get_application_target_sdk_version;
|
||||||
android_set_application_target_sdk_version;
|
android_set_application_target_sdk_version;
|
||||||
android_get_LD_LIBRARY_PATH;
|
android_get_LD_LIBRARY_PATH;
|
||||||
android_update_LD_LIBRARY_PATH;
|
android_update_LD_LIBRARY_PATH;
|
||||||
} LIBC;
|
} LIBC_N;
|
||||||
|
|
|
@ -13,10 +13,16 @@ LIBC {
|
||||||
*;
|
*;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LIBC_N {
|
||||||
|
global:
|
||||||
|
android_init_public_namespace;
|
||||||
|
android_create_namespace;
|
||||||
|
} LIBC;
|
||||||
|
|
||||||
LIBC_PRIVATE {
|
LIBC_PRIVATE {
|
||||||
global:
|
global:
|
||||||
android_get_application_target_sdk_version;
|
android_get_application_target_sdk_version;
|
||||||
android_set_application_target_sdk_version;
|
android_set_application_target_sdk_version;
|
||||||
android_get_LD_LIBRARY_PATH;
|
android_get_LD_LIBRARY_PATH;
|
||||||
android_update_LD_LIBRARY_PATH;
|
android_update_LD_LIBRARY_PATH;
|
||||||
} LIBC;
|
} LIBC_N;
|
||||||
|
|
|
@ -13,10 +13,16 @@ LIBC {
|
||||||
*;
|
*;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LIBC_N {
|
||||||
|
global:
|
||||||
|
android_init_public_namespace;
|
||||||
|
android_create_namespace;
|
||||||
|
} LIBC;
|
||||||
|
|
||||||
LIBC_PRIVATE {
|
LIBC_PRIVATE {
|
||||||
global:
|
global:
|
||||||
android_get_application_target_sdk_version;
|
android_get_application_target_sdk_version;
|
||||||
android_set_application_target_sdk_version;
|
android_set_application_target_sdk_version;
|
||||||
android_get_LD_LIBRARY_PATH;
|
android_get_LD_LIBRARY_PATH;
|
||||||
android_update_LD_LIBRARY_PATH;
|
android_update_LD_LIBRARY_PATH;
|
||||||
} LIBC;
|
} LIBC_N;
|
||||||
|
|
|
@ -13,10 +13,16 @@ LIBC {
|
||||||
*;
|
*;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LIBC_N {
|
||||||
|
global:
|
||||||
|
android_init_public_namespace;
|
||||||
|
android_create_namespace;
|
||||||
|
} LIBC;
|
||||||
|
|
||||||
LIBC_PRIVATE {
|
LIBC_PRIVATE {
|
||||||
global:
|
global:
|
||||||
android_get_application_target_sdk_version;
|
android_get_application_target_sdk_version;
|
||||||
android_set_application_target_sdk_version;
|
android_set_application_target_sdk_version;
|
||||||
android_get_LD_LIBRARY_PATH;
|
android_get_LD_LIBRARY_PATH;
|
||||||
android_update_LD_LIBRARY_PATH;
|
android_update_LD_LIBRARY_PATH;
|
||||||
} LIBC;
|
} LIBC_N;
|
||||||
|
|
|
@ -9,12 +9,12 @@ LOCAL_SRC_FILES := \
|
||||||
dlfcn.cpp \
|
dlfcn.cpp \
|
||||||
linker.cpp \
|
linker.cpp \
|
||||||
linker_allocator.cpp \
|
linker_allocator.cpp \
|
||||||
linker_sdk_versions.cpp \
|
|
||||||
linker_block_allocator.cpp \
|
linker_block_allocator.cpp \
|
||||||
linker_libc_support.c \
|
linker_libc_support.c \
|
||||||
linker_mapped_file_fragment.cpp \
|
linker_mapped_file_fragment.cpp \
|
||||||
linker_memory.cpp \
|
linker_memory.cpp \
|
||||||
linker_phdr.cpp \
|
linker_phdr.cpp \
|
||||||
|
linker_sdk_versions.cpp \
|
||||||
linker_utils.cpp \
|
linker_utils.cpp \
|
||||||
rt.cpp \
|
rt.cpp \
|
||||||
|
|
||||||
|
|
|
@ -108,9 +108,16 @@ void* dlsym(void* handle, const char* symbol) {
|
||||||
const ElfW(Sym)* sym = nullptr;
|
const ElfW(Sym)* sym = nullptr;
|
||||||
void* caller_addr = __builtin_return_address(0);
|
void* caller_addr = __builtin_return_address(0);
|
||||||
soinfo* caller = find_containing_library(caller_addr);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
|
if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
|
||||||
sym = dlsym_linear_lookup(symbol, &found, caller, handle);
|
sym = dlsym_linear_lookup(caller->get_namespace(), symbol, &found, caller, handle);
|
||||||
} else {
|
} else {
|
||||||
sym = dlsym_handle_lookup(reinterpret_cast<soinfo*>(handle), &found, symbol);
|
sym = dlsym_handle_lookup(reinterpret_cast<soinfo*>(handle), &found, symbol);
|
||||||
}
|
}
|
||||||
|
@ -177,6 +184,30 @@ uint32_t android_get_application_target_sdk_version() {
|
||||||
return get_application_target_sdk_version();
|
return get_application_target_sdk_version();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool android_init_public_namespace(const char* path) {
|
||||||
|
ScopedPthreadMutexLocker locker(&g_dl_mutex);
|
||||||
|
bool success = init_public_namespace(path);
|
||||||
|
if (!success) {
|
||||||
|
__bionic_format_dlerror("android_init_public_namespace failed", linker_get_error_buffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
android_namespace_t* android_create_namespace(const char* name, const char* ld_library_path,
|
||||||
|
const char* default_library_path, bool is_isolated) {
|
||||||
|
ScopedPthreadMutexLocker locker(&g_dl_mutex);
|
||||||
|
|
||||||
|
android_namespace_t* result = create_namespace(name, ld_library_path,
|
||||||
|
default_library_path, is_isolated);
|
||||||
|
|
||||||
|
if (result == nullptr) {
|
||||||
|
__bionic_format_dlerror("android_create_namespace failed", linker_get_error_buffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// name_offset: starting index of the name in libdl_info.strtab
|
// name_offset: starting index of the name in libdl_info.strtab
|
||||||
#define ELF32_SYM_INITIALIZER(name_offset, value, shndx) \
|
#define ELF32_SYM_INITIALIZER(name_offset, value, shndx) \
|
||||||
{ name_offset, \
|
{ name_offset, \
|
||||||
|
@ -203,11 +234,11 @@ static const char ANDROID_LIBDL_STRTAB[] =
|
||||||
// 00000000001 1111111112222222222 3333333333444444444455555555556666666666777 777777788888888889999999999
|
// 00000000001 1111111112222222222 3333333333444444444455555555556666666666777 777777788888888889999999999
|
||||||
// 01234567890 1234567890123456789 0123456789012345678901234567890123456789012 345678901234567890123456789
|
// 01234567890 1234567890123456789 0123456789012345678901234567890123456789012 345678901234567890123456789
|
||||||
"erate_phdr\0android_dlopen_ext\0android_set_application_target_sdk_version\0android_get_application_tar"
|
"erate_phdr\0android_dlopen_ext\0android_set_application_target_sdk_version\0android_get_application_tar"
|
||||||
// 0000000000111111
|
// 0000000000111111 111122222222223333333333444444 4444555555555566666666667
|
||||||
// 0123456789012345
|
// 0123456789012345 678901234567890123456789012345 6789012345678901234567890
|
||||||
"get_sdk_version\0"
|
"get_sdk_version\0android_init_public_namespace\0android_create_namespace\0"
|
||||||
#if defined(__arm__)
|
#if defined(__arm__)
|
||||||
// 216
|
// 271
|
||||||
"dl_unwind_find_exidx\0"
|
"dl_unwind_find_exidx\0"
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
@ -229,8 +260,10 @@ static ElfW(Sym) g_libdl_symtab[] = {
|
||||||
ELFW(SYM_INITIALIZER)(111, &android_dlopen_ext, 1),
|
ELFW(SYM_INITIALIZER)(111, &android_dlopen_ext, 1),
|
||||||
ELFW(SYM_INITIALIZER)(130, &android_set_application_target_sdk_version, 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)(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),
|
||||||
#if defined(__arm__)
|
#if defined(__arm__)
|
||||||
ELFW(SYM_INITIALIZER)(216, &dl_unwind_find_exidx, 1),
|
ELFW(SYM_INITIALIZER)(271, &dl_unwind_find_exidx, 1),
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -247,18 +280,20 @@ static ElfW(Sym) g_libdl_symtab[] = {
|
||||||
// Note that adding any new symbols here requires stubbing them out in libdl.
|
// Note that adding any new symbols here requires stubbing them out in libdl.
|
||||||
static unsigned g_libdl_buckets[1] = { 1 };
|
static unsigned g_libdl_buckets[1] = { 1 };
|
||||||
#if defined(__arm__)
|
#if defined(__arm__)
|
||||||
static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0 };
|
static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0 };
|
||||||
#else
|
#else
|
||||||
static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0 };
|
static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0 };
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static uint8_t __libdl_info_buf[sizeof(soinfo)] __attribute__((aligned(8)));
|
static uint8_t __libdl_info_buf[sizeof(soinfo)] __attribute__((aligned(8)));
|
||||||
static soinfo* __libdl_info = nullptr;
|
static soinfo* __libdl_info = nullptr;
|
||||||
|
|
||||||
|
extern android_namespace_t g_default_namespace;
|
||||||
|
|
||||||
// This is used by the dynamic linker. Every process gets these symbols for free.
|
// This is used by the dynamic linker. Every process gets these symbols for free.
|
||||||
soinfo* get_libdl_info() {
|
soinfo* get_libdl_info() {
|
||||||
if (__libdl_info == nullptr) {
|
if (__libdl_info == nullptr) {
|
||||||
__libdl_info = new (__libdl_info_buf) soinfo("libdl.so", nullptr, 0, RTLD_GLOBAL);
|
__libdl_info = new (__libdl_info_buf) soinfo(&g_default_namespace, "libdl.so", nullptr, 0, RTLD_GLOBAL);
|
||||||
__libdl_info->flags_ |= FLAG_LINKED;
|
__libdl_info->flags_ |= FLAG_LINKED;
|
||||||
__libdl_info->strtab_ = ANDROID_LIBDL_STRTAB;
|
__libdl_info->strtab_ = ANDROID_LIBDL_STRTAB;
|
||||||
__libdl_info->symtab_ = g_libdl_symtab;
|
__libdl_info->symtab_ = g_libdl_symtab;
|
||||||
|
|
|
@ -25,12 +25,49 @@ struct LinkedListEntry {
|
||||||
T* element;
|
T* element;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ForwardInputIterator
|
||||||
|
template<typename T>
|
||||||
|
class LinkedListIterator {
|
||||||
|
public:
|
||||||
|
LinkedListIterator() : entry_(nullptr) {}
|
||||||
|
LinkedListIterator(const LinkedListIterator<T>& that) : entry_(that.entry_) {}
|
||||||
|
explicit LinkedListIterator(LinkedListEntry<T>* entry) : entry_(entry) {}
|
||||||
|
|
||||||
|
LinkedListIterator<T>& operator=(const LinkedListIterator<T>& that) {
|
||||||
|
entry_ = that.entry_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkedListIterator<T>& operator++() {
|
||||||
|
entry_ = entry_->next;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
T* operator*() {
|
||||||
|
return entry_->element;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const LinkedListIterator<T>& that) const {
|
||||||
|
return entry_ == that.entry_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const LinkedListIterator<T>& that) const {
|
||||||
|
return entry_ != that.entry_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
LinkedListEntry<T> *entry_;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Represents linked list of objects of type T
|
* Represents linked list of objects of type T
|
||||||
*/
|
*/
|
||||||
template<typename T, typename Allocator>
|
template<typename T, typename Allocator>
|
||||||
class LinkedList {
|
class LinkedList {
|
||||||
public:
|
public:
|
||||||
|
typedef LinkedListIterator<T> iterator;
|
||||||
|
typedef T* value_type;
|
||||||
|
|
||||||
LinkedList() : head_(nullptr), tail_(nullptr) {}
|
LinkedList() : head_(nullptr), tail_(nullptr) {}
|
||||||
~LinkedList() {
|
~LinkedList() {
|
||||||
clear();
|
clear();
|
||||||
|
@ -133,6 +170,7 @@ class LinkedList {
|
||||||
}
|
}
|
||||||
|
|
||||||
Allocator::free(e);
|
Allocator::free(e);
|
||||||
|
|
||||||
e = next;
|
e = next;
|
||||||
} else {
|
} else {
|
||||||
p = e;
|
p = e;
|
||||||
|
@ -152,6 +190,24 @@ class LinkedList {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iterator begin() {
|
||||||
|
return iterator(head_);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator end() {
|
||||||
|
return iterator(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator find(T* value) {
|
||||||
|
for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) {
|
||||||
|
if (e->element == value) {
|
||||||
|
return iterator(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
|
||||||
size_t copy_to_array(T* array[], size_t array_length) const {
|
size_t copy_to_array(T* array[], size_t array_length) const {
|
||||||
size_t sz = 0;
|
size_t sz = 0;
|
||||||
for (LinkedListEntry<T>* e = head_; sz < array_length && e != nullptr; e = e->next) {
|
for (LinkedListEntry<T>* e = head_; sz < array_length && e != nullptr; e = e->next) {
|
||||||
|
|
|
@ -70,11 +70,55 @@ extern void __libc_init_AT_SECURE(KernelArgumentBlock&);
|
||||||
#undef ELF_ST_TYPE
|
#undef ELF_ST_TYPE
|
||||||
#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
|
#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
|
||||||
|
|
||||||
|
struct android_namespace_t {
|
||||||
|
public:
|
||||||
|
android_namespace_t() : name_(nullptr), is_isolated_(false) {}
|
||||||
|
|
||||||
|
const char* get_name() const { return name_; }
|
||||||
|
void set_name(const char* name) { name_ = name; }
|
||||||
|
|
||||||
|
bool is_isolated() const { return is_isolated_; }
|
||||||
|
void set_isolated(bool isolated) { is_isolated_ = isolated; }
|
||||||
|
|
||||||
|
const std::vector<std::string>& get_ld_library_paths() const {
|
||||||
|
return ld_library_paths_;
|
||||||
|
}
|
||||||
|
void set_ld_library_paths(std::vector<std::string>&& library_paths) {
|
||||||
|
ld_library_paths_ = library_paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<std::string>& get_default_library_paths() const {
|
||||||
|
return default_library_paths_;
|
||||||
|
}
|
||||||
|
void set_default_library_paths(std::vector<std::string>&& library_paths) {
|
||||||
|
default_library_paths_ = library_paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
soinfo::soinfo_list_t& soinfo_list() { return soinfo_list_; }
|
||||||
|
|
||||||
|
// For isolated namespaces - checks if the file is on the search path;
|
||||||
|
// always returns true for not isolated namespace.
|
||||||
|
bool is_accessible(const std::string& path);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* name_;
|
||||||
|
bool is_isolated_;
|
||||||
|
std::vector<std::string> ld_library_paths_;
|
||||||
|
std::vector<std::string> default_library_paths_;
|
||||||
|
soinfo::soinfo_list_t soinfo_list_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(android_namespace_t);
|
||||||
|
};
|
||||||
|
|
||||||
|
android_namespace_t g_default_namespace;
|
||||||
|
|
||||||
static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
|
static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
|
||||||
|
|
||||||
static LinkerTypeAllocator<soinfo> g_soinfo_allocator;
|
static LinkerTypeAllocator<soinfo> g_soinfo_allocator;
|
||||||
static LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
|
static LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
|
||||||
|
|
||||||
|
static LinkerTypeAllocator<android_namespace_t> g_namespace_allocator;
|
||||||
|
|
||||||
static soinfo* solist;
|
static soinfo* solist;
|
||||||
static soinfo* sonext;
|
static soinfo* sonext;
|
||||||
static soinfo* somain; // main process, always the one after libdl_info
|
static soinfo* somain; // main process, always the one after libdl_info
|
||||||
|
@ -107,14 +151,15 @@ static const char* const kAsanDefaultLdPaths[] = {
|
||||||
|
|
||||||
static const ElfW(Versym) kVersymNotNeeded = 0;
|
static const ElfW(Versym) kVersymNotNeeded = 0;
|
||||||
static const ElfW(Versym) kVersymGlobal = 1;
|
static const ElfW(Versym) kVersymGlobal = 1;
|
||||||
static const char* const kZipFileSeparator = "!/";
|
|
||||||
|
|
||||||
static const char* const* g_default_ld_paths;
|
static const char* const* g_default_ld_paths;
|
||||||
static std::vector<std::string> g_ld_library_paths;
|
|
||||||
static std::vector<std::string> g_ld_preload_names;
|
static std::vector<std::string> g_ld_preload_names;
|
||||||
|
|
||||||
static std::vector<soinfo*> g_ld_preloads;
|
static std::vector<soinfo*> g_ld_preloads;
|
||||||
|
|
||||||
|
static bool g_public_namespace_initialized;
|
||||||
|
static soinfo::soinfo_list_t g_public_namespace;
|
||||||
|
|
||||||
__LIBC_HIDDEN__ int g_ld_debug_verbosity;
|
__LIBC_HIDDEN__ int g_ld_debug_verbosity;
|
||||||
|
|
||||||
__LIBC_HIDDEN__ abort_msg_t* g_abort_message = nullptr; // For debuggerd.
|
__LIBC_HIDDEN__ abort_msg_t* g_abort_message = nullptr; // For debuggerd.
|
||||||
|
@ -247,6 +292,26 @@ void notify_gdb_of_libraries() {
|
||||||
rtld_db_dlactivity();
|
rtld_db_dlactivity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool android_namespace_t::is_accessible(const std::string& file) {
|
||||||
|
if (!is_isolated_) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& dir : ld_library_paths_) {
|
||||||
|
if (file_is_in_dir(file, dir)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& dir : default_library_paths_) {
|
||||||
|
if (file_is_in_dir(file, dir)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
LinkedListEntry<soinfo>* SoinfoListAllocator::alloc() {
|
LinkedListEntry<soinfo>* SoinfoListAllocator::alloc() {
|
||||||
return g_soinfo_links_allocator.alloc();
|
return g_soinfo_links_allocator.alloc();
|
||||||
}
|
}
|
||||||
|
@ -255,18 +320,22 @@ void SoinfoListAllocator::free(LinkedListEntry<soinfo>* entry) {
|
||||||
g_soinfo_links_allocator.free(entry);
|
g_soinfo_links_allocator.free(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
static soinfo* soinfo_alloc(const char* name, struct stat* file_stat,
|
static soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
|
||||||
off64_t file_offset, uint32_t rtld_flags) {
|
struct stat* file_stat, off64_t file_offset,
|
||||||
|
uint32_t rtld_flags) {
|
||||||
if (strlen(name) >= PATH_MAX) {
|
if (strlen(name) >= PATH_MAX) {
|
||||||
DL_ERR("library name \"%s\" too long", name);
|
DL_ERR("library name \"%s\" too long", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat, file_offset, rtld_flags);
|
soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(ns, name, file_stat,
|
||||||
|
file_offset, rtld_flags);
|
||||||
|
|
||||||
sonext->next = si;
|
sonext->next = si;
|
||||||
sonext = si;
|
sonext = si;
|
||||||
|
|
||||||
|
ns->soinfo_list().push_back(si);
|
||||||
|
|
||||||
TRACE("name %s: allocated soinfo @ %p", name, si);
|
TRACE("name %s: allocated soinfo @ %p", name, si);
|
||||||
return si;
|
return si;
|
||||||
}
|
}
|
||||||
|
@ -307,33 +376,130 @@ static void soinfo_free(soinfo* si) {
|
||||||
sonext = prev;
|
sonext = prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove from the namespace
|
||||||
|
si->get_namespace()->soinfo_list().remove_if([&](soinfo* candidate) {
|
||||||
|
return si == candidate;
|
||||||
|
});
|
||||||
|
|
||||||
si->~soinfo();
|
si->~soinfo();
|
||||||
g_soinfo_allocator.free(si);
|
g_soinfo_allocator.free(si);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_path(const char* path, const char* delimiters,
|
// For every path element this function checks of it exists, and is a directory,
|
||||||
|
// and normalizes it:
|
||||||
|
// 1. For regular path it converts it to realpath()
|
||||||
|
// 2. For path in a zip file it uses realpath on the zipfile
|
||||||
|
// normalizes entry name by calling normalize_path function.
|
||||||
|
static void resolve_paths(std::vector<std::string>& paths,
|
||||||
|
std::vector<std::string>* resolved_paths) {
|
||||||
|
resolved_paths->clear();
|
||||||
|
for (const auto& path : paths) {
|
||||||
|
char resolved_path[PATH_MAX];
|
||||||
|
const char* original_path = path.c_str();
|
||||||
|
if (realpath(original_path, resolved_path) != nullptr) {
|
||||||
|
struct stat s;
|
||||||
|
if (stat(resolved_path, &s) == 0) {
|
||||||
|
if (S_ISDIR(s.st_mode)) {
|
||||||
|
resolved_paths->push_back(resolved_path);
|
||||||
|
} else {
|
||||||
|
DL_WARN("Warning: \"%s\" is not a directory (excluding from path)", resolved_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DL_WARN("Warning: cannot stat file \"%s\": %s", resolved_path, strerror(errno));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::string zip_path;
|
||||||
|
std::string entry_path;
|
||||||
|
|
||||||
|
std::string normalized_path;
|
||||||
|
|
||||||
|
if (!normalize_path(original_path, &normalized_path)) {
|
||||||
|
DL_WARN("Warning: unable to normalize \"%s\"", original_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parse_zip_path(normalized_path.c_str(), &zip_path, &entry_path)) {
|
||||||
|
if (realpath(zip_path.c_str(), resolved_path) == nullptr) {
|
||||||
|
DL_WARN("Warning: unable to resolve \"%s\": %s", zip_path.c_str(), strerror(errno));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZipArchiveHandle handle = nullptr;
|
||||||
|
if (OpenArchive(resolved_path, &handle) != 0) {
|
||||||
|
DL_WARN("Warning: unable to open zip archive: %s", resolved_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if zip-file has a dir with entry_path name
|
||||||
|
void* cookie = nullptr;
|
||||||
|
std::string prefix_str = entry_path + "/";
|
||||||
|
ZipString prefix(prefix_str.c_str());
|
||||||
|
|
||||||
|
ZipEntry out_data;
|
||||||
|
ZipString out_name;
|
||||||
|
|
||||||
|
int32_t error_code;
|
||||||
|
|
||||||
|
if ((error_code = StartIteration(handle, &cookie, &prefix, nullptr)) != 0) {
|
||||||
|
DL_WARN("Unable to iterate over zip-archive entries \"%s\";"
|
||||||
|
" error code: %d", zip_path.c_str(), error_code);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Next(cookie, &out_data, &out_name) != 0) {
|
||||||
|
DL_WARN("Unable to find entries starting with \"%s\" in \"%s\"",
|
||||||
|
prefix_str.c_str(), zip_path.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto zip_guard = make_scope_guard([&]() {
|
||||||
|
if (cookie != nullptr) {
|
||||||
|
EndIteration(cookie);
|
||||||
|
}
|
||||||
|
CloseArchive(handle);
|
||||||
|
});
|
||||||
|
|
||||||
|
resolved_paths->push_back(std::string(resolved_path) + kZipFileSeparator + entry_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void split_path(const char* path, const char* delimiters,
|
||||||
std::vector<std::string>* paths) {
|
std::vector<std::string>* paths) {
|
||||||
paths->clear();
|
|
||||||
if (path != nullptr) {
|
if (path != nullptr) {
|
||||||
*paths = android::base::Split(path, delimiters);
|
*paths = android::base::Split(path, delimiters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void parse_path(const char* path, const char* delimiters,
|
||||||
|
std::vector<std::string>* resolved_paths) {
|
||||||
|
std::vector<std::string> paths;
|
||||||
|
split_path(path, delimiters, &paths);
|
||||||
|
resolve_paths(paths, resolved_paths);
|
||||||
|
}
|
||||||
|
|
||||||
static void parse_LD_LIBRARY_PATH(const char* path) {
|
static void parse_LD_LIBRARY_PATH(const char* path) {
|
||||||
parse_path(path, ":", &g_ld_library_paths);
|
std::vector<std::string> ld_libary_paths;
|
||||||
|
parse_path(path, ":", &ld_libary_paths);
|
||||||
|
g_default_namespace.set_ld_library_paths(std::move(ld_libary_paths));
|
||||||
}
|
}
|
||||||
|
|
||||||
void soinfo::set_dt_runpath(const char* path) {
|
void soinfo::set_dt_runpath(const char* path) {
|
||||||
if (!has_min_version(2)) {
|
if (!has_min_version(3)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_path(path, ":", &dt_runpath_);
|
std::vector<std::string> runpaths;
|
||||||
|
|
||||||
|
split_path(path, ":", &runpaths);
|
||||||
|
|
||||||
std::string origin = dirname(get_realpath());
|
std::string origin = dirname(get_realpath());
|
||||||
// FIXME: add $LIB and $PLATFORM.
|
// FIXME: add $LIB and $PLATFORM.
|
||||||
std::pair<std::string, std::string> substs[] = {{"ORIGIN", origin}};
|
std::pair<std::string, std::string> substs[] = {{"ORIGIN", origin}};
|
||||||
for (auto&& s : dt_runpath_) {
|
for (auto&& s : runpaths) {
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
while (pos < s.size()) {
|
while (pos < s.size()) {
|
||||||
pos = s.find("$", pos);
|
pos = s.find("$", pos);
|
||||||
|
@ -356,11 +522,16 @@ void soinfo::set_dt_runpath(const char* path) {
|
||||||
++pos;
|
++pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolve_paths(runpaths, &dt_runpath_);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_LD_PRELOAD(const char* path) {
|
static void parse_LD_PRELOAD(const char* path) {
|
||||||
// We have historically supported ':' as well as ' ' in LD_PRELOAD.
|
g_ld_preload_names.clear();
|
||||||
parse_path(path, " :", &g_ld_preload_names);
|
if (path != nullptr) {
|
||||||
|
// We have historically supported ':' as well as ' ' in LD_PRELOAD.
|
||||||
|
g_ld_preload_names = android::base::Split(path, " :");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool realpath_fd(int fd, std::string* realpath) {
|
static bool realpath_fd(int fd, std::string* realpath) {
|
||||||
|
@ -688,8 +859,9 @@ bool soinfo::elf_lookup(SymbolName& symbol_name,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
soinfo::soinfo(const char* realpath, const struct stat* file_stat,
|
soinfo::soinfo(android_namespace_t* ns, const char* realpath,
|
||||||
off64_t file_offset, int rtld_flags) {
|
const struct stat* file_stat, off64_t file_offset,
|
||||||
|
int rtld_flags) {
|
||||||
memset(this, 0, sizeof(*this));
|
memset(this, 0, sizeof(*this));
|
||||||
|
|
||||||
if (realpath != nullptr) {
|
if (realpath != nullptr) {
|
||||||
|
@ -706,6 +878,7 @@ soinfo::soinfo(const char* realpath, const struct stat* file_stat,
|
||||||
}
|
}
|
||||||
|
|
||||||
this->rtld_flags_ = rtld_flags;
|
this->rtld_flags_ = rtld_flags;
|
||||||
|
this->namespace_ = ns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -857,6 +1030,7 @@ class ProtectedDataGuard {
|
||||||
void protect_data(int protection) {
|
void protect_data(int protection) {
|
||||||
g_soinfo_allocator.protect_all(protection);
|
g_soinfo_allocator.protect_all(protection);
|
||||||
g_soinfo_links_allocator.protect_all(protection);
|
g_soinfo_links_allocator.protect_all(protection);
|
||||||
|
g_namespace_allocator.protect_all(protection);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t ref_count_;
|
static size_t ref_count_;
|
||||||
|
@ -1096,7 +1270,7 @@ const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* nam
|
||||||
// libraries and they are loaded in breath-first (correct) order we can just execute
|
// libraries and they are loaded in breath-first (correct) order we can just execute
|
||||||
// dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
|
// dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
|
||||||
if (si == somain) {
|
if (si == somain) {
|
||||||
return dlsym_linear_lookup(name, found, nullptr, RTLD_DEFAULT);
|
return dlsym_linear_lookup(&g_default_namespace, name, found, nullptr, RTLD_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolName symbol_name(name);
|
SymbolName symbol_name(name);
|
||||||
|
@ -1108,24 +1282,29 @@ const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* nam
|
||||||
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).
|
||||||
*/
|
*/
|
||||||
const ElfW(Sym)* dlsym_linear_lookup(const char* name,
|
const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
|
||||||
|
const char* name,
|
||||||
soinfo** found,
|
soinfo** found,
|
||||||
soinfo* caller,
|
soinfo* caller,
|
||||||
void* handle) {
|
void* handle) {
|
||||||
SymbolName symbol_name(name);
|
SymbolName symbol_name(name);
|
||||||
|
|
||||||
soinfo* start = solist;
|
soinfo::soinfo_list_t& soinfo_list = ns->soinfo_list();
|
||||||
|
soinfo::soinfo_list_t::iterator start = soinfo_list.begin();
|
||||||
|
|
||||||
if (handle == RTLD_NEXT) {
|
if (handle == RTLD_NEXT) {
|
||||||
if (caller == nullptr) {
|
if (caller == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
} else {
|
} else {
|
||||||
start = caller->next;
|
soinfo::soinfo_list_t::iterator it = soinfo_list.find(caller);
|
||||||
|
CHECK (it != soinfo_list.end());
|
||||||
|
start = ++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ElfW(Sym)* s = nullptr;
|
const ElfW(Sym)* s = nullptr;
|
||||||
for (soinfo* si = start; si != nullptr; si = si->next) {
|
for (soinfo::soinfo_list_t::iterator it = start, end = soinfo_list.end(); it != end; ++it) {
|
||||||
|
soinfo* si = *it;
|
||||||
// Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...)
|
// Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...)
|
||||||
// if the library is opened by application with target api level <= 22
|
// if the library is opened by application with target api level <= 22
|
||||||
// See http://b/21565766
|
// See http://b/21565766
|
||||||
|
@ -1337,35 +1516,13 @@ static bool format_path(char* buf, size_t buf_size, const char* path, const char
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int open_library_on_default_path(const char* name, off64_t* file_offset, std::string* realpath) {
|
|
||||||
for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
|
|
||||||
char buf[512];
|
|
||||||
if (!format_path(buf, sizeof(buf), g_default_ld_paths[i], name)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
|
|
||||||
if (fd != -1) {
|
|
||||||
*file_offset = 0;
|
|
||||||
if (!realpath_fd(fd, realpath)) {
|
|
||||||
PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf);
|
|
||||||
*realpath = buf;
|
|
||||||
}
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int open_library_on_paths(ZipArchiveCache* zip_archive_cache,
|
static int open_library_on_paths(ZipArchiveCache* zip_archive_cache,
|
||||||
const char* name, off64_t* file_offset,
|
const char* name, off64_t* file_offset,
|
||||||
const std::vector<std::string>& paths,
|
const std::vector<std::string>& paths,
|
||||||
std::string* realpath) {
|
std::string* realpath) {
|
||||||
for (const auto& path_str : paths) {
|
for (const auto& path : paths) {
|
||||||
char buf[512];
|
char buf[512];
|
||||||
const char* const path = path_str.c_str();
|
if (!format_path(buf, sizeof(buf), path.c_str(), name)) {
|
||||||
if (!format_path(buf, sizeof(buf), path, name)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1393,39 +1550,49 @@ static int open_library_on_paths(ZipArchiveCache* zip_archive_cache,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int open_library(ZipArchiveCache* zip_archive_cache,
|
static int open_library(android_namespace_t* ns,
|
||||||
|
ZipArchiveCache* zip_archive_cache,
|
||||||
const char* name, soinfo *needed_by,
|
const char* name, soinfo *needed_by,
|
||||||
off64_t* file_offset, std::string* realpath) {
|
off64_t* file_offset, std::string* realpath) {
|
||||||
TRACE("[ opening %s ]", name);
|
TRACE("[ opening %s ]", name);
|
||||||
|
|
||||||
// If the name contains a slash, we should attempt to open it directly and not search the paths.
|
// If the name contains a slash, we should attempt to open it directly and not search the paths.
|
||||||
if (strchr(name, '/') != nullptr) {
|
if (strchr(name, '/') != nullptr) {
|
||||||
|
int fd = -1;
|
||||||
|
|
||||||
if (strstr(name, kZipFileSeparator) != nullptr) {
|
if (strstr(name, kZipFileSeparator) != nullptr) {
|
||||||
int fd = open_library_in_zipfile(zip_archive_cache, name, file_offset, realpath);
|
fd = open_library_in_zipfile(zip_archive_cache, name, file_offset, realpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fd == -1) {
|
||||||
|
fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
|
||||||
if (fd != -1) {
|
if (fd != -1) {
|
||||||
return fd;
|
*file_offset = 0;
|
||||||
|
if (!realpath_fd(fd, realpath)) {
|
||||||
|
PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", name);
|
||||||
|
*realpath = name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
|
if (fd != -1 && !ns->is_accessible(*realpath)) {
|
||||||
if (fd != -1) {
|
fd = -1;
|
||||||
*file_offset = 0;
|
|
||||||
if (!realpath_fd(fd, realpath)) {
|
|
||||||
PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", name);
|
|
||||||
*realpath = name;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise we try LD_LIBRARY_PATH first, and fall back to the built-in well known paths.
|
// Otherwise we try LD_LIBRARY_PATH first, and fall back to the default library path
|
||||||
int fd = open_library_on_paths(zip_archive_cache, name, file_offset, g_ld_library_paths, realpath);
|
int fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_ld_library_paths(), realpath);
|
||||||
if (fd == -1 && needed_by != nullptr) {
|
if (fd == -1 && needed_by != nullptr) {
|
||||||
fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath);
|
fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath);
|
||||||
|
// Check if the library is accessible
|
||||||
|
if (fd != -1 && !ns->is_accessible(*realpath)) {
|
||||||
|
fd = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
fd = open_library_on_default_path(name, file_offset, realpath);
|
fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_default_library_paths(), realpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
|
@ -1464,7 +1631,8 @@ static void for_each_dt_needed(const ElfReader& elf_reader, F action) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool load_library(LoadTask* task,
|
static bool load_library(android_namespace_t* ns,
|
||||||
|
LoadTask* task,
|
||||||
LoadTaskList* load_tasks,
|
LoadTaskList* load_tasks,
|
||||||
int rtld_flags,
|
int rtld_flags,
|
||||||
const std::string& realpath) {
|
const std::string& realpath) {
|
||||||
|
@ -1495,18 +1663,30 @@ static bool load_library(LoadTask* task,
|
||||||
// Check for symlink and other situations where
|
// Check for symlink and other situations where
|
||||||
// file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
|
// file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
|
||||||
if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
|
if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
|
||||||
for (soinfo* si = solist; si != nullptr; si = si->next) {
|
auto predicate = [&](soinfo* si) {
|
||||||
if (si->get_st_dev() != 0 &&
|
return si->get_st_dev() != 0 &&
|
||||||
si->get_st_ino() != 0 &&
|
si->get_st_ino() != 0 &&
|
||||||
si->get_st_dev() == file_stat.st_dev &&
|
si->get_st_dev() == file_stat.st_dev &&
|
||||||
si->get_st_ino() == file_stat.st_ino &&
|
si->get_st_ino() == file_stat.st_ino &&
|
||||||
si->get_file_offset() == file_offset) {
|
si->get_file_offset() == file_offset;
|
||||||
TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
|
};
|
||||||
"will return existing soinfo", name, si->get_realpath());
|
|
||||||
task->set_soinfo(si);
|
soinfo* si = ns->soinfo_list().find_if(predicate);
|
||||||
return true;
|
|
||||||
|
// check public namespace
|
||||||
|
if (si == nullptr) {
|
||||||
|
si = g_public_namespace.find_if(predicate);
|
||||||
|
if (si != nullptr) {
|
||||||
|
ns->soinfo_list().push_back(si);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (si != nullptr) {
|
||||||
|
TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
|
||||||
|
"will return existing soinfo", name, si->get_realpath());
|
||||||
|
task->set_soinfo(si);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((rtld_flags & RTLD_NOLOAD) != 0) {
|
if ((rtld_flags & RTLD_NOLOAD) != 0) {
|
||||||
|
@ -1514,7 +1694,7 @@ static bool load_library(LoadTask* task,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
soinfo* si = soinfo_alloc(realpath.c_str(), &file_stat, file_offset, rtld_flags);
|
soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
|
||||||
if (si == nullptr) {
|
if (si == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1550,7 +1730,8 @@ static bool load_library(LoadTask* task,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool load_library(LoadTask* task,
|
static bool load_library(android_namespace_t* ns,
|
||||||
|
LoadTask* task,
|
||||||
ZipArchiveCache* zip_archive_cache,
|
ZipArchiveCache* zip_archive_cache,
|
||||||
LoadTaskList* load_tasks,
|
LoadTaskList* load_tasks,
|
||||||
int rtld_flags) {
|
int rtld_flags) {
|
||||||
|
@ -1574,11 +1755,11 @@ static bool load_library(LoadTask* task,
|
||||||
|
|
||||||
task->set_fd(extinfo->library_fd, false);
|
task->set_fd(extinfo->library_fd, false);
|
||||||
task->set_file_offset(file_offset);
|
task->set_file_offset(file_offset);
|
||||||
return load_library(task, load_tasks, rtld_flags, realpath);
|
return load_library(ns, task, load_tasks, rtld_flags, realpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the file.
|
// Open the file.
|
||||||
int fd = open_library(zip_archive_cache, name, needed_by, &file_offset, &realpath);
|
int fd = open_library(ns, zip_archive_cache, name, needed_by, &file_offset, &realpath);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
DL_ERR("library \"%s\" not found", name);
|
DL_ERR("library \"%s\" not found", name);
|
||||||
return false;
|
return false;
|
||||||
|
@ -1587,14 +1768,15 @@ static bool load_library(LoadTask* task,
|
||||||
task->set_fd(fd, true);
|
task->set_fd(fd, true);
|
||||||
task->set_file_offset(file_offset);
|
task->set_file_offset(file_offset);
|
||||||
|
|
||||||
return load_library(task, load_tasks, rtld_flags, realpath);
|
return load_library(ns, task, load_tasks, rtld_flags, realpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if library was found and false in 2 cases
|
// Returns true if library was found and false in 2 cases
|
||||||
// 1. The library was found but loaded under different target_sdk_version
|
// 1. (for default namespace only) The library was found but loaded under different
|
||||||
// (*candidate != nullptr)
|
// target_sdk_version (*candidate != nullptr)
|
||||||
// 2. The library was not found by soname (*candidate is nullptr)
|
// 2. The library was not found by soname (*candidate is nullptr)
|
||||||
static bool find_loaded_library_by_soname(const char* name, soinfo** candidate) {
|
static bool find_loaded_library_by_soname(android_namespace_t* ns,
|
||||||
|
const char* name, soinfo** candidate) {
|
||||||
*candidate = nullptr;
|
*candidate = nullptr;
|
||||||
|
|
||||||
// Ignore filename with path.
|
// Ignore filename with path.
|
||||||
|
@ -1604,7 +1786,7 @@ static bool find_loaded_library_by_soname(const char* name, soinfo** candidate)
|
||||||
|
|
||||||
uint32_t target_sdk_version = get_application_target_sdk_version();
|
uint32_t target_sdk_version = get_application_target_sdk_version();
|
||||||
|
|
||||||
for (soinfo* si = solist; si != nullptr; si = si->next) {
|
return !ns->soinfo_list().visit([&](soinfo* si) {
|
||||||
const char* soname = si->get_soname();
|
const char* soname = si->get_soname();
|
||||||
if (soname != nullptr && (strcmp(name, soname) == 0)) {
|
if (soname != nullptr && (strcmp(name, soname) == 0)) {
|
||||||
// If the library was opened under different target sdk version
|
// If the library was opened under different target sdk version
|
||||||
|
@ -1614,36 +1796,52 @@ static bool find_loaded_library_by_soname(const char* name, soinfo** candidate)
|
||||||
// in any case.
|
// in any case.
|
||||||
bool is_libdl = si == solist;
|
bool is_libdl = si == solist;
|
||||||
if (is_libdl || (si->get_dt_flags_1() & DF_1_GLOBAL) != 0 ||
|
if (is_libdl || (si->get_dt_flags_1() & DF_1_GLOBAL) != 0 ||
|
||||||
!si->is_linked() || si->get_target_sdk_version() == target_sdk_version) {
|
!si->is_linked() || si->get_target_sdk_version() == target_sdk_version ||
|
||||||
|
ns != &g_default_namespace) {
|
||||||
*candidate = si;
|
*candidate = si;
|
||||||
return true;
|
return false;
|
||||||
} else if (*candidate == nullptr) {
|
} else if (*candidate == nullptr) {
|
||||||
// for the different sdk version - remember the first library.
|
// for the different sdk version in the default namespace
|
||||||
|
// remember the first library.
|
||||||
*candidate = si;
|
*candidate = si;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool find_library_internal(LoadTask* task,
|
static bool find_library_internal(android_namespace_t* ns,
|
||||||
|
LoadTask* task,
|
||||||
ZipArchiveCache* zip_archive_cache,
|
ZipArchiveCache* zip_archive_cache,
|
||||||
LoadTaskList* load_tasks,
|
LoadTaskList* load_tasks,
|
||||||
int rtld_flags) {
|
int rtld_flags) {
|
||||||
soinfo* candidate;
|
soinfo* candidate;
|
||||||
|
|
||||||
if (find_loaded_library_by_soname(task->get_name(), &candidate)) {
|
if (find_loaded_library_by_soname(ns, task->get_name(), &candidate)) {
|
||||||
task->set_soinfo(candidate);
|
task->set_soinfo(candidate);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ns != &g_default_namespace) {
|
||||||
|
// check public namespace
|
||||||
|
candidate = g_public_namespace.find_if([&](soinfo* si) {
|
||||||
|
return strcmp(task->get_name(), si->get_soname()) == 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (candidate != nullptr) {
|
||||||
|
ns->soinfo_list().push_back(candidate);
|
||||||
|
task->set_soinfo(candidate);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Library might still be loaded, the accurate detection
|
// Library might still be loaded, the accurate detection
|
||||||
// of this fact is done by load_library.
|
// of this fact is done by load_library.
|
||||||
TRACE("[ '%s' find_loaded_library_by_soname returned false (*candidate=%s@%p). Trying harder...]",
|
TRACE("[ '%s' find_loaded_library_by_soname returned false (*candidate=%s@%p). Trying harder...]",
|
||||||
task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
|
task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
|
||||||
|
|
||||||
if (load_library(task, zip_archive_cache, load_tasks, rtld_flags)) {
|
if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags)) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
// In case we were unable to load the library but there
|
// In case we were unable to load the library but there
|
||||||
|
@ -1667,13 +1865,13 @@ static void soinfo_unload(soinfo* si);
|
||||||
//
|
//
|
||||||
// This group consists of the main executable, LD_PRELOADs
|
// This group consists of the main executable, LD_PRELOADs
|
||||||
// and libraries with the DF_1_GLOBAL flag set.
|
// and libraries with the DF_1_GLOBAL flag set.
|
||||||
static soinfo::soinfo_list_t make_global_group() {
|
static soinfo::soinfo_list_t make_global_group(android_namespace_t* ns) {
|
||||||
soinfo::soinfo_list_t global_group;
|
soinfo::soinfo_list_t global_group;
|
||||||
for (soinfo* si = somain; si != nullptr; si = si->next) {
|
ns->soinfo_list().for_each([&](soinfo* si) {
|
||||||
if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
|
if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
|
||||||
global_group.push_back(si);
|
global_group.push_back(si);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
return global_group;
|
return global_group;
|
||||||
}
|
}
|
||||||
|
@ -1690,7 +1888,8 @@ static void shuffle(std::vector<LoadTask*>* v) {
|
||||||
// not their transitive dependencies) as children of the start_with library.
|
// not their transitive dependencies) as children of the start_with library.
|
||||||
// This is false when find_libraries is called for dlopen(), when newly loaded
|
// This is false when find_libraries is called for dlopen(), when newly loaded
|
||||||
// libraries must form a disjoint tree.
|
// libraries must form a disjoint tree.
|
||||||
static bool find_libraries(soinfo* start_with,
|
static bool find_libraries(android_namespace_t* ns,
|
||||||
|
soinfo* start_with,
|
||||||
const char* const library_names[],
|
const char* const library_names[],
|
||||||
size_t library_names_count, soinfo* soinfos[],
|
size_t library_names_count, soinfo* soinfos[],
|
||||||
std::vector<soinfo*>* ld_preloads,
|
std::vector<soinfo*>* ld_preloads,
|
||||||
|
@ -1707,7 +1906,7 @@ static bool find_libraries(soinfo* start_with,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct global_group.
|
// Construct global_group.
|
||||||
soinfo::soinfo_list_t global_group = make_global_group();
|
soinfo::soinfo_list_t global_group = make_global_group(ns);
|
||||||
|
|
||||||
// If soinfos array is null allocate one on stack.
|
// If soinfos array is null allocate one on stack.
|
||||||
// The array is needed in case of failure; for example
|
// The array is needed in case of failure; for example
|
||||||
|
@ -1749,7 +1948,7 @@ static bool find_libraries(soinfo* start_with,
|
||||||
bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
|
bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
|
||||||
task->set_extinfo(is_dt_needed ? nullptr : extinfo);
|
task->set_extinfo(is_dt_needed ? nullptr : extinfo);
|
||||||
|
|
||||||
if(!find_library_internal(task, &zip_archive_cache, &load_tasks, rtld_flags)) {
|
if(!find_library_internal(ns, task, &zip_archive_cache, &load_tasks, rtld_flags)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1850,14 +2049,15 @@ static bool find_libraries(soinfo* start_with,
|
||||||
return linked;
|
return linked;
|
||||||
}
|
}
|
||||||
|
|
||||||
static soinfo* find_library(const char* name, int rtld_flags,
|
static soinfo* find_library(android_namespace_t* ns,
|
||||||
|
const char* name, int rtld_flags,
|
||||||
const android_dlextinfo* extinfo,
|
const android_dlextinfo* extinfo,
|
||||||
soinfo* needed_by) {
|
soinfo* needed_by) {
|
||||||
soinfo* si;
|
soinfo* si;
|
||||||
|
|
||||||
if (name == nullptr) {
|
if (name == nullptr) {
|
||||||
si = somain;
|
si = somain;
|
||||||
} else if (!find_libraries(needed_by, &name, 1, &si, nullptr, 0, rtld_flags,
|
} else if (!find_libraries(ns, needed_by, &name, 1, &si, nullptr, 0, rtld_flags,
|
||||||
extinfo, /* add_as_children */ false)) {
|
extinfo, /* add_as_children */ false)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -1920,7 +2120,9 @@ static void soinfo_unload(soinfo* root) {
|
||||||
TRACE("deprecated (old format of soinfo): %s needs to unload %s",
|
TRACE("deprecated (old format of soinfo): %s needs to unload %s",
|
||||||
si->get_realpath(), library_name);
|
si->get_realpath(), library_name);
|
||||||
|
|
||||||
soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr, nullptr);
|
soinfo* needed = find_library(si->get_namespace(),
|
||||||
|
library_name, RTLD_NOLOAD, nullptr, nullptr);
|
||||||
|
|
||||||
if (needed != nullptr) {
|
if (needed != nullptr) {
|
||||||
// Not found: for example if symlink was deleted between dlopen and dlclose
|
// Not found: for example if symlink was deleted between dlopen and dlclose
|
||||||
// Since we cannot really handle errors at this point - print and continue.
|
// Since we cannot really handle errors at this point - print and continue.
|
||||||
|
@ -1992,6 +2194,9 @@ soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo,
|
||||||
DL_ERR("invalid flags to dlopen: %x", flags);
|
DL_ERR("invalid flags to dlopen: %x", flags);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
android_namespace_t* ns = caller->get_namespace();
|
||||||
|
|
||||||
if (extinfo != nullptr) {
|
if (extinfo != nullptr) {
|
||||||
if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
|
if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
|
||||||
DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
|
DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
|
||||||
|
@ -2011,13 +2216,22 @@ soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo,
|
||||||
"compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
|
"compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) {
|
||||||
|
if (extinfo->library_namespace == nullptr) {
|
||||||
|
DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
ns = extinfo->library_namespace;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ProtectedDataGuard guard;
|
ProtectedDataGuard guard;
|
||||||
soinfo* si = find_library(name, flags, extinfo, caller);
|
soinfo* si = find_library(ns, name, flags, extinfo, caller);
|
||||||
if (si != nullptr) {
|
if (si != nullptr) {
|
||||||
si->call_constructors();
|
si->call_constructors();
|
||||||
}
|
}
|
||||||
|
|
||||||
return si;
|
return si;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2026,6 +2240,67 @@ void do_dlclose(soinfo* si) {
|
||||||
soinfo_unload(si);
|
soinfo_unload(si);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool init_public_namespace(const char* libs) {
|
||||||
|
CHECK(libs != nullptr);
|
||||||
|
if (g_public_namespace_initialized) {
|
||||||
|
DL_ERR("Public namespace has already been initialized.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> sonames = android::base::Split(libs, ":");
|
||||||
|
|
||||||
|
ProtectedDataGuard guard;
|
||||||
|
|
||||||
|
auto failure_guard = make_scope_guard([&]() {
|
||||||
|
g_public_namespace.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
soinfo* candidate;
|
||||||
|
for (const auto& soname : sonames) {
|
||||||
|
if (!find_loaded_library_by_soname(&g_default_namespace, soname.c_str(), &candidate)) {
|
||||||
|
DL_ERR("Error initializing public namespace: \"%s\" was not found"
|
||||||
|
" in the default namespace", soname.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
candidate->set_nodelete();
|
||||||
|
g_public_namespace.push_back(candidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
failure_guard.disable();
|
||||||
|
g_public_namespace_initialized = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
android_namespace_t* create_namespace(const char* name,
|
||||||
|
const char* ld_library_path,
|
||||||
|
const char* default_library_path,
|
||||||
|
bool is_isolated) {
|
||||||
|
if (!g_public_namespace_initialized) {
|
||||||
|
DL_ERR("Cannot create namespace: public namespace is not initialized.");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtectedDataGuard guard;
|
||||||
|
std::vector<std::string> ld_library_paths;
|
||||||
|
std::vector<std::string> default_library_paths;
|
||||||
|
|
||||||
|
parse_path(ld_library_path, ":", &ld_library_paths);
|
||||||
|
parse_path(default_library_path, ":", &default_library_paths);
|
||||||
|
|
||||||
|
android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
|
||||||
|
ns->set_name(name);
|
||||||
|
ns->set_isolated(is_isolated);
|
||||||
|
ns->set_ld_library_paths(std::move(ld_library_paths));
|
||||||
|
ns->set_default_library_paths(std::move(default_library_paths));
|
||||||
|
|
||||||
|
// TODO(dimtiry): Should this be global group of caller's namespace?
|
||||||
|
auto global_group = make_global_group(&g_default_namespace);
|
||||||
|
std::copy(global_group.begin(), global_group.end(), std::back_inserter(ns->soinfo_list()));
|
||||||
|
|
||||||
|
return ns;
|
||||||
|
}
|
||||||
|
|
||||||
static ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
|
static ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
|
||||||
typedef ElfW(Addr) (*ifunc_resolver_t)(void);
|
typedef ElfW(Addr) (*ifunc_resolver_t)(void);
|
||||||
ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
|
ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
|
||||||
|
@ -2694,6 +2969,10 @@ void soinfo::set_dt_flags_1(uint32_t dt_flags_1) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void soinfo::set_nodelete() {
|
||||||
|
rtld_flags_ |= RTLD_NODELETE;
|
||||||
|
}
|
||||||
|
|
||||||
const char* soinfo::get_realpath() const {
|
const char* soinfo::get_realpath() const {
|
||||||
#if defined(__work_around_b_24465209__)
|
#if defined(__work_around_b_24465209__)
|
||||||
if (has_min_version(2)) {
|
if (has_min_version(2)) {
|
||||||
|
@ -2760,13 +3039,21 @@ soinfo::soinfo_list_t& soinfo::get_parents() {
|
||||||
static std::vector<std::string> g_empty_runpath;
|
static std::vector<std::string> g_empty_runpath;
|
||||||
|
|
||||||
const std::vector<std::string>& soinfo::get_dt_runpath() const {
|
const std::vector<std::string>& soinfo::get_dt_runpath() const {
|
||||||
if (has_min_version(2)) {
|
if (has_min_version(3)) {
|
||||||
return dt_runpath_;
|
return dt_runpath_;
|
||||||
}
|
}
|
||||||
|
|
||||||
return g_empty_runpath;
|
return g_empty_runpath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
android_namespace_t* soinfo::get_namespace() {
|
||||||
|
if (has_min_version(3)) {
|
||||||
|
return namespace_;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &g_default_namespace;
|
||||||
|
}
|
||||||
|
|
||||||
ElfW(Addr) soinfo::resolve_symbol_address(const ElfW(Sym)* s) const {
|
ElfW(Addr) soinfo::resolve_symbol_address(const ElfW(Sym)* s) const {
|
||||||
if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
|
if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
|
||||||
return call_ifunc_resolver(s->st_value + load_bias);
|
return call_ifunc_resolver(s->st_value + load_bias);
|
||||||
|
@ -3464,7 +3751,8 @@ static soinfo* linker_soinfo_for_gdb = nullptr;
|
||||||
* be on the soinfo list.
|
* be on the soinfo list.
|
||||||
*/
|
*/
|
||||||
static void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
|
static void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
|
||||||
linker_soinfo_for_gdb = new (linker_soinfo_for_gdb_buf) soinfo(LINKER_PATH, nullptr, 0, 0);
|
linker_soinfo_for_gdb = new (linker_soinfo_for_gdb_buf) soinfo(nullptr, LINKER_PATH,
|
||||||
|
nullptr, 0, 0);
|
||||||
|
|
||||||
linker_soinfo_for_gdb->load_bias = linker_base;
|
linker_soinfo_for_gdb->load_bias = linker_base;
|
||||||
|
|
||||||
|
@ -3481,14 +3769,25 @@ static void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
|
||||||
insert_soinfo_into_debug_map(linker_soinfo_for_gdb);
|
insert_soinfo_into_debug_map(linker_soinfo_for_gdb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_default_ld_library_path() {
|
static void init_default_namespace() {
|
||||||
|
g_default_namespace.set_name("(default)");
|
||||||
|
g_default_namespace.set_isolated(false);
|
||||||
|
|
||||||
const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
|
const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
|
||||||
somain->load_bias);
|
somain->load_bias);
|
||||||
const char* bname = basename(interp);
|
const char* bname = basename(interp);
|
||||||
if (bname && (strcmp(bname, "linker_asan") == 0 || strcmp(bname, "linker_asan64") == 0))
|
if (bname && (strcmp(bname, "linker_asan") == 0 || strcmp(bname, "linker_asan64") == 0)) {
|
||||||
g_default_ld_paths = kAsanDefaultLdPaths;
|
g_default_ld_paths = kAsanDefaultLdPaths;
|
||||||
else
|
} else {
|
||||||
g_default_ld_paths = kDefaultLdPaths;
|
g_default_ld_paths = kDefaultLdPaths;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> ld_default_paths;
|
||||||
|
for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {
|
||||||
|
ld_default_paths.push_back(g_default_ld_paths[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_default_namespace.set_default_library_paths(std::move(ld_default_paths));
|
||||||
};
|
};
|
||||||
|
|
||||||
extern "C" int __system_properties_init(void);
|
extern "C" int __system_properties_init(void);
|
||||||
|
@ -3529,7 +3828,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
|
||||||
|
|
||||||
INFO("[ android linker & debugger ]");
|
INFO("[ android linker & debugger ]");
|
||||||
|
|
||||||
soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0, RTLD_GLOBAL);
|
soinfo* si = soinfo_alloc(&g_default_namespace, args.argv[0], nullptr, 0, RTLD_GLOBAL);
|
||||||
if (si == nullptr) {
|
if (si == nullptr) {
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
@ -3581,11 +3880,10 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
|
||||||
|
|
||||||
somain = si;
|
somain = si;
|
||||||
|
|
||||||
init_default_ld_library_path();
|
init_default_namespace();
|
||||||
|
|
||||||
if (!si->prelink_image()) {
|
if (!si->prelink_image()) {
|
||||||
__libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
|
__libc_fatal("CANNOT LINK EXECUTABLE: %s", linker_get_error_buffer());
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add somain to global group
|
// add somain to global group
|
||||||
|
@ -3613,15 +3911,13 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
|
||||||
needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count);
|
needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count);
|
||||||
|
|
||||||
if (needed_libraries_count > 0 &&
|
if (needed_libraries_count > 0 &&
|
||||||
!find_libraries(si, needed_library_names, needed_libraries_count, nullptr,
|
!find_libraries(&g_default_namespace, si, needed_library_names, needed_libraries_count,
|
||||||
&g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr,
|
nullptr, &g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr,
|
||||||
/* add_as_children */ true)) {
|
/* add_as_children */ true)) {
|
||||||
__libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
|
__libc_fatal("CANNOT LINK EXECUTABLE: %s", linker_get_error_buffer());
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
} else if (needed_libraries_count == 0) {
|
} else if (needed_libraries_count == 0) {
|
||||||
if (!si->link_image(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr)) {
|
if (!si->link_image(g_empty_list, soinfo::soinfo_list_t::make_list(si), nullptr)) {
|
||||||
__libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
|
__libc_fatal("CANNOT LINK EXECUTABLE: %s", linker_get_error_buffer());
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
}
|
||||||
si->increment_ref_count();
|
si->increment_ref_count();
|
||||||
}
|
}
|
||||||
|
@ -3730,7 +4026,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) {
|
||||||
ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
|
ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
|
||||||
ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff);
|
ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff);
|
||||||
|
|
||||||
soinfo linker_so(nullptr, nullptr, 0, 0);
|
soinfo linker_so(nullptr, nullptr, nullptr, 0, 0);
|
||||||
|
|
||||||
// If the linker is not acting as PT_INTERP entry_point is equal to
|
// If the linker is not acting as PT_INTERP entry_point is equal to
|
||||||
// _start. Which means that the linker is running as an executable and
|
// _start. Which means that the linker is running as an executable and
|
||||||
|
@ -3739,7 +4035,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) {
|
||||||
// This happens when user tries to run 'adb shell /system/bin/linker'
|
// This happens when user tries to run 'adb shell /system/bin/linker'
|
||||||
// see also https://code.google.com/p/android/issues/detail?id=63174
|
// see also https://code.google.com/p/android/issues/detail?id=63174
|
||||||
if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) {
|
if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) {
|
||||||
__libc_fatal("This is %s, the helper program for shared library executables.\n", args.argv[0]);
|
__libc_fatal("This is %s, the helper program for shared library executables.", args.argv[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
linker_so.base = linker_addr;
|
linker_so.base = linker_addr;
|
||||||
|
@ -3757,15 +4053,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) {
|
||||||
// are not yet initialized, and therefore we cannot use linked_list.push_*
|
// are not yet initialized, and therefore we cannot use linked_list.push_*
|
||||||
// functions at this point.
|
// functions at this point.
|
||||||
if (!(linker_so.prelink_image() && linker_so.link_image(g_empty_list, g_empty_list, nullptr))) {
|
if (!(linker_so.prelink_image() && linker_so.link_image(g_empty_list, g_empty_list, nullptr))) {
|
||||||
// It would be nice to print an error message, but if the linker
|
__libc_fatal("CANNOT LINK EXECUTABLE: %s", linker_get_error_buffer());
|
||||||
// can't link itself, there's no guarantee that we'll be able to
|
|
||||||
// call write() (because it involves a GOT reference). We may as
|
|
||||||
// well try though...
|
|
||||||
const char* msg = "CANNOT LINK EXECUTABLE: ";
|
|
||||||
write(2, msg, strlen(msg));
|
|
||||||
write(2, __linker_dl_err_buf, strlen(__linker_dl_err_buf));
|
|
||||||
write(2, "\n", 1);
|
|
||||||
_exit(EXIT_FAILURE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__libc_init_main_thread(args);
|
__libc_init_main_thread(args);
|
||||||
|
@ -3781,6 +4069,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) {
|
||||||
// before get_libdl_info().
|
// before get_libdl_info().
|
||||||
solist = get_libdl_info();
|
solist = get_libdl_info();
|
||||||
sonext = get_libdl_info();
|
sonext = get_libdl_info();
|
||||||
|
g_default_namespace.soinfo_list().push_back(get_libdl_info());
|
||||||
|
|
||||||
// We have successfully fixed our own relocations. It's safe to run
|
// We have successfully fixed our own relocations. It's safe to run
|
||||||
// the main part of the linker now.
|
// the main part of the linker now.
|
||||||
|
|
|
@ -86,7 +86,7 @@
|
||||||
|
|
||||||
#define SUPPORTED_DT_FLAGS_1 (DF_1_NOW | DF_1_GLOBAL | DF_1_NODELETE)
|
#define SUPPORTED_DT_FLAGS_1 (DF_1_NOW | DF_1_GLOBAL | DF_1_NODELETE)
|
||||||
|
|
||||||
#define SOINFO_VERSION 2
|
#define SOINFO_VERSION 3
|
||||||
|
|
||||||
#if defined(__work_around_b_24465209__)
|
#if defined(__work_around_b_24465209__)
|
||||||
#define SOINFO_NAME_LEN 128
|
#define SOINFO_NAME_LEN 128
|
||||||
|
@ -261,7 +261,8 @@ struct soinfo {
|
||||||
bool has_DT_SYMBOLIC;
|
bool has_DT_SYMBOLIC;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
soinfo(const char* name, const struct stat* file_stat, off64_t file_offset, int rtld_flags);
|
soinfo(android_namespace_t* ns, const char* name, const struct stat* file_stat,
|
||||||
|
off64_t file_offset, int rtld_flags);
|
||||||
|
|
||||||
void call_constructors();
|
void call_constructors();
|
||||||
void call_destructors();
|
void call_destructors();
|
||||||
|
@ -311,6 +312,7 @@ struct soinfo {
|
||||||
void set_linked();
|
void set_linked();
|
||||||
void set_linker_flag();
|
void set_linker_flag();
|
||||||
void set_main_executable();
|
void set_main_executable();
|
||||||
|
void set_nodelete();
|
||||||
|
|
||||||
void increment_ref_count();
|
void increment_ref_count();
|
||||||
size_t decrement_ref_count();
|
size_t decrement_ref_count();
|
||||||
|
@ -332,6 +334,7 @@ struct soinfo {
|
||||||
|
|
||||||
void set_dt_runpath(const char *);
|
void set_dt_runpath(const char *);
|
||||||
const std::vector<std::string>& get_dt_runpath() const;
|
const std::vector<std::string>& get_dt_runpath() const;
|
||||||
|
android_namespace_t* get_namespace();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool elf_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const;
|
bool elf_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const;
|
||||||
|
@ -394,7 +397,9 @@ struct soinfo {
|
||||||
|
|
||||||
uint32_t target_sdk_version_;
|
uint32_t target_sdk_version_;
|
||||||
|
|
||||||
|
// version >= 3
|
||||||
std::vector<std::string> dt_runpath_;
|
std::vector<std::string> dt_runpath_;
|
||||||
|
android_namespace_t* namespace_;
|
||||||
|
|
||||||
friend soinfo* get_libdl_info();
|
friend soinfo* get_libdl_info();
|
||||||
};
|
};
|
||||||
|
@ -422,7 +427,9 @@ void do_dlclose(soinfo* si);
|
||||||
|
|
||||||
int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data);
|
int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data);
|
||||||
|
|
||||||
const ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* caller, void* handle);
|
const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns, const char* name, soinfo** found,
|
||||||
|
soinfo* caller, void* handle);
|
||||||
|
|
||||||
soinfo* find_containing_library(const void* addr);
|
soinfo* find_containing_library(const void* addr);
|
||||||
|
|
||||||
const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name);
|
const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name);
|
||||||
|
@ -437,4 +444,8 @@ size_t linker_get_error_buffer_size();
|
||||||
void set_application_target_sdk_version(uint32_t target);
|
void set_application_target_sdk_version(uint32_t target);
|
||||||
uint32_t get_application_target_sdk_version();
|
uint32_t get_application_target_sdk_version();
|
||||||
|
|
||||||
|
bool init_public_namespace(const char* path);
|
||||||
|
android_namespace_t* create_namespace(const char* name, const char* ld_library_path,
|
||||||
|
const char* default_library_path, bool is_isolated);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
bool normalize_path(const char* path, std::string* normalized_path) {
|
bool normalize_path(const char* path, std::string* normalized_path) {
|
||||||
// Input should be an absolute path
|
// Input should be an absolute path
|
||||||
if (path[0] != '/') {
|
if (path[0] != '/') {
|
||||||
PRINT("canonize_path - invalid input: '%s', the input path should be absolute", path);
|
PRINT("normalize_path - invalid input: '%s', the input path should be absolute", path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,3 +61,47 @@ bool normalize_path(const char* path, std::string* normalized_path) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool file_is_in_dir(const std::string& file, const std::string& dir) {
|
||||||
|
const char* needle = dir.c_str();
|
||||||
|
const char* haystack = file.c_str();
|
||||||
|
size_t needle_len = strlen(needle);
|
||||||
|
|
||||||
|
return (strncmp(haystack, needle, needle_len) == 0 &&
|
||||||
|
haystack[needle_len] == '/' &&
|
||||||
|
strchr(haystack + needle_len + 1, '/') == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* const kZipFileSeparator = "!/";
|
||||||
|
|
||||||
|
bool parse_zip_path(const char* input_path, std::string* zip_path, std::string* entry_path) {
|
||||||
|
std::string normalized_path;
|
||||||
|
if (!normalize_path(input_path, &normalized_path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* const path = normalized_path.c_str();
|
||||||
|
TRACE("Trying zip file open from path '%s' -> normalized '%s'", input_path, path);
|
||||||
|
|
||||||
|
// Treat an '!/' separator inside a path as the separator between the name
|
||||||
|
// of the zip file on disk and the subdirectory to search within it.
|
||||||
|
// For example, if path is "foo.zip!/bar/bas/x.so", then we search for
|
||||||
|
// "bar/bas/x.so" within "foo.zip".
|
||||||
|
const char* const separator = strstr(path, kZipFileSeparator);
|
||||||
|
if (separator == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buf[512];
|
||||||
|
if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) {
|
||||||
|
PRINT("Warning: ignoring very long library path: %s", path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[separator - path] = '\0';
|
||||||
|
|
||||||
|
*zip_path = buf;
|
||||||
|
*entry_path = &buf[separator - path + 2];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,10 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
extern const char* const kZipFileSeparator;
|
||||||
|
|
||||||
bool normalize_path(const char* path, std::string* normalized_path);
|
bool normalize_path(const char* path, std::string* normalized_path);
|
||||||
|
bool file_is_in_dir(const std::string& file, const std::string& dir);
|
||||||
|
bool parse_zip_path(const char* input_path, std::string* zip_path, std::string* entry_path);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -43,3 +43,29 @@ TEST(linker_utils, normalize_path_smoke) {
|
||||||
ASSERT_FALSE(normalize_path("root///dir/.///dir2/somedir/../zipfile!/dir/dir9//..///afile", &output));
|
ASSERT_FALSE(normalize_path("root///dir/.///dir2/somedir/../zipfile!/dir/dir9//..///afile", &output));
|
||||||
ASSERT_EQ("unchanged", output);
|
ASSERT_EQ("unchanged", output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(linker_utils, file_is_in_dir_smoke) {
|
||||||
|
ASSERT_TRUE(file_is_in_dir("/foo/bar/file", "/foo/bar"));
|
||||||
|
ASSERT_FALSE(file_is_in_dir("/foo/bar/file", "/foo"));
|
||||||
|
|
||||||
|
ASSERT_FALSE(file_is_in_dir("/foo/bar/file", "/bar/foo"));
|
||||||
|
|
||||||
|
ASSERT_TRUE(file_is_in_dir("/file", ""));
|
||||||
|
ASSERT_FALSE(file_is_in_dir("/file", "/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(linker_utils, parse_zip_path_smoke) {
|
||||||
|
std::string zip_path;
|
||||||
|
std::string entry_path;
|
||||||
|
|
||||||
|
ASSERT_FALSE(parse_zip_path("/not/a/zip/path/file.zip", &zip_path, &entry_path));
|
||||||
|
ASSERT_FALSE(parse_zip_path("/not/a/zip/path/file.zip!path/in/zip", &zip_path, &entry_path));
|
||||||
|
ASSERT_TRUE(parse_zip_path("/zip/path/file.zip!/path/in/zip", &zip_path, &entry_path));
|
||||||
|
ASSERT_EQ("/zip/path/file.zip", zip_path);
|
||||||
|
ASSERT_EQ("path/in/zip", entry_path);
|
||||||
|
|
||||||
|
ASSERT_TRUE(parse_zip_path("/zip/path/file2.zip!/", &zip_path, &entry_path));
|
||||||
|
ASSERT_EQ("/zip/path/file2.zip", zip_path);
|
||||||
|
ASSERT_EQ("", entry_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,9 +28,17 @@ ifneq ($(findstring LIBRARY, $(build_target)),LIBRARY)
|
||||||
LOCAL_MODULE_STEM_32 := $(module)32
|
LOCAL_MODULE_STEM_32 := $(module)32
|
||||||
LOCAL_MODULE_STEM_64 := $(module)64
|
LOCAL_MODULE_STEM_64 := $(module)64
|
||||||
else
|
else
|
||||||
|
|
||||||
|
ifneq ($($(module)_install_to_out_data_dir),)
|
||||||
|
$(module)_install_to_out_data := true
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($($(module)_install_to_out_data),true)
|
ifeq ($($(module)_install_to_out_data),true)
|
||||||
LOCAL_MODULE_PATH_32 := $($(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_DATA_NATIVE_TESTS)/$(module)
|
ifeq ($($(module)_install_to_out_data_dir),)
|
||||||
LOCAL_MODULE_PATH_64 := $(TARGET_OUT_DATA_NATIVE_TESTS)/$(module)
|
$(module)_install_to_out_data_dir := $(module)
|
||||||
|
endif
|
||||||
|
LOCAL_MODULE_PATH_32 := $($(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_DATA_NATIVE_TESTS)/$($(module)_install_to_out_data_dir)
|
||||||
|
LOCAL_MODULE_PATH_64 := $(TARGET_OUT_DATA_NATIVE_TESTS)/$($(module)_install_to_out_data_dir)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -52,14 +52,14 @@ typedef int (*fn)(void);
|
||||||
#define LIBSIZE 1024*1024 // how much address space to reserve for it
|
#define LIBSIZE 1024*1024 // how much address space to reserve for it
|
||||||
|
|
||||||
#if defined(__LP64__)
|
#if defined(__LP64__)
|
||||||
#define LIBPATH_PREFIX "/nativetest64/"
|
#define NATIVE_TESTS_PATH "/nativetest64"
|
||||||
#else
|
#else
|
||||||
#define LIBPATH_PREFIX "/nativetest/"
|
#define NATIVE_TESTS_PATH "/nativetest"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LIBPATH LIBPATH_PREFIX "libdlext_test_fd/libdlext_test_fd.so"
|
#define LIBPATH NATIVE_TESTS_PATH "/libdlext_test_fd/libdlext_test_fd.so"
|
||||||
#define LIBZIPPATH LIBPATH_PREFIX "libdlext_test_zip/libdlext_test_zip_zipaligned.zip"
|
#define LIBZIPPATH NATIVE_TESTS_PATH "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip"
|
||||||
#define LIBZIPPATH_WITH_RUNPATH LIBPATH_PREFIX "libdlext_test_runpath_zip/libdlext_test_runpath_zip_zipaligned.zip"
|
#define LIBZIPPATH_WITH_RUNPATH NATIVE_TESTS_PATH "/libdlext_test_runpath_zip/libdlext_test_runpath_zip_zipaligned.zip"
|
||||||
|
|
||||||
#define LIBZIP_OFFSET PAGE_SIZE
|
#define LIBZIP_OFFSET PAGE_SIZE
|
||||||
|
|
||||||
|
@ -602,3 +602,192 @@ void DlExtRelroSharingTest::SpawnChildrenAndMeasurePss(const char* lib, bool sha
|
||||||
ASSERT_EQ(0, WEXITSTATUS(status));
|
ASSERT_EQ(0, WEXITSTATUS(status));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testing namespaces
|
||||||
|
static const char* g_public_lib = "libnstest_public.so";
|
||||||
|
|
||||||
|
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: "
|
||||||
|
"\"libnstest_public.so\" was not found in the default namespace", dlerror());
|
||||||
|
|
||||||
|
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_public_namespace(path.c_str())) << dlerror();
|
||||||
|
|
||||||
|
// Check that libraries added to public namespace are NODELETE
|
||||||
|
dlclose(handle_public);
|
||||||
|
handle_public = dlopen((lib_path + "/public_namespace_libs/" + g_public_lib).c_str(), RTLD_NOW | RTLD_NOLOAD);
|
||||||
|
ASSERT_TRUE(handle_public != nullptr) << dlerror();
|
||||||
|
|
||||||
|
android_namespace_t* ns1 = android_create_namespace("private", nullptr, (lib_path + "/private_namespace_libs").c_str(), false);
|
||||||
|
ASSERT_TRUE(ns1 != nullptr) << dlerror();
|
||||||
|
|
||||||
|
android_namespace_t* ns2 = android_create_namespace("private_isolated", nullptr, (lib_path + "/private_namespace_libs").c_str(), true);
|
||||||
|
ASSERT_TRUE(ns2 != nullptr) << dlerror();
|
||||||
|
|
||||||
|
// This should not have affect search path for default namespace:
|
||||||
|
ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
|
||||||
|
void* handle = dlopen(g_public_lib, RTLD_NOW);
|
||||||
|
ASSERT_TRUE(handle != nullptr) << dlerror();
|
||||||
|
dlclose(handle);
|
||||||
|
|
||||||
|
android_dlextinfo extinfo;
|
||||||
|
extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
|
||||||
|
extinfo.library_namespace = ns1;
|
||||||
|
|
||||||
|
void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
|
||||||
|
ASSERT_TRUE(handle1 != nullptr) << dlerror();
|
||||||
|
|
||||||
|
extinfo.library_namespace = ns2;
|
||||||
|
void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
|
||||||
|
ASSERT_TRUE(handle2 != nullptr) << dlerror();
|
||||||
|
|
||||||
|
ASSERT_TRUE(handle1 != handle2);
|
||||||
|
|
||||||
|
typedef const char* (*fn_t)();
|
||||||
|
|
||||||
|
fn_t ns_get_local_string1 = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string"));
|
||||||
|
ASSERT_TRUE(ns_get_local_string1 != nullptr) << dlerror();
|
||||||
|
fn_t ns_get_local_string2 = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_local_string"));
|
||||||
|
ASSERT_TRUE(ns_get_local_string2 != nullptr) << dlerror();
|
||||||
|
|
||||||
|
EXPECT_STREQ("This string is local to root library", ns_get_local_string1());
|
||||||
|
EXPECT_STREQ("This string is local to root library", ns_get_local_string2());
|
||||||
|
|
||||||
|
ASSERT_TRUE(ns_get_local_string1() != ns_get_local_string2());
|
||||||
|
|
||||||
|
fn_t ns_get_private_extern_string1 =
|
||||||
|
reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string"));
|
||||||
|
ASSERT_TRUE(ns_get_private_extern_string1 != nullptr) << dlerror();
|
||||||
|
fn_t ns_get_private_extern_string2 =
|
||||||
|
reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_private_extern_string"));
|
||||||
|
ASSERT_TRUE(ns_get_private_extern_string2 != nullptr) << dlerror();
|
||||||
|
|
||||||
|
EXPECT_STREQ("This string is from private namespace", ns_get_private_extern_string1());
|
||||||
|
EXPECT_STREQ("This string is from private namespace", ns_get_private_extern_string2());
|
||||||
|
|
||||||
|
ASSERT_TRUE(ns_get_private_extern_string1() != ns_get_private_extern_string2());
|
||||||
|
|
||||||
|
fn_t ns_get_public_extern_string1 =
|
||||||
|
reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string"));
|
||||||
|
ASSERT_TRUE(ns_get_public_extern_string1 != nullptr) << dlerror();
|
||||||
|
fn_t ns_get_public_extern_string2 =
|
||||||
|
reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_public_extern_string"));
|
||||||
|
ASSERT_TRUE(ns_get_public_extern_string2 != nullptr) << dlerror();
|
||||||
|
|
||||||
|
EXPECT_STREQ("This string is from public namespace", ns_get_public_extern_string1());
|
||||||
|
ASSERT_TRUE(ns_get_public_extern_string1() == ns_get_public_extern_string2());
|
||||||
|
|
||||||
|
// and now check that dlopen() does the right thing in terms of preserving namespace
|
||||||
|
fn_t ns_get_dlopened_string1 = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string"));
|
||||||
|
ASSERT_TRUE(ns_get_dlopened_string1 != nullptr) << dlerror();
|
||||||
|
fn_t ns_get_dlopened_string2 = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_dlopened_string"));
|
||||||
|
ASSERT_TRUE(ns_get_dlopened_string2 != nullptr) << dlerror();
|
||||||
|
|
||||||
|
EXPECT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string1());
|
||||||
|
EXPECT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string2());
|
||||||
|
|
||||||
|
ASSERT_TRUE(ns_get_dlopened_string1() != ns_get_dlopened_string2());
|
||||||
|
|
||||||
|
dlclose(handle1);
|
||||||
|
|
||||||
|
// Check if handle2 is still alive (and well)
|
||||||
|
ASSERT_STREQ("This string is local to root library", ns_get_local_string2());
|
||||||
|
ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string2());
|
||||||
|
ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string2());
|
||||||
|
ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string2());
|
||||||
|
|
||||||
|
dlclose(handle2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(dlext, ns_isolated) {
|
||||||
|
static const char* root_lib = "libnstest_root_not_isolated.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_public_namespace(path.c_str())) << 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();
|
||||||
|
|
||||||
|
android_namespace_t* ns_isolated = android_create_namespace("private_isolated1", nullptr, (lib_path + "/private_namespace_libs").c_str(), true);
|
||||||
|
ASSERT_TRUE(ns_isolated != nullptr) << dlerror();
|
||||||
|
|
||||||
|
android_namespace_t* ns_isolated2 = android_create_namespace("private_isolated2", (lib_path + "/private_namespace_libs").c_str(), nullptr, true);
|
||||||
|
ASSERT_TRUE(ns_isolated2 != nullptr) << dlerror();
|
||||||
|
|
||||||
|
ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
|
||||||
|
ASSERT_STREQ("dlopen failed: library \"libnstest_root_not_isolated.so\" not found", dlerror());
|
||||||
|
|
||||||
|
std::string lib_private_external_path =
|
||||||
|
lib_path + "/private_namespace_libs_external/libnstest_private_external.so";
|
||||||
|
|
||||||
|
// Load lib_private_external_path to default namespace
|
||||||
|
// (it should remain invisible for the isolated namespaces after this)
|
||||||
|
void* handle = dlopen(lib_private_external_path.c_str(), RTLD_NOW);
|
||||||
|
ASSERT_TRUE(handle != nullptr) << dlerror();
|
||||||
|
|
||||||
|
android_dlextinfo extinfo;
|
||||||
|
extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
|
||||||
|
extinfo.library_namespace = ns_not_isolated;
|
||||||
|
|
||||||
|
void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
|
||||||
|
ASSERT_TRUE(handle1 != nullptr) << dlerror();
|
||||||
|
|
||||||
|
extinfo.library_namespace = ns_isolated;
|
||||||
|
|
||||||
|
void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
|
||||||
|
ASSERT_TRUE(handle2 == nullptr);
|
||||||
|
ASSERT_STREQ("dlopen failed: library \"libnstest_private_external.so\" not found", dlerror());
|
||||||
|
|
||||||
|
// Check dlopen by absolute path
|
||||||
|
handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
|
||||||
|
ASSERT_TRUE(handle2 == nullptr);
|
||||||
|
ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" not found", dlerror());
|
||||||
|
|
||||||
|
extinfo.library_namespace = ns_isolated2;
|
||||||
|
|
||||||
|
handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
|
||||||
|
ASSERT_TRUE(handle2 == nullptr);
|
||||||
|
ASSERT_STREQ("dlopen failed: library \"libnstest_private_external.so\" not found", dlerror());
|
||||||
|
|
||||||
|
// Check dlopen by absolute path
|
||||||
|
handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
|
||||||
|
ASSERT_TRUE(handle2 == nullptr);
|
||||||
|
ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" not found", dlerror());
|
||||||
|
|
||||||
|
typedef const char* (*fn_t)();
|
||||||
|
fn_t ns_get_local_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string"));
|
||||||
|
ASSERT_TRUE(ns_get_local_string != nullptr) << dlerror();
|
||||||
|
|
||||||
|
ASSERT_STREQ("This string is local to root library", ns_get_local_string());
|
||||||
|
|
||||||
|
fn_t ns_get_private_extern_string =
|
||||||
|
reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string"));
|
||||||
|
ASSERT_TRUE(ns_get_private_extern_string != nullptr) << dlerror();
|
||||||
|
|
||||||
|
ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string());
|
||||||
|
|
||||||
|
fn_t ns_get_public_extern_string =
|
||||||
|
reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string"));
|
||||||
|
ASSERT_TRUE(ns_get_public_extern_string != nullptr) << dlerror();
|
||||||
|
|
||||||
|
ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string());
|
||||||
|
|
||||||
|
fn_t ns_get_dlopened_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string"));
|
||||||
|
ASSERT_TRUE(ns_get_dlopened_string != nullptr) << dlerror();
|
||||||
|
|
||||||
|
ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string());
|
||||||
|
|
||||||
|
dlclose(handle1);
|
||||||
|
}
|
||||||
|
|
84
tests/libs/Android.build.linker_namespaces.mk
Normal file
84
tests/libs/Android.build.linker_namespaces.mk
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
#
|
||||||
|
# Copyright (C) 2015 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# This set of libraries are used to verify linker namespaces.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Test cases
|
||||||
|
# 1. Check that private libraries loaded in different namespaces are
|
||||||
|
# different. Check that dlsym does not confuse them.
|
||||||
|
# 2. Check that public libraries loaded in different namespaces are shared
|
||||||
|
# between them.
|
||||||
|
# 3. Check that namespace sticks on dlopen
|
||||||
|
#
|
||||||
|
# Dependency tree (visibility)
|
||||||
|
# libnstest_root.so (this should be local to the namespace)
|
||||||
|
# +-> libnstest_public.so
|
||||||
|
# +-> libnstest_private.so
|
||||||
|
#
|
||||||
|
# libnstest_dlopened.so (library in private namespace dlopened from libnstest_root.so)
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
libnstest_root_src_files := namespaces_root.cpp
|
||||||
|
libnstest_root_shared_libraries := libnstest_public libnstest_private
|
||||||
|
libnstest_root_install_to_out_data_dir := private_namespace_libs
|
||||||
|
module := libnstest_root
|
||||||
|
include $(LOCAL_PATH)/Android.build.target.testlib.mk
|
||||||
|
|
||||||
|
libnstest_public_src_files := namespaces_public.cpp
|
||||||
|
module := libnstest_public
|
||||||
|
libnstest_public_install_to_out_data_dir := public_namespace_libs
|
||||||
|
include $(LOCAL_PATH)/Android.build.target.testlib.mk
|
||||||
|
|
||||||
|
libnstest_private_src_files := namespaces_private.cpp
|
||||||
|
libnstest_private_install_to_out_data_dir := private_namespace_libs
|
||||||
|
module := libnstest_private
|
||||||
|
include $(LOCAL_PATH)/Android.build.target.testlib.mk
|
||||||
|
|
||||||
|
libnstest_dlopened_src_files := namespaces_dlopened.cpp
|
||||||
|
libnstest_dlopened_install_to_out_data_dir := private_namespace_libs
|
||||||
|
module := libnstest_dlopened
|
||||||
|
include $(LOCAL_PATH)/Android.build.target.testlib.mk
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# This set of libraries is to test isolated namespaces
|
||||||
|
#
|
||||||
|
# Isolated namespaces do not allow loading of the library outside of
|
||||||
|
# the search paths.
|
||||||
|
#
|
||||||
|
# This library cannot be loaded in isolated namespace because one of DT_NEEDED
|
||||||
|
# libraries is outside of the search paths.
|
||||||
|
#
|
||||||
|
# libnstest_root_not_isolated.so (DT_RUNPATH = $ORIGIN/../private_namespace_libs_external/)
|
||||||
|
# +-> libnstest_public.so
|
||||||
|
# +-> libnstest_private_external.so (located in $ORIGIN/../private_namespace_libs_external/)
|
||||||
|
#
|
||||||
|
# Search path: $NATIVE_TESTS/private_namespace_libs/
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
libnstest_root_not_isolated_src_files := namespaces_root.cpp
|
||||||
|
libnstest_root_not_isolated_shared_libraries := libnstest_public libnstest_private_external
|
||||||
|
libnstest_root_not_isolated_install_to_out_data_dir := private_namespace_libs
|
||||||
|
libnstest_root_not_isolated_ldflags := -Wl,--rpath,\$$ORIGIN/../private_namespace_libs_external \
|
||||||
|
-Wl,--enable-new-dtags
|
||||||
|
|
||||||
|
module := libnstest_root_not_isolated
|
||||||
|
include $(LOCAL_PATH)/Android.build.target.testlib.mk
|
||||||
|
|
||||||
|
libnstest_private_external_src_files := namespaces_private.cpp
|
||||||
|
libnstest_private_external_install_to_out_data_dir := private_namespace_libs_external
|
||||||
|
module := libnstest_private_external
|
||||||
|
include $(LOCAL_PATH)/Android.build.target.testlib.mk
|
20
tests/libs/Android.build.target.testlib.mk
Normal file
20
tests/libs/Android.build.target.testlib.mk
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#
|
||||||
|
# Copyright (C) 2015 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
build_target := SHARED_LIBRARY
|
||||||
|
build_type := target
|
||||||
|
include $(TEST_PATH)/Android.build.mk
|
||||||
|
|
|
@ -26,6 +26,7 @@ common_additional_dependencies := \
|
||||||
$(LOCAL_PATH)/Android.build.dlopen_check_order_dlsym.mk \
|
$(LOCAL_PATH)/Android.build.dlopen_check_order_dlsym.mk \
|
||||||
$(LOCAL_PATH)/Android.build.dlopen_check_order_reloc_siblings.mk \
|
$(LOCAL_PATH)/Android.build.dlopen_check_order_reloc_siblings.mk \
|
||||||
$(LOCAL_PATH)/Android.build.dlopen_check_order_reloc_main_executable.mk \
|
$(LOCAL_PATH)/Android.build.dlopen_check_order_reloc_main_executable.mk \
|
||||||
|
$(LOCAL_PATH)/Android.build.linker_namespaces.mk \
|
||||||
$(LOCAL_PATH)/Android.build.pthread_atfork.mk \
|
$(LOCAL_PATH)/Android.build.pthread_atfork.mk \
|
||||||
$(LOCAL_PATH)/Android.build.testlib.mk \
|
$(LOCAL_PATH)/Android.build.testlib.mk \
|
||||||
$(LOCAL_PATH)/Android.build.versioned_lib.mk \
|
$(LOCAL_PATH)/Android.build.versioned_lib.mk \
|
||||||
|
@ -212,6 +213,11 @@ libtest_nodelete_dt_flags_1_ldflags := -Wl,-z,nodelete
|
||||||
module := libtest_nodelete_dt_flags_1
|
module := libtest_nodelete_dt_flags_1
|
||||||
include $(LOCAL_PATH)/Android.build.testlib.mk
|
include $(LOCAL_PATH)/Android.build.testlib.mk
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Build test helper libraries for linker namespaces
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
include $(LOCAL_PATH)/Android.build.linker_namespaces.mk
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Build DT_RUNPATH test helper libraries
|
# Build DT_RUNPATH test helper libraries
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
19
tests/libs/namespaces_dlopened.cpp
Normal file
19
tests/libs/namespaces_dlopened.cpp
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char* g_private_dlopened_string = "This string is from private namespace "
|
||||||
|
"(dlopened library)";
|
||||||
|
|
18
tests/libs/namespaces_private.cpp
Normal file
18
tests/libs/namespaces_private.cpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char* g_private_extern_string = "This string is from private namespace";
|
||||||
|
|
18
tests/libs/namespaces_public.cpp
Normal file
18
tests/libs/namespaces_public.cpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char* g_public_extern_string = "This string is from public namespace";
|
||||||
|
|
49
tests/libs/namespaces_root.cpp
Normal file
49
tests/libs/namespaces_root.cpp
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 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 <dlfcn.h>
|
||||||
|
|
||||||
|
static const char* g_local_string = "This string is local to root library";
|
||||||
|
extern "C" const char* g_private_extern_string;
|
||||||
|
extern "C" const char* g_public_extern_string;
|
||||||
|
|
||||||
|
bool g_dlopened = false;
|
||||||
|
|
||||||
|
extern "C" const char* ns_get_local_string() {
|
||||||
|
return g_local_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" const char* ns_get_private_extern_string() {
|
||||||
|
return g_private_extern_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" const char* ns_get_public_extern_string() {
|
||||||
|
return g_public_extern_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" const char* ns_get_dlopened_string() {
|
||||||
|
void* handle = dlopen("libnstest_dlopened.so", RTLD_NOW | RTLD_GLOBAL);
|
||||||
|
if (handle == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* result = *static_cast<const char**>(dlsym(handle, "g_private_dlopened_string"));
|
||||||
|
if (result != nullptr) {
|
||||||
|
g_dlopened = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
Loading…
Reference in a new issue