* commit 'b9b75697fa6c58a85f48d7f31113814385a709bd': Handle empty relro segment or incorrectly sized file.
This commit is contained in:
commit
e0a8474adf
@ -591,9 +591,12 @@ int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, El
|
||||
return -1;
|
||||
}
|
||||
off_t file_size = file_stat.st_size;
|
||||
void* temp_mapping = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (temp_mapping == MAP_FAILED) {
|
||||
return -1;
|
||||
void* temp_mapping = NULL;
|
||||
if (file_size > 0) {
|
||||
temp_mapping = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (temp_mapping == MAP_FAILED) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
size_t file_offset = 0;
|
||||
|
||||
@ -614,6 +617,13 @@ int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, El
|
||||
size_t match_offset = 0;
|
||||
size_t size = seg_page_end - seg_page_start;
|
||||
|
||||
if (file_size - file_offset < size) {
|
||||
// File is too short to compare to this segment. The contents are likely
|
||||
// different as well (it's probably for a different library version) so
|
||||
// just don't bother checking.
|
||||
break;
|
||||
}
|
||||
|
||||
while (match_offset < size) {
|
||||
// Skip over dissimilar pages.
|
||||
while (match_offset < size &&
|
||||
|
@ -198,17 +198,32 @@ include $(LOCAL_PATH)/Android.build.mk
|
||||
endif
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Library used by dlext tests.
|
||||
# Library used by dlext tests - with/without GNU RELRO program header
|
||||
# -----------------------------------------------------------------------------
|
||||
libdlext_test_src_files := \
|
||||
dlext_test_library.cpp \
|
||||
|
||||
libdlext_test_ldflags := \
|
||||
-Wl,-z,relro \
|
||||
|
||||
module := libdlext_test
|
||||
module_tag := optional
|
||||
build_type := target
|
||||
build_target := SHARED_LIBRARY
|
||||
include $(LOCAL_PATH)/Android.build.mk
|
||||
|
||||
libdlext_test_norelro_src_files := \
|
||||
dlext_test_library.cpp \
|
||||
|
||||
libdlext_test_norelro_ldflags := \
|
||||
-Wl,-z,norelro \
|
||||
|
||||
module := libdlext_test_norelro
|
||||
module_tag := optional
|
||||
build_type := target
|
||||
build_target := SHARED_LIBRARY
|
||||
include $(LOCAL_PATH)/Android.build.mk
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# This library used by atexit tests
|
||||
# -----------------------------------------------------------------------------
|
||||
|
@ -39,6 +39,7 @@
|
||||
|
||||
typedef int (*fn)(void);
|
||||
#define LIBNAME "libdlext_test.so"
|
||||
#define LIBNAME_NORELRO "libdlext_test_norelro.so"
|
||||
#define LIBSIZE 1024*1024 // how much address space to reserve for it
|
||||
|
||||
|
||||
@ -144,52 +145,88 @@ TEST_F(DlExtTest, ReservedHintTooSmall) {
|
||||
EXPECT_EQ(4, f());
|
||||
}
|
||||
|
||||
TEST_F(DlExtTest, RelroShareChildWrites) {
|
||||
void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
ASSERT_TRUE(start != MAP_FAILED);
|
||||
android_dlextinfo extinfo;
|
||||
extinfo.reserved_addr = start;
|
||||
extinfo.reserved_size = LIBSIZE;
|
||||
class DlExtRelroSharingTest : public DlExtTest {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
DlExtTest::SetUp();
|
||||
void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
ASSERT_TRUE(start != MAP_FAILED);
|
||||
extinfo_.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
|
||||
extinfo_.reserved_addr = start;
|
||||
extinfo_.reserved_size = LIBSIZE;
|
||||
extinfo_.relro_fd = -1;
|
||||
|
||||
int relro_fd;
|
||||
char relro_file[PATH_MAX];
|
||||
const char* android_data = getenv("ANDROID_DATA");
|
||||
ASSERT_TRUE(android_data != NULL);
|
||||
snprintf(relro_file, sizeof(relro_file), "%s/local/tmp/libdlext_test.relro", android_data);
|
||||
relro_fd = open(relro_file, O_CREAT | O_RDWR | O_TRUNC, 0644);
|
||||
extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_WRITE_RELRO;
|
||||
ASSERT_NOERROR(relro_fd);
|
||||
extinfo.relro_fd = relro_fd;
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
// child process
|
||||
void* handle = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
|
||||
if (handle == NULL) {
|
||||
fprintf(stderr, "in child: %s\n", dlerror());
|
||||
exit(1);
|
||||
}
|
||||
exit(0);
|
||||
const char* android_data = getenv("ANDROID_DATA");
|
||||
ASSERT_TRUE(android_data != NULL);
|
||||
snprintf(relro_file_, sizeof(relro_file_), "%s/local/tmp/libdlext_test.relro", android_data);
|
||||
}
|
||||
|
||||
// continuing in parent
|
||||
ASSERT_NOERROR(close(relro_fd));
|
||||
ASSERT_NOERROR(pid);
|
||||
int status;
|
||||
ASSERT_EQ(pid, waitpid(pid, &status, 0));
|
||||
ASSERT_TRUE(WIFEXITED(status));
|
||||
ASSERT_EQ(0, WEXITSTATUS(status));
|
||||
virtual void TearDown() {
|
||||
DlExtTest::TearDown();
|
||||
if (extinfo_.relro_fd != -1) {
|
||||
ASSERT_NOERROR(close(extinfo_.relro_fd));
|
||||
}
|
||||
}
|
||||
|
||||
relro_fd = open(relro_file, O_RDONLY);
|
||||
ASSERT_NOERROR(relro_fd);
|
||||
extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_USE_RELRO;
|
||||
extinfo.relro_fd = relro_fd;
|
||||
handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
|
||||
ASSERT_NOERROR(close(relro_fd));
|
||||
void CreateRelroFile(const char* lib) {
|
||||
int relro_fd = open(relro_file_, O_CREAT | O_RDWR | O_TRUNC, 0644);
|
||||
ASSERT_NOERROR(relro_fd);
|
||||
|
||||
ASSERT_DL_NOTNULL(handle_);
|
||||
fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
|
||||
ASSERT_DL_NOTNULL(f);
|
||||
EXPECT_EQ(4, f());
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
// child process
|
||||
extinfo_.flags |= ANDROID_DLEXT_WRITE_RELRO;
|
||||
extinfo_.relro_fd = relro_fd;
|
||||
void* handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
|
||||
if (handle == NULL) {
|
||||
fprintf(stderr, "in child: %s\n", dlerror());
|
||||
exit(1);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// continuing in parent
|
||||
ASSERT_NOERROR(close(relro_fd));
|
||||
ASSERT_NOERROR(pid);
|
||||
int status;
|
||||
ASSERT_EQ(pid, waitpid(pid, &status, 0));
|
||||
ASSERT_TRUE(WIFEXITED(status));
|
||||
ASSERT_EQ(0, WEXITSTATUS(status));
|
||||
|
||||
// reopen file for reading so it can be used
|
||||
relro_fd = open(relro_file_, O_RDONLY);
|
||||
ASSERT_NOERROR(relro_fd);
|
||||
extinfo_.flags |= ANDROID_DLEXT_USE_RELRO;
|
||||
extinfo_.relro_fd = relro_fd;
|
||||
}
|
||||
|
||||
void TryUsingRelro(const char* lib) {
|
||||
handle_ = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
|
||||
ASSERT_DL_NOTNULL(handle_);
|
||||
fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
|
||||
ASSERT_DL_NOTNULL(f);
|
||||
EXPECT_EQ(4, f());
|
||||
}
|
||||
|
||||
android_dlextinfo extinfo_;
|
||||
char relro_file_[PATH_MAX];
|
||||
};
|
||||
|
||||
TEST_F(DlExtRelroSharingTest, ChildWritesGoodData) {
|
||||
ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME));
|
||||
ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME));
|
||||
}
|
||||
|
||||
TEST_F(DlExtRelroSharingTest, ChildWritesNoRelro) {
|
||||
ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME_NORELRO));
|
||||
ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME_NORELRO));
|
||||
}
|
||||
|
||||
TEST_F(DlExtRelroSharingTest, RelroFileEmpty) {
|
||||
int relro_fd = open(relro_file_, O_CREAT | O_RDWR | O_TRUNC, 0644);
|
||||
ASSERT_NOERROR(relro_fd);
|
||||
ASSERT_NOERROR(close(relro_fd));
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user