Check for unknown flags passed to dlopen(3).
Change-Id: I56f4aab0e5a1487bc32d2c4d231e8bd15c4ac8da
This commit is contained in:
parent
4c4b08a32e
commit
e66190d2a9
@ -22,7 +22,7 @@ LOCAL_LDFLAGS := -shared
|
|||||||
LOCAL_CFLAGS += -fno-stack-protector \
|
LOCAL_CFLAGS += -fno-stack-protector \
|
||||||
-Wstrict-overflow=5 \
|
-Wstrict-overflow=5 \
|
||||||
-fvisibility=hidden \
|
-fvisibility=hidden \
|
||||||
-Wall -Wextra
|
-Wall -Wextra -Werror
|
||||||
|
|
||||||
# We need to access Bionic private headers in the linker...
|
# We need to access Bionic private headers in the linker...
|
||||||
LOCAL_CFLAGS += -I$(LOCAL_PATH)/../libc/
|
LOCAL_CFLAGS += -I$(LOCAL_PATH)/../libc/
|
||||||
|
@ -55,9 +55,9 @@ const char* dlerror() {
|
|||||||
return old_value;
|
return old_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* dlopen(const char* filename, int flag) {
|
void* dlopen(const char* filename, int flags) {
|
||||||
ScopedPthreadMutexLocker locker(&gDlMutex);
|
ScopedPthreadMutexLocker locker(&gDlMutex);
|
||||||
soinfo* result = do_dlopen(filename);
|
soinfo* result = do_dlopen(filename, flags);
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
__bionic_format_dlerror("dlopen failed", linker_get_error());
|
__bionic_format_dlerror("dlopen failed", linker_get_error());
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -966,7 +966,11 @@ static int soinfo_unload(soinfo* si) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
soinfo* do_dlopen(const char* name) {
|
soinfo* do_dlopen(const char* name, int flags) {
|
||||||
|
if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL)) != 0) {
|
||||||
|
DL_ERR("invalid flags to dlopen: %x", flags);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
set_soinfo_pool_protection(PROT_READ | PROT_WRITE);
|
set_soinfo_pool_protection(PROT_READ | PROT_WRITE);
|
||||||
soinfo* si = find_library(name);
|
soinfo* si = find_library(name);
|
||||||
if (si != NULL) {
|
if (si != NULL) {
|
||||||
|
@ -207,7 +207,7 @@ extern soinfo libdl_info;
|
|||||||
#define DT_PREINIT_ARRAYSZ 33
|
#define DT_PREINIT_ARRAYSZ 33
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
soinfo* do_dlopen(const char* name);
|
soinfo* do_dlopen(const char* name, int flags);
|
||||||
int do_dlclose(soinfo* si);
|
int do_dlclose(soinfo* si);
|
||||||
|
|
||||||
Elf32_Sym* lookup(const char* name, soinfo** found, soinfo* start);
|
Elf32_Sym* lookup(const char* name, soinfo** found, soinfo* start);
|
||||||
|
@ -68,7 +68,7 @@ test_src_files = \
|
|||||||
|
|
||||||
test_dynamic_ldflags = -Wl,--export-dynamic -Wl,-u,DlSymTestFunction
|
test_dynamic_ldflags = -Wl,--export-dynamic -Wl,-u,DlSymTestFunction
|
||||||
test_dynamic_src_files = \
|
test_dynamic_src_files = \
|
||||||
dlopen_test.cpp \
|
dlfcn_test.cpp \
|
||||||
|
|
||||||
# Build tests for the device (with bionic's .so). Run with:
|
# Build tests for the device (with bionic's .so). Run with:
|
||||||
# adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests
|
# adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests
|
||||||
|
@ -32,7 +32,7 @@ extern "C" void DlSymTestFunction() {
|
|||||||
gCalled = true;
|
gCalled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(dlopen, dlsym_in_self) {
|
TEST(dlfcn, dlsym_in_self) {
|
||||||
dlerror(); // Clear any pending errors.
|
dlerror(); // Clear any pending errors.
|
||||||
void* self = dlopen(NULL, RTLD_NOW);
|
void* self = dlopen(NULL, RTLD_NOW);
|
||||||
ASSERT_TRUE(self != NULL);
|
ASSERT_TRUE(self != NULL);
|
||||||
@ -50,7 +50,7 @@ TEST(dlopen, dlsym_in_self) {
|
|||||||
ASSERT_EQ(0, dlclose(self));
|
ASSERT_EQ(0, dlclose(self));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(dlopen, dlopen_failure) {
|
TEST(dlfcn, dlopen_failure) {
|
||||||
void* self = dlopen("/does/not/exist", RTLD_NOW);
|
void* self = dlopen("/does/not/exist", RTLD_NOW);
|
||||||
ASSERT_TRUE(self == NULL);
|
ASSERT_TRUE(self == NULL);
|
||||||
#if __BIONIC__
|
#if __BIONIC__
|
||||||
@ -65,7 +65,7 @@ static void* ConcurrentDlErrorFn(void*) {
|
|||||||
return reinterpret_cast<void*>(strdup(dlerror()));
|
return reinterpret_cast<void*>(strdup(dlerror()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(dlopen, dlerror_concurrent) {
|
TEST(dlfcn, dlerror_concurrent) {
|
||||||
dlopen("/main/thread", RTLD_NOW);
|
dlopen("/main/thread", RTLD_NOW);
|
||||||
const char* main_thread_error = dlerror();
|
const char* main_thread_error = dlerror();
|
||||||
ASSERT_SUBSTR("/main/thread", main_thread_error);
|
ASSERT_SUBSTR("/main/thread", main_thread_error);
|
||||||
@ -81,7 +81,7 @@ TEST(dlopen, dlerror_concurrent) {
|
|||||||
ASSERT_SUBSTR("/main/thread", main_thread_error);
|
ASSERT_SUBSTR("/main/thread", main_thread_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(dlopen, dlsym_failures) {
|
TEST(dlfcn, dlsym_failures) {
|
||||||
dlerror(); // Clear any pending errors.
|
dlerror(); // Clear any pending errors.
|
||||||
void* self = dlopen(NULL, RTLD_NOW);
|
void* self = dlopen(NULL, RTLD_NOW);
|
||||||
ASSERT_TRUE(self != NULL);
|
ASSERT_TRUE(self != NULL);
|
||||||
@ -114,7 +114,7 @@ TEST(dlopen, dlsym_failures) {
|
|||||||
ASSERT_EQ(0, dlclose(self));
|
ASSERT_EQ(0, dlclose(self));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(dlopen, dladdr) {
|
TEST(dlfcn, dladdr) {
|
||||||
dlerror(); // Clear any pending errors.
|
dlerror(); // Clear any pending errors.
|
||||||
void* self = dlopen(NULL, RTLD_NOW);
|
void* self = dlopen(NULL, RTLD_NOW);
|
||||||
ASSERT_TRUE(self != NULL);
|
ASSERT_TRUE(self != NULL);
|
||||||
@ -174,7 +174,7 @@ TEST(dlopen, dladdr) {
|
|||||||
ASSERT_EQ(0, dlclose(self));
|
ASSERT_EQ(0, dlclose(self));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(dlopen, dladdr_invalid) {
|
TEST(dlfcn, dladdr_invalid) {
|
||||||
Dl_info info;
|
Dl_info info;
|
||||||
|
|
||||||
dlerror(); // Clear any pending errors.
|
dlerror(); // Clear any pending errors.
|
||||||
@ -190,10 +190,31 @@ TEST(dlopen, dladdr_invalid) {
|
|||||||
|
|
||||||
#if __BIONIC__
|
#if __BIONIC__
|
||||||
// Our dynamic linker doesn't support GNU hash tables.
|
// Our dynamic linker doesn't support GNU hash tables.
|
||||||
TEST(dlopen, library_with_only_gnu_hash) {
|
TEST(dlfcn, dlopen_library_with_only_gnu_hash) {
|
||||||
dlerror(); // Clear any pending errors.
|
dlerror(); // Clear any pending errors.
|
||||||
void* handle = dlopen("no-elf-hash-table-library.so", RTLD_NOW);
|
void* handle = dlopen("no-elf-hash-table-library.so", RTLD_NOW);
|
||||||
ASSERT_TRUE(handle == NULL);
|
ASSERT_TRUE(handle == NULL);
|
||||||
ASSERT_STREQ("dlopen failed: empty/missing DT_HASH in \"no-elf-hash-table-library.so\" (built with --hash-style=gnu?)", dlerror());
|
ASSERT_STREQ("dlopen failed: empty/missing DT_HASH in \"no-elf-hash-table-library.so\" (built with --hash-style=gnu?)", dlerror());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
TEST(dlfcn, dlopen_bad_flags) {
|
||||||
|
dlerror(); // Clear any pending errors.
|
||||||
|
void* handle;
|
||||||
|
|
||||||
|
#ifdef __GLIBC__
|
||||||
|
// glibc was smart enough not to define RTLD_NOW as 0, so it can detect missing flags.
|
||||||
|
handle = dlopen(NULL, 0);
|
||||||
|
ASSERT_TRUE(handle == NULL);
|
||||||
|
ASSERT_SUBSTR("invalid", dlerror());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
handle = dlopen(NULL, 0xffffffff);
|
||||||
|
ASSERT_TRUE(handle == NULL);
|
||||||
|
ASSERT_SUBSTR("invalid", dlerror());
|
||||||
|
|
||||||
|
// glibc actually allows you to choose both RTLD_NOW and RTLD_LAZY at the same time, and so do we.
|
||||||
|
handle = dlopen(NULL, RTLD_NOW|RTLD_LAZY);
|
||||||
|
ASSERT_TRUE(handle != NULL);
|
||||||
|
ASSERT_SUBSTR(NULL, dlerror());
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user