blob: 4b2a5e23cecbf97a1a5a36b3733df5bc51175b69 [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"
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +010042#define LIBNAME_NORELRO "libdlext_test_norelro.so"
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000043#define LIBSIZE 1024*1024 // how much address space to reserve for it
44
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
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100148class DlExtRelroSharingTest : public DlExtTest {
149protected:
150 virtual void SetUp() {
151 DlExtTest::SetUp();
152 void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
153 -1, 0);
154 ASSERT_TRUE(start != MAP_FAILED);
155 extinfo_.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
156 extinfo_.reserved_addr = start;
157 extinfo_.reserved_size = LIBSIZE;
158 extinfo_.relro_fd = -1;
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000159
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100160 const char* android_data = getenv("ANDROID_DATA");
161 ASSERT_TRUE(android_data != NULL);
162 snprintf(relro_file_, sizeof(relro_file_), "%s/local/tmp/libdlext_test.relro", android_data);
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000163 }
164
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100165 virtual void TearDown() {
166 DlExtTest::TearDown();
167 if (extinfo_.relro_fd != -1) {
168 ASSERT_NOERROR(close(extinfo_.relro_fd));
169 }
170 }
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000171
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100172 void CreateRelroFile(const char* lib) {
173 int relro_fd = open(relro_file_, O_CREAT | O_RDWR | O_TRUNC, 0644);
174 ASSERT_NOERROR(relro_fd);
175
176 pid_t pid = fork();
177 if (pid == 0) {
178 // child process
179 extinfo_.flags |= ANDROID_DLEXT_WRITE_RELRO;
180 extinfo_.relro_fd = relro_fd;
181 void* handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
182 if (handle == NULL) {
183 fprintf(stderr, "in child: %s\n", dlerror());
184 exit(1);
185 }
186 exit(0);
187 }
188
189 // continuing in parent
190 ASSERT_NOERROR(close(relro_fd));
191 ASSERT_NOERROR(pid);
192 int status;
193 ASSERT_EQ(pid, waitpid(pid, &status, 0));
194 ASSERT_TRUE(WIFEXITED(status));
195 ASSERT_EQ(0, WEXITSTATUS(status));
196
197 // reopen file for reading so it can be used
198 relro_fd = open(relro_file_, O_RDONLY);
199 ASSERT_NOERROR(relro_fd);
200 extinfo_.flags |= ANDROID_DLEXT_USE_RELRO;
201 extinfo_.relro_fd = relro_fd;
202 }
203
204 void TryUsingRelro(const char* lib) {
205 handle_ = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
206 ASSERT_DL_NOTNULL(handle_);
207 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
208 ASSERT_DL_NOTNULL(f);
209 EXPECT_EQ(4, f());
210 }
211
212 android_dlextinfo extinfo_;
213 char relro_file_[PATH_MAX];
214};
215
216TEST_F(DlExtRelroSharingTest, ChildWritesGoodData) {
217 ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME));
218 ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME));
219}
220
221TEST_F(DlExtRelroSharingTest, ChildWritesNoRelro) {
222 ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME_NORELRO));
223 ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME_NORELRO));
224}
225
226TEST_F(DlExtRelroSharingTest, RelroFileEmpty) {
227 int relro_fd = open(relro_file_, O_CREAT | O_RDWR | O_TRUNC, 0644);
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000228 ASSERT_NOERROR(relro_fd);
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000229 ASSERT_NOERROR(close(relro_fd));
230
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100231 ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME));
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000232}