Allow sharing the RELRO section via a file.
Add flags and a file descriptor to android_dlopen_ext() to allow writing the RELRO section of the loaded library to a file after relocation processing, and to allow mapping identical pages from the file over the top of relocated memory in another process. Explicitly comparing the pages is required in case a page contains a reference to a symbol defined in another library loaded at a random base address. Bug: 13005501 Change-Id: Ibb5b2d384edfaa5acf3e97a5f8b6115c10497a1e
This commit is contained in:
@@ -17,8 +17,14 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <android/dlext.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
|
||||
#define ASSERT_DL_NOTNULL(ptr) \
|
||||
@@ -27,10 +33,14 @@
|
||||
#define ASSERT_DL_ZERO(i) \
|
||||
ASSERT_EQ(0, i) << "dlerror: " << dlerror()
|
||||
|
||||
#define ASSERT_NOERROR(i) \
|
||||
ASSERT_NE(-1, i) << "errno: " << strerror(errno)
|
||||
|
||||
|
||||
typedef int (*fn)(void);
|
||||
#define LIBNAME "libdlext_test.so"
|
||||
#define LIBSIZE 1024*1024 // how much address space to reserve for it
|
||||
#define RELRO_FILE "/data/local/tmp/libdlext_test.relro"
|
||||
|
||||
|
||||
class DlExtTest : public ::testing::Test {
|
||||
@@ -134,3 +144,49 @@ TEST_F(DlExtTest, ReservedHintTooSmall) {
|
||||
reinterpret_cast<char*>(start) + PAGE_SIZE));
|
||||
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;
|
||||
|
||||
int relro_fd;
|
||||
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
|
||||
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));
|
||||
|
||||
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));
|
||||
|
||||
ASSERT_DL_NOTNULL(handle_);
|
||||
fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
|
||||
ASSERT_DL_NOTNULL(f);
|
||||
EXPECT_EQ(4, f());
|
||||
}
|
||||
|
Reference in New Issue
Block a user