]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/platform-bionic.git/blob - tests/dlext_test.cpp
Merge "Ensure <fcntl.h> defines the S_* constants from <sys/stat.h>."
[android-sdk/platform-bionic.git] / tests / dlext_test.cpp
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  */
17 #include <gtest/gtest.h>
19 #include <dlfcn.h>
20 #include <elf.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <inttypes.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <android/dlext.h>
28 #include <sys/mman.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
32 #include <pagemap/pagemap.h>
35 #define ASSERT_DL_NOTNULL(ptr) \
36     ASSERT_TRUE(ptr != nullptr) << "dlerror: " << dlerror()
38 #define ASSERT_DL_ZERO(i) \
39     ASSERT_EQ(0, i) << "dlerror: " << dlerror()
41 #define ASSERT_NOERROR(i) \
42     ASSERT_NE(-1, i) << "errno: " << strerror(errno)
44 #define ASSERT_SUBSTR(needle, haystack) \
45     ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack)
48 typedef int (*fn)(void);
49 #define LIBNAME "libdlext_test.so"
50 #define LIBNAME_NORELRO "libdlext_test_norelro.so"
51 #define LIBSIZE 1024*1024 // how much address space to reserve for it
53 #if defined(__LP64__)
54 #define LIBPATH_PREFIX "%s/nativetest64/libdlext_test_fd/"
55 #else
56 #define LIBPATH_PREFIX "%s/nativetest/libdlext_test_fd/"
57 #endif
59 #define LIBPATH LIBPATH_PREFIX "libdlext_test_fd.so"
60 #define LIBZIPPATH LIBPATH_PREFIX "libdlext_test_fd_zipaligned.zip"
62 #define LIBZIP_OFFSET 2*PAGE_SIZE
64 class DlExtTest : public ::testing::Test {
65 protected:
66   virtual void SetUp() {
67     handle_ = nullptr;
68     // verify that we don't have the library loaded already
69     void* h = dlopen(LIBNAME, RTLD_NOW | RTLD_NOLOAD);
70     ASSERT_TRUE(h == nullptr);
71     h = dlopen(LIBNAME_NORELRO, RTLD_NOW | RTLD_NOLOAD);
72     ASSERT_TRUE(h == nullptr);
73     // call dlerror() to swallow the error, and check it was the one we wanted
74     ASSERT_STREQ("dlopen failed: library \"" LIBNAME_NORELRO "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
75   }
77   virtual void TearDown() {
78     if (handle_ != nullptr) {
79       ASSERT_DL_ZERO(dlclose(handle_));
80     }
81   }
83   void* handle_;
84 };
86 TEST_F(DlExtTest, ExtInfoNull) {
87   handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, nullptr);
88   ASSERT_DL_NOTNULL(handle_);
89   fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
90   ASSERT_DL_NOTNULL(f);
91   EXPECT_EQ(4, f());
92 }
94 TEST_F(DlExtTest, ExtInfoNoFlags) {
95   android_dlextinfo extinfo;
96   extinfo.flags = 0;
97   handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
98   ASSERT_DL_NOTNULL(handle_);
99   fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
100   ASSERT_DL_NOTNULL(f);
101   EXPECT_EQ(4, f());
104 TEST_F(DlExtTest, ExtInfoUseFd) {
105   const char* android_data = getenv("ANDROID_DATA");
106   ASSERT_TRUE(android_data != nullptr);
107   char lib_path[PATH_MAX];
108   snprintf(lib_path, sizeof(lib_path), LIBPATH, android_data);
110   android_dlextinfo extinfo;
111   extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD;
112   extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path, O_RDONLY | O_CLOEXEC));
113   ASSERT_TRUE(extinfo.library_fd != -1);
114   handle_ = android_dlopen_ext(lib_path, RTLD_NOW, &extinfo);
115   ASSERT_DL_NOTNULL(handle_);
116   fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
117   ASSERT_DL_NOTNULL(f);
118   EXPECT_EQ(4, f());
121 TEST_F(DlExtTest, ExtInfoUseFdWithOffset) {
122   const char* android_data = getenv("ANDROID_DATA");
123   ASSERT_TRUE(android_data != nullptr);
125   char lib_path[PATH_MAX];
126   snprintf(lib_path, sizeof(lib_path), LIBZIPPATH, android_data);
128   android_dlextinfo extinfo;
129   extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
130   extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path, O_RDONLY | O_CLOEXEC));
131   extinfo.library_fd_offset = LIBZIP_OFFSET;
133   handle_ = android_dlopen_ext(lib_path, RTLD_NOW, &extinfo);
134   ASSERT_DL_NOTNULL(handle_);
136   fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
137   ASSERT_DL_NOTNULL(f);
138   EXPECT_EQ(4, f());
141 TEST_F(DlExtTest, ExtInfoUseFdWithInvalidOffset) {
142   const char* android_data = getenv("ANDROID_DATA");
143   ASSERT_TRUE(android_data != nullptr);
145   char lib_path[PATH_MAX];
146   snprintf(lib_path, sizeof(lib_path), LIBPATH, android_data);
148   android_dlextinfo extinfo;
149   extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
150   extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path, O_RDONLY | O_CLOEXEC));
151   extinfo.library_fd_offset = 17;
153   handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo);
154   ASSERT_TRUE(handle_ == nullptr);
155   ASSERT_STREQ("dlopen failed: file offset for the library \"libname_placeholder\" is not page-aligned: 17", dlerror());
157   // Test an address above 2^44, for http://b/18178121 .
158   extinfo.library_fd_offset = (5LL<<48) + PAGE_SIZE;
159   handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo);
160   ASSERT_TRUE(handle_ == nullptr);
161   ASSERT_SUBSTR("dlopen failed: file offset for the library \"libname_placeholder\" >= file size", dlerror());
163   extinfo.library_fd_offset = 0LL - PAGE_SIZE;
164   handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo);
165   ASSERT_TRUE(handle_ == nullptr);
166   ASSERT_SUBSTR("dlopen failed: file offset for the library \"libname_placeholder\" is negative", dlerror());
168   extinfo.library_fd_offset = PAGE_SIZE;
169   handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo);
170   ASSERT_TRUE(handle_ == nullptr);
171   ASSERT_STREQ("dlopen failed: \"libname_placeholder\" has bad ELF magic", dlerror());
173   close(extinfo.library_fd);
176 TEST_F(DlExtTest, ExtInfoUseOffsetWihtoutFd) {
177   android_dlextinfo extinfo;
178   extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
179   extinfo.library_fd_offset = LIBZIP_OFFSET;
181   handle_ = android_dlopen_ext("/some/lib/that/does_not_exist", RTLD_NOW, &extinfo);
182   ASSERT_TRUE(handle_ == nullptr);
183   ASSERT_STREQ("dlopen failed: invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without ANDROID_DLEXT_USE_LIBRARY_FD): 0x20", dlerror());
186 TEST_F(DlExtTest, Reserved) {
187   void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
188                      -1, 0);
189   ASSERT_TRUE(start != MAP_FAILED);
190   android_dlextinfo extinfo;
191   extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
192   extinfo.reserved_addr = start;
193   extinfo.reserved_size = LIBSIZE;
194   handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
195   ASSERT_DL_NOTNULL(handle_);
196   fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
197   ASSERT_DL_NOTNULL(f);
198   EXPECT_GE(reinterpret_cast<void*>(f), start);
199   EXPECT_LT(reinterpret_cast<void*>(f),
200             reinterpret_cast<char*>(start) + LIBSIZE);
201   EXPECT_EQ(4, f());
204 TEST_F(DlExtTest, ReservedTooSmall) {
205   void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
206                      -1, 0);
207   ASSERT_TRUE(start != MAP_FAILED);
208   android_dlextinfo extinfo;
209   extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
210   extinfo.reserved_addr = start;
211   extinfo.reserved_size = PAGE_SIZE;
212   handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
213   EXPECT_EQ(nullptr, handle_);
216 TEST_F(DlExtTest, ReservedHint) {
217   void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
218                      -1, 0);
219   ASSERT_TRUE(start != MAP_FAILED);
220   android_dlextinfo extinfo;
221   extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT;
222   extinfo.reserved_addr = start;
223   extinfo.reserved_size = LIBSIZE;
224   handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
225   ASSERT_DL_NOTNULL(handle_);
226   fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
227   ASSERT_DL_NOTNULL(f);
228   EXPECT_GE(reinterpret_cast<void*>(f), start);
229   EXPECT_LT(reinterpret_cast<void*>(f),
230             reinterpret_cast<char*>(start) + LIBSIZE);
231   EXPECT_EQ(4, f());
234 TEST_F(DlExtTest, ReservedHintTooSmall) {
235   void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
236                      -1, 0);
237   ASSERT_TRUE(start != MAP_FAILED);
238   android_dlextinfo extinfo;
239   extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT;
240   extinfo.reserved_addr = start;
241   extinfo.reserved_size = PAGE_SIZE;
242   handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
243   ASSERT_DL_NOTNULL(handle_);
244   fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
245   ASSERT_DL_NOTNULL(f);
246   EXPECT_TRUE(reinterpret_cast<void*>(f) < start ||
247               (reinterpret_cast<void*>(f) >=
248                reinterpret_cast<char*>(start) + PAGE_SIZE));
249   EXPECT_EQ(4, f());
252 class DlExtRelroSharingTest : public DlExtTest {
253 protected:
254   virtual void SetUp() {
255     DlExtTest::SetUp();
256     void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
257                        -1, 0);
258     ASSERT_TRUE(start != MAP_FAILED);
259     extinfo_.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
260     extinfo_.reserved_addr = start;
261     extinfo_.reserved_size = LIBSIZE;
262     extinfo_.relro_fd = -1;
264     const char* android_data = getenv("ANDROID_DATA");
265     ASSERT_TRUE(android_data != nullptr);
266     snprintf(relro_file_, sizeof(relro_file_), "%s/local/tmp/libdlext_test.relro", android_data);
267   }
269   virtual void TearDown() {
270     DlExtTest::TearDown();
271     if (extinfo_.relro_fd != -1) {
272       ASSERT_NOERROR(close(extinfo_.relro_fd));
273     }
274   }
276   void CreateRelroFile(const char* lib) {
277     int relro_fd = open(relro_file_, O_CREAT | O_RDWR | O_TRUNC, 0644);
278     ASSERT_NOERROR(relro_fd);
280     pid_t pid = fork();
281     if (pid == 0) {
282       // child process
283       extinfo_.flags |= ANDROID_DLEXT_WRITE_RELRO;
284       extinfo_.relro_fd = relro_fd;
285       void* handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
286       if (handle == nullptr) {
287         fprintf(stderr, "in child: %s\n", dlerror());
288         exit(1);
289       }
290       exit(0);
291     }
293     // continuing in parent
294     ASSERT_NOERROR(close(relro_fd));
295     ASSERT_NOERROR(pid);
296     int status;
297     ASSERT_EQ(pid, waitpid(pid, &status, 0));
298     ASSERT_TRUE(WIFEXITED(status));
299     ASSERT_EQ(0, WEXITSTATUS(status));
301     // reopen file for reading so it can be used
302     relro_fd = open(relro_file_, O_RDONLY);
303     ASSERT_NOERROR(relro_fd);
304     extinfo_.flags |= ANDROID_DLEXT_USE_RELRO;
305     extinfo_.relro_fd = relro_fd;
306   }
308   void TryUsingRelro(const char* lib) {
309     handle_ = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
310     ASSERT_DL_NOTNULL(handle_);
311     fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
312     ASSERT_DL_NOTNULL(f);
313     EXPECT_EQ(4, f());
314   }
316   void SpawnChildrenAndMeasurePss(const char* lib, bool share_relro, size_t* pss_out);
318   android_dlextinfo extinfo_;
319   char relro_file_[PATH_MAX];
320 };
322 TEST_F(DlExtRelroSharingTest, ChildWritesGoodData) {
323   ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME));
324   ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME));
327 TEST_F(DlExtRelroSharingTest, ChildWritesNoRelro) {
328   ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME_NORELRO));
329   ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME_NORELRO));
332 TEST_F(DlExtRelroSharingTest, RelroFileEmpty) {
333   int relro_fd = open(relro_file_, O_CREAT | O_RDWR | O_TRUNC, 0644);
334   ASSERT_NOERROR(relro_fd);
335   ASSERT_NOERROR(close(relro_fd));
337   ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME));
340 TEST_F(DlExtRelroSharingTest, VerifyMemorySaving) {
341   if (geteuid() != 0) {
342     GTEST_LOG_(INFO) << "This test must be run as root.\n";
343     return;
344   }
346   ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME));
347   int relro_fd = open(relro_file_, O_RDONLY);
348   ASSERT_NOERROR(relro_fd);
349   extinfo_.flags |= ANDROID_DLEXT_USE_RELRO;
350   extinfo_.relro_fd = relro_fd;
351   int pipefd[2];
352   ASSERT_NOERROR(pipe(pipefd));
354   size_t without_sharing, with_sharing;
355   ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(LIBNAME, false, &without_sharing));
356   ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(LIBNAME, true, &with_sharing));
358   // We expect the sharing to save at least 10% of the total PSS. In practice
359   // it saves 40%+ for this test.
360   size_t expected_size = without_sharing - (without_sharing/10);
361   EXPECT_LT(with_sharing, expected_size);
364 void getPss(pid_t pid, size_t* pss_out) {
365   pm_kernel_t* kernel;
366   ASSERT_EQ(0, pm_kernel_create(&kernel));
368   pm_process_t* process;
369   ASSERT_EQ(0, pm_process_create(kernel, pid, &process));
371   pm_map_t** maps;
372   size_t num_maps;
373   ASSERT_EQ(0, pm_process_maps(process, &maps, &num_maps));
375   size_t total_pss = 0;
376   for (size_t i = 0; i < num_maps; i++) {
377     pm_memusage_t usage;
378     ASSERT_EQ(0, pm_map_usage(maps[i], &usage));
379     total_pss += usage.pss;
380   }
381   *pss_out = total_pss;
383   free(maps);
384   pm_process_destroy(process);
385   pm_kernel_destroy(kernel);
388 void DlExtRelroSharingTest::SpawnChildrenAndMeasurePss(const char* lib, bool share_relro,
389                                                        size_t* pss_out) {
390   const int CHILDREN = 20;
392   // Create children
393   pid_t childpid[CHILDREN];
394   int childpipe[CHILDREN];
395   for (int i=0; i<CHILDREN; ++i) {
396     char read_buf;
397     int child_done_pipe[2], parent_done_pipe[2];
398     ASSERT_NOERROR(pipe(child_done_pipe));
399     ASSERT_NOERROR(pipe(parent_done_pipe));
401     pid_t child = fork();
402     if (child == 0) {
403       // close the 'wrong' ends of the pipes in the child
404       close(child_done_pipe[0]);
405       close(parent_done_pipe[1]);
407       // open the library
408       void* handle;
409       if (share_relro) {
410         handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
411       } else {
412         handle = dlopen(lib, RTLD_NOW);
413       }
414       if (handle == nullptr) {
415         fprintf(stderr, "in child: %s\n", dlerror());
416         exit(1);
417       }
419       // close write end of child_done_pipe to signal the parent that we're done.
420       close(child_done_pipe[1]);
422       // wait for the parent to close parent_done_pipe, then exit
423       read(parent_done_pipe[0], &read_buf, 1);
424       exit(0);
425     }
427     ASSERT_NOERROR(child);
429     // close the 'wrong' ends of the pipes in the parent
430     close(child_done_pipe[1]);
431     close(parent_done_pipe[0]);
433     // wait for the child to be done
434     read(child_done_pipe[0], &read_buf, 1);
435     close(child_done_pipe[0]);
437     // save the child's pid and the parent_done_pipe
438     childpid[i] = child;
439     childpipe[i] = parent_done_pipe[1];
440   }
442   // Sum the PSS of all the children
443   size_t total_pss = 0;
444   for (int i=0; i<CHILDREN; ++i) {
445     size_t child_pss;
446     ASSERT_NO_FATAL_FAILURE(getPss(childpid[i], &child_pss));
447     total_pss += child_pss;
448   }
449   *pss_out = total_pss;
451   // Close pipes and wait for children to exit
452   for (int i=0; i<CHILDREN; ++i) {
453     ASSERT_NOERROR(close(childpipe[i]));
454   }
455   for (int i=0; i<CHILDREN; ++i) {
456     int status;
457     ASSERT_EQ(childpid[i], waitpid(childpid[i], &status, 0));
458     ASSERT_TRUE(WIFEXITED(status));
459     ASSERT_EQ(0, WEXITSTATUS(status));
460   }