am b9b75697: am 9b5ee4aa: Merge "Handle empty relro segment or incorrectly sized file."

* commit 'b9b75697fa6c58a85f48d7f31113814385a709bd':
  Handle empty relro segment or incorrectly sized file.
This commit is contained in:
Torne (Richard Coles) 2014-05-06 10:22:39 +00:00 committed by Android Git Automerger
commit e0a8474adf
3 changed files with 109 additions and 47 deletions

View File

@ -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 &&

View File

@ -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
# -----------------------------------------------------------------------------

View File

@ -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));
}