blob: 14dff2bc87c4d2ccc9ff01a7c20bd3fa2fee65f7 [file] [log] [blame]
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +00001/*
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>
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +000020#include <errno.h>
21#include <fcntl.h>
22#include <stdio.h>
23#include <string.h>
24#include <unistd.h>
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000025#include <android/dlext.h>
26#include <sys/mman.h>
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +000027#include <sys/wait.h>
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000028
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
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +000036#define ASSERT_NOERROR(i) \
37 ASSERT_NE(-1, i) << "errno: " << strerror(errno)
38
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000039
40typedef int (*fn)(void);
41#define LIBNAME "libdlext_test.so"
42#define LIBSIZE 1024*1024 // how much address space to reserve for it
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +000043#define RELRO_FILE "/data/local/tmp/libdlext_test.relro"
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000044
45
46class DlExtTest : public ::testing::Test {
47protected:
48 virtual void SetUp() {
49 handle_ = NULL;
50 // verify that we don't have the library loaded already
51 ASSERT_EQ(NULL, dlsym(RTLD_DEFAULT, "getRandomNumber"));
52 // call dlerror() to swallow the error, and check it was the one we wanted
53 ASSERT_STREQ("undefined symbol: getRandomNumber", dlerror());
54 }
55
56 virtual void TearDown() {
57 if (handle_ != NULL) {
58 ASSERT_DL_ZERO(dlclose(handle_));
59 }
60 }
61
62 void* handle_;
63};
64
65TEST_F(DlExtTest, ExtInfoNull) {
66 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, NULL);
67 ASSERT_DL_NOTNULL(handle_);
68 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
69 ASSERT_DL_NOTNULL(f);
70 EXPECT_EQ(4, f());
71}
72
73TEST_F(DlExtTest, ExtInfoNoFlags) {
74 android_dlextinfo extinfo;
75 extinfo.flags = 0;
76 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
77 ASSERT_DL_NOTNULL(handle_);
78 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
79 ASSERT_DL_NOTNULL(f);
80 EXPECT_EQ(4, f());
81}
82
83TEST_F(DlExtTest, Reserved) {
84 void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
85 -1, 0);
86 ASSERT_TRUE(start != MAP_FAILED);
87 android_dlextinfo extinfo;
88 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
89 extinfo.reserved_addr = start;
90 extinfo.reserved_size = LIBSIZE;
91 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
92 ASSERT_DL_NOTNULL(handle_);
93 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
94 ASSERT_DL_NOTNULL(f);
95 EXPECT_GE(f, start);
96 EXPECT_LT(reinterpret_cast<void*>(f),
97 reinterpret_cast<char*>(start) + LIBSIZE);
98 EXPECT_EQ(4, f());
99}
100
101TEST_F(DlExtTest, ReservedTooSmall) {
102 void* start = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
103 -1, 0);
104 ASSERT_TRUE(start != MAP_FAILED);
105 android_dlextinfo extinfo;
106 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
107 extinfo.reserved_addr = start;
108 extinfo.reserved_size = PAGE_SIZE;
109 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
110 EXPECT_EQ(NULL, handle_);
111}
112
113TEST_F(DlExtTest, ReservedHint) {
114 void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
115 -1, 0);
116 ASSERT_TRUE(start != MAP_FAILED);
117 android_dlextinfo extinfo;
118 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT;
119 extinfo.reserved_addr = start;
120 extinfo.reserved_size = LIBSIZE;
121 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
122 ASSERT_DL_NOTNULL(handle_);
123 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
124 ASSERT_DL_NOTNULL(f);
125 EXPECT_GE(f, start);
126 EXPECT_LT(reinterpret_cast<void*>(f),
127 reinterpret_cast<char*>(start) + LIBSIZE);
128 EXPECT_EQ(4, f());
129}
130
131TEST_F(DlExtTest, ReservedHintTooSmall) {
132 void* start = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
133 -1, 0);
134 ASSERT_TRUE(start != MAP_FAILED);
135 android_dlextinfo extinfo;
136 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT;
137 extinfo.reserved_addr = start;
138 extinfo.reserved_size = PAGE_SIZE;
139 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
140 ASSERT_DL_NOTNULL(handle_);
141 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
142 ASSERT_DL_NOTNULL(f);
143 EXPECT_TRUE(f < start || (reinterpret_cast<void*>(f) >=
144 reinterpret_cast<char*>(start) + PAGE_SIZE));
145 EXPECT_EQ(4, f());
146}
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000147
148TEST_F(DlExtTest, RelroShareChildWrites) {
149 void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
150 -1, 0);
151 ASSERT_TRUE(start != MAP_FAILED);
152 android_dlextinfo extinfo;
153 extinfo.reserved_addr = start;
154 extinfo.reserved_size = LIBSIZE;
155
156 int relro_fd;
157 relro_fd = open(RELRO_FILE, O_CREAT | O_RDWR | O_TRUNC, 0644);
158 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_WRITE_RELRO;
159 ASSERT_NOERROR(relro_fd);
160 extinfo.relro_fd = relro_fd;
161
162 pid_t pid = fork();
163 if (pid == 0) {
164 // child process
165 void* handle = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
166 if (handle == NULL) {
167 fprintf(stderr, "in child: %s\n", dlerror());
168 exit(1);
169 }
170 exit(0);
171 }
172
173 // continuing in parent
174 ASSERT_NOERROR(close(relro_fd));
175 ASSERT_NOERROR(pid);
176 int status;
177 ASSERT_EQ(pid, waitpid(pid, &status, 0));
178 ASSERT_TRUE(WIFEXITED(status));
179 ASSERT_EQ(0, WEXITSTATUS(status));
180
181 relro_fd = open(RELRO_FILE, O_RDONLY);
182 ASSERT_NOERROR(relro_fd);
183 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_USE_RELRO;
184 extinfo.relro_fd = relro_fd;
185 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
186 ASSERT_NOERROR(close(relro_fd));
187
188 ASSERT_DL_NOTNULL(handle_);
189 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
190 ASSERT_DL_NOTNULL(f);
191 EXPECT_EQ(4, f());
192}