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; return -1;
} }
off_t file_size = file_stat.st_size; off_t file_size = file_stat.st_size;
void* temp_mapping = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0); void* temp_mapping = NULL;
if (temp_mapping == MAP_FAILED) { if (file_size > 0) {
return -1; temp_mapping = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (temp_mapping == MAP_FAILED) {
return -1;
}
} }
size_t file_offset = 0; 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 match_offset = 0;
size_t size = seg_page_end - seg_page_start; 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) { while (match_offset < size) {
// Skip over dissimilar pages. // Skip over dissimilar pages.
while (match_offset < size && while (match_offset < size &&

View File

@ -198,17 +198,32 @@ include $(LOCAL_PATH)/Android.build.mk
endif endif
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Library used by dlext tests. # Library used by dlext tests - with/without GNU RELRO program header
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
libdlext_test_src_files := \ libdlext_test_src_files := \
dlext_test_library.cpp \ dlext_test_library.cpp \
libdlext_test_ldflags := \
-Wl,-z,relro \
module := libdlext_test module := libdlext_test
module_tag := optional module_tag := optional
build_type := target build_type := target
build_target := SHARED_LIBRARY build_target := SHARED_LIBRARY
include $(LOCAL_PATH)/Android.build.mk 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 # This library used by atexit tests
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------

View File

@ -39,6 +39,7 @@
typedef int (*fn)(void); typedef int (*fn)(void);
#define LIBNAME "libdlext_test.so" #define LIBNAME "libdlext_test.so"
#define LIBNAME_NORELRO "libdlext_test_norelro.so"
#define LIBSIZE 1024*1024 // how much address space to reserve for it #define LIBSIZE 1024*1024 // how much address space to reserve for it
@ -144,52 +145,88 @@ TEST_F(DlExtTest, ReservedHintTooSmall) {
EXPECT_EQ(4, f()); EXPECT_EQ(4, f());
} }
TEST_F(DlExtTest, RelroShareChildWrites) { class DlExtRelroSharingTest : public DlExtTest {
void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, protected:
-1, 0); virtual void SetUp() {
ASSERT_TRUE(start != MAP_FAILED); DlExtTest::SetUp();
android_dlextinfo extinfo; void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
extinfo.reserved_addr = start; -1, 0);
extinfo.reserved_size = LIBSIZE; 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; const char* android_data = getenv("ANDROID_DATA");
char relro_file[PATH_MAX]; ASSERT_TRUE(android_data != NULL);
const char* android_data = getenv("ANDROID_DATA"); snprintf(relro_file_, sizeof(relro_file_), "%s/local/tmp/libdlext_test.relro", 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);
} }
// continuing in parent virtual void TearDown() {
ASSERT_NOERROR(close(relro_fd)); DlExtTest::TearDown();
ASSERT_NOERROR(pid); if (extinfo_.relro_fd != -1) {
int status; ASSERT_NOERROR(close(extinfo_.relro_fd));
ASSERT_EQ(pid, waitpid(pid, &status, 0)); }
ASSERT_TRUE(WIFEXITED(status)); }
ASSERT_EQ(0, WEXITSTATUS(status));
relro_fd = open(relro_file, O_RDONLY); void CreateRelroFile(const char* lib) {
ASSERT_NOERROR(relro_fd); int relro_fd = open(relro_file_, O_CREAT | O_RDWR | O_TRUNC, 0644);
extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_USE_RELRO; ASSERT_NOERROR(relro_fd);
extinfo.relro_fd = relro_fd;
handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
ASSERT_NOERROR(close(relro_fd));
ASSERT_DL_NOTNULL(handle_); pid_t pid = fork();
fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); if (pid == 0) {
ASSERT_DL_NOTNULL(f); // child process
EXPECT_EQ(4, f()); 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));
} }