Check for unknown flags passed to dlopen(3).

Change-Id: I56f4aab0e5a1487bc32d2c4d231e8bd15c4ac8da
This commit is contained in:
Elliott Hughes 2012-12-18 15:57:55 -08:00
parent 4c4b08a32e
commit e66190d2a9
6 changed files with 46 additions and 21 deletions

View file

@ -22,7 +22,7 @@ LOCAL_LDFLAGS := -shared
LOCAL_CFLAGS += -fno-stack-protector \
-Wstrict-overflow=5 \
-fvisibility=hidden \
-Wall -Wextra
-Wall -Wextra -Werror
# We need to access Bionic private headers in the linker...
LOCAL_CFLAGS += -I$(LOCAL_PATH)/../libc/

View file

@ -55,9 +55,9 @@ const char* dlerror() {
return old_value;
}
void* dlopen(const char* filename, int flag) {
void* dlopen(const char* filename, int flags) {
ScopedPthreadMutexLocker locker(&gDlMutex);
soinfo* result = do_dlopen(filename);
soinfo* result = do_dlopen(filename, flags);
if (result == NULL) {
__bionic_format_dlerror("dlopen failed", linker_get_error());
return NULL;

View file

@ -966,7 +966,11 @@ static int soinfo_unload(soinfo* si) {
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);
soinfo* si = find_library(name);
if (si != NULL) {

View file

@ -207,7 +207,7 @@ extern soinfo libdl_info;
#define DT_PREINIT_ARRAYSZ 33
#endif
soinfo* do_dlopen(const char* name);
soinfo* do_dlopen(const char* name, int flags);
int do_dlclose(soinfo* si);
Elf32_Sym* lookup(const char* name, soinfo** found, soinfo* start);

View file

@ -68,7 +68,7 @@ test_src_files = \
test_dynamic_ldflags = -Wl,--export-dynamic -Wl,-u,DlSymTestFunction
test_dynamic_src_files = \
dlopen_test.cpp \
dlfcn_test.cpp \
# Build tests for the device (with bionic's .so). Run with:
# adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests

View file

@ -32,7 +32,7 @@ extern "C" void DlSymTestFunction() {
gCalled = true;
}
TEST(dlopen, dlsym_in_self) {
TEST(dlfcn, dlsym_in_self) {
dlerror(); // Clear any pending errors.
void* self = dlopen(NULL, RTLD_NOW);
ASSERT_TRUE(self != NULL);
@ -50,7 +50,7 @@ TEST(dlopen, dlsym_in_self) {
ASSERT_EQ(0, dlclose(self));
}
TEST(dlopen, dlopen_failure) {
TEST(dlfcn, dlopen_failure) {
void* self = dlopen("/does/not/exist", RTLD_NOW);
ASSERT_TRUE(self == NULL);
#if __BIONIC__
@ -65,7 +65,7 @@ static void* ConcurrentDlErrorFn(void*) {
return reinterpret_cast<void*>(strdup(dlerror()));
}
TEST(dlopen, dlerror_concurrent) {
TEST(dlfcn, dlerror_concurrent) {
dlopen("/main/thread", RTLD_NOW);
const char* main_thread_error = dlerror();
ASSERT_SUBSTR("/main/thread", main_thread_error);
@ -81,7 +81,7 @@ TEST(dlopen, dlerror_concurrent) {
ASSERT_SUBSTR("/main/thread", main_thread_error);
}
TEST(dlopen, dlsym_failures) {
TEST(dlfcn, dlsym_failures) {
dlerror(); // Clear any pending errors.
void* self = dlopen(NULL, RTLD_NOW);
ASSERT_TRUE(self != NULL);
@ -114,7 +114,7 @@ TEST(dlopen, dlsym_failures) {
ASSERT_EQ(0, dlclose(self));
}
TEST(dlopen, dladdr) {
TEST(dlfcn, dladdr) {
dlerror(); // Clear any pending errors.
void* self = dlopen(NULL, RTLD_NOW);
ASSERT_TRUE(self != NULL);
@ -174,7 +174,7 @@ TEST(dlopen, dladdr) {
ASSERT_EQ(0, dlclose(self));
}
TEST(dlopen, dladdr_invalid) {
TEST(dlfcn, dladdr_invalid) {
Dl_info info;
dlerror(); // Clear any pending errors.
@ -190,10 +190,31 @@ TEST(dlopen, dladdr_invalid) {
#if __BIONIC__
// 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.
void* handle = dlopen("no-elf-hash-table-library.so", RTLD_NOW);
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());
}
#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());
}