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