dlext_test.cpp revision 53c884e28166678b2fa40cb3763d1549074628ad
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <gtest/gtest.h> 18 19#include <dlfcn.h> 20#include <errno.h> 21#include <fcntl.h> 22#include <stdio.h> 23#include <string.h> 24#include <unistd.h> 25#include <android/dlext.h> 26#include <sys/mman.h> 27#include <sys/wait.h> 28 29 30#define ASSERT_DL_NOTNULL(ptr) \ 31 ASSERT_TRUE(ptr != NULL) << "dlerror: " << dlerror() 32 33#define ASSERT_DL_ZERO(i) \ 34 ASSERT_EQ(0, i) << "dlerror: " << dlerror() 35 36#define ASSERT_NOERROR(i) \ 37 ASSERT_NE(-1, i) << "errno: " << strerror(errno) 38 39 40typedef int (*fn)(void); 41#define LIBNAME "libdlext_test.so" 42#define LIBSIZE 1024*1024 // how much address space to reserve for it 43 44 45class DlExtTest : public ::testing::Test { 46protected: 47 virtual void SetUp() { 48 handle_ = NULL; 49 // verify that we don't have the library loaded already 50 ASSERT_EQ(NULL, dlsym(RTLD_DEFAULT, "getRandomNumber")); 51 // call dlerror() to swallow the error, and check it was the one we wanted 52 ASSERT_STREQ("undefined symbol: getRandomNumber", dlerror()); 53 } 54 55 virtual void TearDown() { 56 if (handle_ != NULL) { 57 ASSERT_DL_ZERO(dlclose(handle_)); 58 } 59 } 60 61 void* handle_; 62}; 63 64TEST_F(DlExtTest, ExtInfoNull) { 65 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, NULL); 66 ASSERT_DL_NOTNULL(handle_); 67 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); 68 ASSERT_DL_NOTNULL(f); 69 EXPECT_EQ(4, f()); 70} 71 72TEST_F(DlExtTest, ExtInfoNoFlags) { 73 android_dlextinfo extinfo; 74 extinfo.flags = 0; 75 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo); 76 ASSERT_DL_NOTNULL(handle_); 77 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); 78 ASSERT_DL_NOTNULL(f); 79 EXPECT_EQ(4, f()); 80} 81 82TEST_F(DlExtTest, Reserved) { 83 void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 84 -1, 0); 85 ASSERT_TRUE(start != MAP_FAILED); 86 android_dlextinfo extinfo; 87 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS; 88 extinfo.reserved_addr = start; 89 extinfo.reserved_size = LIBSIZE; 90 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo); 91 ASSERT_DL_NOTNULL(handle_); 92 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); 93 ASSERT_DL_NOTNULL(f); 94 EXPECT_GE(f, start); 95 EXPECT_LT(reinterpret_cast<void*>(f), 96 reinterpret_cast<char*>(start) + LIBSIZE); 97 EXPECT_EQ(4, f()); 98} 99 100TEST_F(DlExtTest, ReservedTooSmall) { 101 void* start = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 102 -1, 0); 103 ASSERT_TRUE(start != MAP_FAILED); 104 android_dlextinfo extinfo; 105 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS; 106 extinfo.reserved_addr = start; 107 extinfo.reserved_size = PAGE_SIZE; 108 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo); 109 EXPECT_EQ(NULL, handle_); 110} 111 112TEST_F(DlExtTest, ReservedHint) { 113 void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 114 -1, 0); 115 ASSERT_TRUE(start != MAP_FAILED); 116 android_dlextinfo extinfo; 117 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT; 118 extinfo.reserved_addr = start; 119 extinfo.reserved_size = LIBSIZE; 120 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo); 121 ASSERT_DL_NOTNULL(handle_); 122 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); 123 ASSERT_DL_NOTNULL(f); 124 EXPECT_GE(f, start); 125 EXPECT_LT(reinterpret_cast<void*>(f), 126 reinterpret_cast<char*>(start) + LIBSIZE); 127 EXPECT_EQ(4, f()); 128} 129 130TEST_F(DlExtTest, ReservedHintTooSmall) { 131 void* start = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 132 -1, 0); 133 ASSERT_TRUE(start != MAP_FAILED); 134 android_dlextinfo extinfo; 135 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT; 136 extinfo.reserved_addr = start; 137 extinfo.reserved_size = PAGE_SIZE; 138 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo); 139 ASSERT_DL_NOTNULL(handle_); 140 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); 141 ASSERT_DL_NOTNULL(f); 142 EXPECT_TRUE(f < start || (reinterpret_cast<void*>(f) >= 143 reinterpret_cast<char*>(start) + PAGE_SIZE)); 144 EXPECT_EQ(4, f()); 145} 146 147TEST_F(DlExtTest, RelroShareChildWrites) { 148 void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 149 -1, 0); 150 ASSERT_TRUE(start != MAP_FAILED); 151 android_dlextinfo extinfo; 152 extinfo.reserved_addr = start; 153 extinfo.reserved_size = LIBSIZE; 154 155 int relro_fd; 156 char relro_file[PATH_MAX]; 157 const char* android_data = getenv("ANDROID_DATA"); 158 ASSERT_TRUE(android_data != NULL); 159 snprintf(relro_file, sizeof(relro_file), "%s/local/tmp/libdlext_test.relro", android_data); 160 relro_fd = open(relro_file, O_CREAT | O_RDWR | O_TRUNC, 0644); 161 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_WRITE_RELRO; 162 ASSERT_NOERROR(relro_fd); 163 extinfo.relro_fd = relro_fd; 164 165 pid_t pid = fork(); 166 if (pid == 0) { 167 // child process 168 void* handle = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo); 169 if (handle == NULL) { 170 fprintf(stderr, "in child: %s\n", dlerror()); 171 exit(1); 172 } 173 exit(0); 174 } 175 176 // continuing in parent 177 ASSERT_NOERROR(close(relro_fd)); 178 ASSERT_NOERROR(pid); 179 int status; 180 ASSERT_EQ(pid, waitpid(pid, &status, 0)); 181 ASSERT_TRUE(WIFEXITED(status)); 182 ASSERT_EQ(0, WEXITSTATUS(status)); 183 184 relro_fd = open(relro_file, O_RDONLY); 185 ASSERT_NOERROR(relro_fd); 186 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_USE_RELRO; 187 extinfo.relro_fd = relro_fd; 188 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo); 189 ASSERT_NOERROR(close(relro_fd)); 190 191 ASSERT_DL_NOTNULL(handle_); 192 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); 193 ASSERT_DL_NOTNULL(f); 194 EXPECT_EQ(4, f()); 195} 196