dlext_test.cpp revision 284ae3559ed909613b189b98bdc3efab94373a30
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 <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>
31
32#include <pagemap/pagemap.h>
33
34#include "TemporaryFile.h"
35#include "utils.h"
36
37#define ASSERT_DL_NOTNULL(ptr) \
38    ASSERT_TRUE(ptr != nullptr) << "dlerror: " << dlerror()
39
40#define ASSERT_DL_ZERO(i) \
41    ASSERT_EQ(0, i) << "dlerror: " << dlerror()
42
43#define ASSERT_NOERROR(i) \
44    ASSERT_NE(-1, i) << "errno: " << strerror(errno)
45
46#define ASSERT_SUBSTR(needle, haystack) \
47    ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack)
48
49
50typedef int (*fn)(void);
51#define LIBNAME "libdlext_test.so"
52#define LIBNAME_NORELRO "libdlext_test_norelro.so"
53#define LIBSIZE 1024*1024 // how much address space to reserve for it
54
55#if defined(__LP64__)
56#define NATIVE_TESTS_PATH "/nativetest64"
57#else
58#define NATIVE_TESTS_PATH "/nativetest"
59#endif
60
61#define LIBPATH NATIVE_TESTS_PATH "/libdlext_test_fd/libdlext_test_fd.so"
62#define LIBZIPPATH NATIVE_TESTS_PATH "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip"
63#define LIBZIPPATH_WITH_RUNPATH NATIVE_TESTS_PATH "/libdlext_test_runpath_zip/libdlext_test_runpath_zip_zipaligned.zip"
64
65#define LIBZIP_OFFSET PAGE_SIZE
66
67class DlExtTest : public ::testing::Test {
68protected:
69  virtual void SetUp() {
70    handle_ = nullptr;
71    // verify that we don't have the library loaded already
72    void* h = dlopen(LIBNAME, RTLD_NOW | RTLD_NOLOAD);
73    ASSERT_TRUE(h == nullptr);
74    h = dlopen(LIBNAME_NORELRO, RTLD_NOW | RTLD_NOLOAD);
75    ASSERT_TRUE(h == nullptr);
76    // call dlerror() to swallow the error, and check it was the one we wanted
77    ASSERT_STREQ("dlopen failed: library \"" LIBNAME_NORELRO "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
78  }
79
80  virtual void TearDown() {
81    if (handle_ != nullptr) {
82      ASSERT_DL_ZERO(dlclose(handle_));
83    }
84  }
85
86  void* handle_;
87};
88
89TEST_F(DlExtTest, ExtInfoNull) {
90  handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, nullptr);
91  ASSERT_DL_NOTNULL(handle_);
92  fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
93  ASSERT_DL_NOTNULL(f);
94  EXPECT_EQ(4, f());
95}
96
97TEST_F(DlExtTest, ExtInfoNoFlags) {
98  android_dlextinfo extinfo;
99  extinfo.flags = 0;
100  handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
101  ASSERT_DL_NOTNULL(handle_);
102  fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
103  ASSERT_DL_NOTNULL(f);
104  EXPECT_EQ(4, f());
105}
106
107TEST_F(DlExtTest, ExtInfoUseFd) {
108  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBPATH;
109
110  android_dlextinfo extinfo;
111  extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD;
112  extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path.c_str(), O_RDONLY | O_CLOEXEC));
113  ASSERT_TRUE(extinfo.library_fd != -1);
114  handle_ = android_dlopen_ext(lib_path.c_str(), 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());
119
120  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle_, "dlopen_testlib_taxicab_number"));
121  ASSERT_DL_NOTNULL(taxicab_number);
122  EXPECT_EQ(1729U, *taxicab_number);
123}
124
125TEST_F(DlExtTest, ExtInfoUseFdWithOffset) {
126  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH;
127
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.c_str(), O_RDONLY | O_CLOEXEC));
131  extinfo.library_fd_offset = LIBZIP_OFFSET;
132
133  handle_ = android_dlopen_ext(lib_path.c_str(), RTLD_NOW, &extinfo);
134  ASSERT_DL_NOTNULL(handle_);
135
136  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle_, "dlopen_testlib_taxicab_number"));
137  ASSERT_DL_NOTNULL(taxicab_number);
138  EXPECT_EQ(1729U, *taxicab_number);
139}
140
141TEST_F(DlExtTest, ExtInfoUseFdWithInvalidOffset) {
142  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH;
143  // lib_path is relative when $ANDROID_DATA is relative
144  char lib_realpath_buf[PATH_MAX];
145  ASSERT_TRUE(realpath(lib_path.c_str(), lib_realpath_buf) == lib_realpath_buf);
146  const std::string lib_realpath = std::string(lib_realpath_buf);
147
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.c_str(), O_RDONLY | O_CLOEXEC));
151  extinfo.library_fd_offset = 17;
152
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());
156
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());
162
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());
167
168  extinfo.library_fd_offset = 0;
169  handle_ = android_dlopen_ext("libname_ignored", RTLD_NOW, &extinfo);
170  ASSERT_TRUE(handle_ == nullptr);
171  ASSERT_EQ("dlopen failed: \"" + lib_realpath + "\" has bad ELF magic", dlerror());
172
173  // Check if dlsym works after unsuccessful dlopen().
174  // Supply non-exiting one to make linker visit every soinfo.
175  void* sym = dlsym(RTLD_DEFAULT, "this_symbol_does_not_exist___");
176  ASSERT_TRUE(sym == nullptr);
177
178  close(extinfo.library_fd);
179}
180
181TEST_F(DlExtTest, ExtInfoUseOffsetWihtoutFd) {
182  android_dlextinfo extinfo;
183  extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
184  extinfo.library_fd_offset = LIBZIP_OFFSET;
185
186  handle_ = android_dlopen_ext("/some/lib/that/does_not_exist", RTLD_NOW, &extinfo);
187  ASSERT_TRUE(handle_ == nullptr);
188  ASSERT_STREQ("dlopen failed: invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without ANDROID_DLEXT_USE_LIBRARY_FD): 0x20", dlerror());
189}
190
191TEST(dlext, android_dlopen_ext_force_load_smoke) {
192  // 1. Open actual file
193  void* handle = dlopen("libdlext_test.so", RTLD_NOW);
194  ASSERT_DL_NOTNULL(handle);
195  // 2. Open link with force_load flag set
196  android_dlextinfo extinfo;
197  extinfo.flags = ANDROID_DLEXT_FORCE_LOAD;
198  void* handle2 = android_dlopen_ext("libdlext_test_v2.so", RTLD_NOW, &extinfo);
199  ASSERT_DL_NOTNULL(handle2);
200  ASSERT_TRUE(handle != handle2);
201
202  dlclose(handle2);
203  dlclose(handle);
204}
205
206TEST(dlext, android_dlopen_ext_force_load_soname_exception) {
207  // Check if soname lookup still returns already loaded library
208  // when ANDROID_DLEXT_FORCE_LOAD flag is specified.
209  void* handle = dlopen("libdlext_test_v2.so", RTLD_NOW);
210  ASSERT_DL_NOTNULL(handle);
211
212  android_dlextinfo extinfo;
213  extinfo.flags = ANDROID_DLEXT_FORCE_LOAD;
214
215  // Note that 'libdlext_test.so' is dt_soname for libdlext_test_v2.so
216  void* handle2 = android_dlopen_ext("libdlext_test.so", RTLD_NOW, &extinfo);
217
218  ASSERT_DL_NOTNULL(handle2);
219  ASSERT_TRUE(handle == handle2);
220
221  dlclose(handle2);
222  dlclose(handle);
223}
224
225TEST(dlfcn, dlopen_from_zip_absolute_path) {
226  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH;
227
228  void* handle = dlopen((lib_path + "!/libdir/libatest_simple_zip.so").c_str(), RTLD_NOW);
229  ASSERT_TRUE(handle != nullptr) << dlerror();
230
231  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
232  ASSERT_DL_NOTNULL(taxicab_number);
233  EXPECT_EQ(1729U, *taxicab_number);
234
235  dlclose(handle);
236}
237
238TEST(dlfcn, dlopen_from_zip_with_dt_runpath) {
239  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH_WITH_RUNPATH;
240
241  void* handle = dlopen((lib_path + "!/libdir/libtest_dt_runpath_d_zip.so").c_str(), RTLD_NOW);
242
243  ASSERT_TRUE(handle != nullptr) << dlerror();
244
245  typedef void *(* dlopen_b_fn)();
246  dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b");
247  ASSERT_TRUE(fn != nullptr) << dlerror();
248
249  void *p = fn();
250  ASSERT_TRUE(p != nullptr) << dlerror();
251
252  dlclose(p);
253  dlclose(handle);
254}
255
256TEST(dlfcn, dlopen_from_zip_ld_library_path) {
257  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH + "!/libdir";
258
259  typedef void (*fn_t)(const char*);
260  fn_t android_update_LD_LIBRARY_PATH =
261      reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "android_update_LD_LIBRARY_PATH"));
262
263  ASSERT_TRUE(android_update_LD_LIBRARY_PATH != nullptr) << dlerror();
264
265  void* handle = dlopen("libdlext_test_zip.so", RTLD_NOW);
266  ASSERT_TRUE(handle == nullptr);
267
268  android_update_LD_LIBRARY_PATH(lib_path.c_str());
269
270  handle = dlopen("libdlext_test_zip.so", RTLD_NOW);
271  ASSERT_TRUE(handle != nullptr) << dlerror();
272
273  int (*fn)(void);
274  fn = reinterpret_cast<int (*)(void)>(dlsym(handle, "getRandomNumber"));
275  ASSERT_TRUE(fn != nullptr);
276  EXPECT_EQ(4, fn());
277
278  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
279  ASSERT_DL_NOTNULL(taxicab_number);
280  EXPECT_EQ(1729U, *taxicab_number);
281
282  dlclose(handle);
283}
284
285
286TEST_F(DlExtTest, Reserved) {
287  void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
288                     -1, 0);
289  ASSERT_TRUE(start != MAP_FAILED);
290  android_dlextinfo extinfo;
291  extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
292  extinfo.reserved_addr = start;
293  extinfo.reserved_size = LIBSIZE;
294  handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
295  ASSERT_DL_NOTNULL(handle_);
296  fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
297  ASSERT_DL_NOTNULL(f);
298  EXPECT_GE(reinterpret_cast<void*>(f), start);
299  EXPECT_LT(reinterpret_cast<void*>(f),
300            reinterpret_cast<char*>(start) + LIBSIZE);
301  EXPECT_EQ(4, f());
302}
303
304TEST_F(DlExtTest, ReservedTooSmall) {
305  void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
306                     -1, 0);
307  ASSERT_TRUE(start != MAP_FAILED);
308  android_dlextinfo extinfo;
309  extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
310  extinfo.reserved_addr = start;
311  extinfo.reserved_size = PAGE_SIZE;
312  handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
313  EXPECT_EQ(nullptr, handle_);
314}
315
316TEST_F(DlExtTest, ReservedHint) {
317  void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
318                     -1, 0);
319  ASSERT_TRUE(start != MAP_FAILED);
320  android_dlextinfo extinfo;
321  extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT;
322  extinfo.reserved_addr = start;
323  extinfo.reserved_size = LIBSIZE;
324  handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
325  ASSERT_DL_NOTNULL(handle_);
326  fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
327  ASSERT_DL_NOTNULL(f);
328  EXPECT_GE(reinterpret_cast<void*>(f), start);
329  EXPECT_LT(reinterpret_cast<void*>(f),
330            reinterpret_cast<char*>(start) + LIBSIZE);
331  EXPECT_EQ(4, f());
332}
333
334TEST_F(DlExtTest, ReservedHintTooSmall) {
335  void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
336                     -1, 0);
337  ASSERT_TRUE(start != MAP_FAILED);
338  android_dlextinfo extinfo;
339  extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT;
340  extinfo.reserved_addr = start;
341  extinfo.reserved_size = PAGE_SIZE;
342  handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
343  ASSERT_DL_NOTNULL(handle_);
344  fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
345  ASSERT_DL_NOTNULL(f);
346  EXPECT_TRUE(reinterpret_cast<void*>(f) < start ||
347              (reinterpret_cast<void*>(f) >=
348               reinterpret_cast<char*>(start) + PAGE_SIZE));
349  EXPECT_EQ(4, f());
350}
351
352TEST_F(DlExtTest, LoadAtFixedAddress) {
353  void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
354                     -1, 0);
355  ASSERT_TRUE(start != MAP_FAILED);
356  munmap(start, LIBSIZE);
357
358  android_dlextinfo extinfo;
359  extinfo.flags = ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS;
360  extinfo.reserved_addr = start;
361
362  handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
363  ASSERT_DL_NOTNULL(handle_);
364  fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
365  ASSERT_DL_NOTNULL(f);
366  EXPECT_GE(reinterpret_cast<void*>(f), start);
367  EXPECT_LT(reinterpret_cast<void*>(f), reinterpret_cast<char*>(start) + LIBSIZE);
368
369  EXPECT_EQ(4, f());
370}
371
372TEST_F(DlExtTest, LoadAtFixedAddressTooSmall) {
373  void* start = mmap(nullptr, LIBSIZE + PAGE_SIZE, PROT_NONE,
374                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
375  ASSERT_TRUE(start != MAP_FAILED);
376  munmap(start, LIBSIZE + PAGE_SIZE);
377  void* new_addr = mmap(reinterpret_cast<uint8_t*>(start) + PAGE_SIZE, LIBSIZE, PROT_NONE,
378                        MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
379  ASSERT_TRUE(new_addr != MAP_FAILED);
380
381  android_dlextinfo extinfo;
382  extinfo.flags = ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS;
383  extinfo.reserved_addr = start;
384
385  handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
386  ASSERT_TRUE(handle_ == nullptr);
387}
388
389class DlExtRelroSharingTest : public DlExtTest {
390protected:
391  virtual void SetUp() {
392    DlExtTest::SetUp();
393    void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
394                       -1, 0);
395    ASSERT_TRUE(start != MAP_FAILED);
396    extinfo_.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
397    extinfo_.reserved_addr = start;
398    extinfo_.reserved_size = LIBSIZE;
399    extinfo_.relro_fd = -1;
400  }
401
402  virtual void TearDown() {
403    DlExtTest::TearDown();
404  }
405
406  void CreateRelroFile(const char* lib, const char* relro_file) {
407    int relro_fd = open(relro_file, O_RDWR | O_TRUNC);
408    ASSERT_NOERROR(relro_fd);
409
410    pid_t pid = fork();
411    if (pid == 0) {
412      // child process
413      extinfo_.flags |= ANDROID_DLEXT_WRITE_RELRO;
414      extinfo_.relro_fd = relro_fd;
415      void* handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
416      if (handle == nullptr) {
417        fprintf(stderr, "in child: %s\n", dlerror());
418        exit(1);
419      }
420      exit(0);
421    }
422
423    // continuing in parent
424    ASSERT_NOERROR(close(relro_fd));
425    ASSERT_NOERROR(pid);
426    int status;
427    ASSERT_EQ(pid, waitpid(pid, &status, 0));
428    ASSERT_TRUE(WIFEXITED(status));
429    ASSERT_EQ(0, WEXITSTATUS(status));
430
431    // reopen file for reading so it can be used
432    relro_fd = open(relro_file, O_RDONLY);
433    ASSERT_NOERROR(relro_fd);
434    extinfo_.flags |= ANDROID_DLEXT_USE_RELRO;
435    extinfo_.relro_fd = relro_fd;
436  }
437
438  void TryUsingRelro(const char* lib) {
439    handle_ = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
440    ASSERT_DL_NOTNULL(handle_);
441    fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
442    ASSERT_DL_NOTNULL(f);
443    EXPECT_EQ(4, f());
444
445    uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle_, "dlopen_testlib_taxicab_number"));
446    ASSERT_DL_NOTNULL(taxicab_number);
447    EXPECT_EQ(1729U, *taxicab_number);
448  }
449
450  void SpawnChildrenAndMeasurePss(const char* lib, bool share_relro, size_t* pss_out);
451
452  android_dlextinfo extinfo_;
453};
454
455TEST_F(DlExtRelroSharingTest, ChildWritesGoodData) {
456  TemporaryFile tf; // Use tf to get an unique filename.
457  ASSERT_NOERROR(close(tf.fd));
458
459  ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME, tf.filename));
460  ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME));
461
462  // Use destructor of tf to close and unlink the file.
463  tf.fd = extinfo_.relro_fd;
464}
465
466TEST_F(DlExtRelroSharingTest, ChildWritesNoRelro) {
467  TemporaryFile tf; // // Use tf to get an unique filename.
468  ASSERT_NOERROR(close(tf.fd));
469
470  ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME_NORELRO, tf.filename));
471  ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME_NORELRO));
472
473  // Use destructor of tf to close and unlink the file.
474  tf.fd = extinfo_.relro_fd;
475}
476
477TEST_F(DlExtRelroSharingTest, RelroFileEmpty) {
478  ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME));
479}
480
481TEST_F(DlExtRelroSharingTest, VerifyMemorySaving) {
482  if (geteuid() != 0) {
483    GTEST_LOG_(INFO) << "This test must be run as root.\n";
484    return;
485  }
486
487  TemporaryFile tf; // Use tf to get an unique filename.
488  ASSERT_NOERROR(close(tf.fd));
489
490  ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME, tf.filename));
491
492  int pipefd[2];
493  ASSERT_NOERROR(pipe(pipefd));
494
495  size_t without_sharing, with_sharing;
496  ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(LIBNAME, false, &without_sharing));
497  ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(LIBNAME, true, &with_sharing));
498
499  // We expect the sharing to save at least 10% of the total PSS. In practice
500  // it saves 40%+ for this test.
501  size_t expected_size = without_sharing - (without_sharing/10);
502  EXPECT_LT(with_sharing, expected_size);
503
504  // Use destructor of tf to close and unlink the file.
505  tf.fd = extinfo_.relro_fd;
506}
507
508void getPss(pid_t pid, size_t* pss_out) {
509  pm_kernel_t* kernel;
510  ASSERT_EQ(0, pm_kernel_create(&kernel));
511
512  pm_process_t* process;
513  ASSERT_EQ(0, pm_process_create(kernel, pid, &process));
514
515  pm_map_t** maps;
516  size_t num_maps;
517  ASSERT_EQ(0, pm_process_maps(process, &maps, &num_maps));
518
519  size_t total_pss = 0;
520  for (size_t i = 0; i < num_maps; i++) {
521    pm_memusage_t usage;
522    ASSERT_EQ(0, pm_map_usage(maps[i], &usage));
523    total_pss += usage.pss;
524  }
525  *pss_out = total_pss;
526
527  free(maps);
528  pm_process_destroy(process);
529  pm_kernel_destroy(kernel);
530}
531
532void DlExtRelroSharingTest::SpawnChildrenAndMeasurePss(const char* lib, bool share_relro,
533                                                       size_t* pss_out) {
534  const int CHILDREN = 20;
535
536  // Create children
537  pid_t childpid[CHILDREN];
538  int childpipe[CHILDREN];
539  for (int i=0; i<CHILDREN; ++i) {
540    char read_buf;
541    int child_done_pipe[2], parent_done_pipe[2];
542    ASSERT_NOERROR(pipe(child_done_pipe));
543    ASSERT_NOERROR(pipe(parent_done_pipe));
544
545    pid_t child = fork();
546    if (child == 0) {
547      // close the 'wrong' ends of the pipes in the child
548      close(child_done_pipe[0]);
549      close(parent_done_pipe[1]);
550
551      // open the library
552      void* handle;
553      if (share_relro) {
554        handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
555      } else {
556        handle = dlopen(lib, RTLD_NOW);
557      }
558      if (handle == nullptr) {
559        fprintf(stderr, "in child: %s\n", dlerror());
560        exit(1);
561      }
562
563      // close write end of child_done_pipe to signal the parent that we're done.
564      close(child_done_pipe[1]);
565
566      // wait for the parent to close parent_done_pipe, then exit
567      read(parent_done_pipe[0], &read_buf, 1);
568      exit(0);
569    }
570
571    ASSERT_NOERROR(child);
572
573    // close the 'wrong' ends of the pipes in the parent
574    close(child_done_pipe[1]);
575    close(parent_done_pipe[0]);
576
577    // wait for the child to be done
578    read(child_done_pipe[0], &read_buf, 1);
579    close(child_done_pipe[0]);
580
581    // save the child's pid and the parent_done_pipe
582    childpid[i] = child;
583    childpipe[i] = parent_done_pipe[1];
584  }
585
586  // Sum the PSS of all the children
587  size_t total_pss = 0;
588  for (int i=0; i<CHILDREN; ++i) {
589    size_t child_pss;
590    ASSERT_NO_FATAL_FAILURE(getPss(childpid[i], &child_pss));
591    total_pss += child_pss;
592  }
593  *pss_out = total_pss;
594
595  // Close pipes and wait for children to exit
596  for (int i=0; i<CHILDREN; ++i) {
597    ASSERT_NOERROR(close(childpipe[i]));
598  }
599  for (int i=0; i<CHILDREN; ++i) {
600    int status;
601    ASSERT_EQ(childpid[i], waitpid(childpid[i], &status, 0));
602    ASSERT_TRUE(WIFEXITED(status));
603    ASSERT_EQ(0, WEXITSTATUS(status));
604  }
605}
606
607// Testing namespaces
608static const char* g_public_lib = "libnstest_public.so";
609
610TEST(dlext, ns_smoke) {
611  static const char* root_lib = "libnstest_root.so";
612  std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
613
614  ASSERT_FALSE(android_init_namespaces(path.c_str(), nullptr));
615  ASSERT_STREQ("android_init_namespaces failed: error initializing public namespace: "
616               "\"libnstest_public.so\" was not found in the default namespace", dlerror());
617
618  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
619
620  const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib;
621  void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
622  ASSERT_TRUE(handle_public != nullptr) << dlerror();
623
624  ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
625
626  // Check that libraries added to public namespace are NODELETE
627  dlclose(handle_public);
628  handle_public = dlopen((lib_path + "/public_namespace_libs/" + g_public_lib).c_str(), RTLD_NOW | RTLD_NOLOAD);
629  ASSERT_TRUE(handle_public != nullptr) << dlerror();
630
631  android_namespace_t* ns1 = android_create_namespace("private", nullptr, (lib_path + "/private_namespace_libs").c_str(), false, nullptr);
632  ASSERT_TRUE(ns1 != nullptr) << dlerror();
633
634  android_namespace_t* ns2 = android_create_namespace("private_isolated", nullptr, (lib_path + "/private_namespace_libs").c_str(), true, nullptr);
635  ASSERT_TRUE(ns2 != nullptr) << dlerror();
636
637  // This should not have affect search path for default namespace:
638  ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
639  void* handle = dlopen(g_public_lib, RTLD_NOW);
640  ASSERT_TRUE(handle != nullptr) << dlerror();
641  dlclose(handle);
642
643  android_dlextinfo extinfo;
644  extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
645  extinfo.library_namespace = ns1;
646
647  void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
648  ASSERT_TRUE(handle1 != nullptr) << dlerror();
649
650  extinfo.library_namespace = ns2;
651  void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
652  ASSERT_TRUE(handle2 != nullptr) << dlerror();
653
654  ASSERT_TRUE(handle1 != handle2);
655
656  // dlopen for a public library using an absolute path should work for isolated namespaces
657  extinfo.library_namespace = ns2;
658  handle = android_dlopen_ext(lib_public_path.c_str(), RTLD_NOW, &extinfo);
659  ASSERT_TRUE(handle != nullptr) << dlerror();
660  ASSERT_TRUE(handle == handle_public);
661
662  dlclose(handle);
663
664  typedef const char* (*fn_t)();
665
666  fn_t ns_get_local_string1 = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string"));
667  ASSERT_TRUE(ns_get_local_string1 != nullptr) << dlerror();
668  fn_t ns_get_local_string2 = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_local_string"));
669  ASSERT_TRUE(ns_get_local_string2 != nullptr) << dlerror();
670
671  EXPECT_STREQ("This string is local to root library", ns_get_local_string1());
672  EXPECT_STREQ("This string is local to root library", ns_get_local_string2());
673
674  ASSERT_TRUE(ns_get_local_string1() != ns_get_local_string2());
675
676  fn_t ns_get_private_extern_string1 =
677          reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string"));
678  ASSERT_TRUE(ns_get_private_extern_string1 != nullptr) << dlerror();
679  fn_t ns_get_private_extern_string2 =
680          reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_private_extern_string"));
681  ASSERT_TRUE(ns_get_private_extern_string2 != nullptr) << dlerror();
682
683  EXPECT_STREQ("This string is from private namespace", ns_get_private_extern_string1());
684  EXPECT_STREQ("This string is from private namespace", ns_get_private_extern_string2());
685
686  ASSERT_TRUE(ns_get_private_extern_string1() != ns_get_private_extern_string2());
687
688  fn_t ns_get_public_extern_string1 =
689          reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string"));
690  ASSERT_TRUE(ns_get_public_extern_string1 != nullptr) << dlerror();
691  fn_t ns_get_public_extern_string2 =
692          reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_public_extern_string"));
693  ASSERT_TRUE(ns_get_public_extern_string2 != nullptr) << dlerror();
694
695  EXPECT_STREQ("This string is from public namespace", ns_get_public_extern_string1());
696  ASSERT_TRUE(ns_get_public_extern_string1() == ns_get_public_extern_string2());
697
698  // and now check that dlopen() does the right thing in terms of preserving namespace
699  fn_t ns_get_dlopened_string1 = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string"));
700  ASSERT_TRUE(ns_get_dlopened_string1 != nullptr) << dlerror();
701  fn_t ns_get_dlopened_string2 = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_dlopened_string"));
702  ASSERT_TRUE(ns_get_dlopened_string2 != nullptr) << dlerror();
703
704  EXPECT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string1());
705  EXPECT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string2());
706
707  ASSERT_TRUE(ns_get_dlopened_string1() != ns_get_dlopened_string2());
708
709  dlclose(handle1);
710
711  // Check if handle2 is still alive (and well)
712  ASSERT_STREQ("This string is local to root library", ns_get_local_string2());
713  ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string2());
714  ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string2());
715  ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string2());
716
717  dlclose(handle2);
718}
719
720extern "C" void android_set_application_target_sdk_version(uint32_t target);
721
722TEST(dlext, ns_isolated) {
723  static const char* root_lib = "libnstest_root_not_isolated.so";
724  std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
725
726  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
727  const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib;
728  void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
729  ASSERT_TRUE(handle_public != nullptr) << dlerror();
730
731  android_set_application_target_sdk_version(42U); // something > 23
732
733  ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
734
735  android_namespace_t* ns_not_isolated = android_create_namespace("private", nullptr, (lib_path + "/private_namespace_libs").c_str(), false, nullptr);
736  ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror();
737
738  android_namespace_t* ns_isolated = android_create_namespace("private_isolated1", nullptr, (lib_path + "/private_namespace_libs").c_str(), true, nullptr);
739  ASSERT_TRUE(ns_isolated != nullptr) << dlerror();
740
741  android_namespace_t* ns_isolated2 = android_create_namespace("private_isolated2", (lib_path + "/private_namespace_libs").c_str(), nullptr, true, lib_path.c_str());
742  ASSERT_TRUE(ns_isolated2 != nullptr) << dlerror();
743
744  ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
745  ASSERT_STREQ("dlopen failed: library \"libnstest_root_not_isolated.so\" not found", dlerror());
746
747  std::string lib_private_external_path =
748      lib_path + "/private_namespace_libs_external/libnstest_private_external.so";
749
750  // Load lib_private_external_path to default namespace
751  // (it should remain invisible for the isolated namespaces after this)
752  void* handle = dlopen(lib_private_external_path.c_str(), RTLD_NOW);
753  ASSERT_TRUE(handle != nullptr) << dlerror();
754
755  android_dlextinfo extinfo;
756  extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
757  extinfo.library_namespace = ns_not_isolated;
758
759  void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
760  ASSERT_TRUE(handle1 != nullptr) << dlerror();
761
762  extinfo.library_namespace = ns_isolated;
763
764  void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
765  ASSERT_TRUE(handle2 == nullptr);
766  ASSERT_STREQ("dlopen failed: library \"libnstest_private_external.so\" not found", dlerror());
767
768  // Check dlopen by absolute path
769  handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
770  ASSERT_TRUE(handle2 == nullptr);
771  ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" is not accessible for the namespace \"private_isolated1\"", dlerror());
772
773  extinfo.library_namespace = ns_isolated2;
774
775  // this should work because isolation_path for private_isolated2 includes lib_path
776  handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
777  ASSERT_TRUE(handle2 != nullptr) << dlerror();
778  dlclose(handle2);
779
780  // Check dlopen by absolute path
781  handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
782  ASSERT_TRUE(handle2 != nullptr) << dlerror();
783  dlclose(handle2);
784
785  typedef const char* (*fn_t)();
786  fn_t ns_get_local_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string"));
787  ASSERT_TRUE(ns_get_local_string != nullptr) << dlerror();
788
789  ASSERT_STREQ("This string is local to root library", ns_get_local_string());
790
791  fn_t ns_get_private_extern_string =
792          reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string"));
793  ASSERT_TRUE(ns_get_private_extern_string != nullptr) << dlerror();
794
795  ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string());
796
797  fn_t ns_get_public_extern_string =
798          reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string"));
799  ASSERT_TRUE(ns_get_public_extern_string != nullptr) << dlerror();
800
801  ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string());
802
803  fn_t ns_get_dlopened_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string"));
804  ASSERT_TRUE(ns_get_dlopened_string != nullptr) << dlerror();
805
806  ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string());
807
808  dlclose(handle1);
809}
810
811TEST(dlext, ns_anonymous) {
812  static const char* root_lib = "libnstest_root.so";
813  std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
814
815  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
816
817  const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib;
818  void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
819
820  ASSERT_TRUE(handle_public != nullptr) << dlerror();
821
822  ASSERT_TRUE(android_init_namespaces(path.c_str(), (lib_path + "/private_namespace_libs").c_str()))
823      << dlerror();
824
825  android_namespace_t* ns = android_create_namespace(
826                                "private", nullptr,
827                                (lib_path + "/private_namespace_libs").c_str(),
828                                false, nullptr);
829
830  ASSERT_TRUE(ns != nullptr) << dlerror();
831
832  std::string private_library_absolute_path = lib_path + "/private_namespace_libs/" + root_lib;
833
834  android_dlextinfo extinfo;
835  extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
836  extinfo.library_namespace = ns;
837
838  // we are going to copy this library to anonymous mmap and call the copy of ns_get_dlopened_string
839  void* handle = android_dlopen_ext(private_library_absolute_path.c_str(), RTLD_NOW, &extinfo);
840  ASSERT_TRUE(handle != nullptr) << dlerror();
841
842  uintptr_t ns_get_dlopened_string_addr =
843      reinterpret_cast<uintptr_t>(dlsym(handle, "ns_get_dlopened_string"));
844  ASSERT_TRUE(ns_get_dlopened_string_addr != 0) << dlerror();
845  typedef const char* (*fn_t)();
846  fn_t ns_get_dlopened_string_private = reinterpret_cast<fn_t>(ns_get_dlopened_string_addr);
847
848  std::vector<map_record> maps;
849  Maps::parse_maps(&maps);
850
851  uintptr_t addr_start = 0;
852  uintptr_t addr_end = 0;
853  std::vector<map_record> maps_to_copy;
854
855  for (const auto& rec : maps) {
856    if (rec.pathname == private_library_absolute_path) {
857      if (addr_start == 0) {
858        addr_start = rec.addr_start;
859      }
860      addr_end = rec.addr_end;
861
862      maps_to_copy.push_back(rec);
863    }
864  }
865
866  // some sanity checks..
867  ASSERT_TRUE(addr_start > 0);
868  ASSERT_TRUE(addr_end > 0);
869  ASSERT_EQ(3U, maps_to_copy.size());
870  ASSERT_TRUE(ns_get_dlopened_string_addr > addr_start);
871  ASSERT_TRUE(ns_get_dlopened_string_addr < addr_end);
872
873  // copy
874  uintptr_t reserved_addr = reinterpret_cast<uintptr_t>(mmap(nullptr, addr_end - addr_start,
875                                                             PROT_NONE, MAP_ANON | MAP_PRIVATE,
876                                                             -1, 0));
877  ASSERT_TRUE(reinterpret_cast<void*>(reserved_addr) != MAP_FAILED);
878
879  for (const auto& rec : maps_to_copy) {
880    uintptr_t offset = rec.addr_start - addr_start;
881    size_t size = rec.addr_end - rec.addr_start;
882    void* addr = reinterpret_cast<void*>(reserved_addr + offset);
883    void* map = mmap(addr, size, PROT_READ | PROT_WRITE,
884                     MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
885    ASSERT_TRUE(map != MAP_FAILED);
886    memcpy(map, reinterpret_cast<void*>(rec.addr_start), size);
887    mprotect(map, size, rec.perms);
888  }
889
890  // call the function copy
891  uintptr_t ns_get_dlopened_string_offset  = ns_get_dlopened_string_addr - addr_start;
892  fn_t ns_get_dlopened_string_anon = reinterpret_cast<fn_t>(reserved_addr + ns_get_dlopened_string_offset);
893  ASSERT_STREQ("This string is from private namespace (dlopened library)",
894               ns_get_dlopened_string_anon());
895
896  // They should belong to different namespaces (private and anonymous)
897  ASSERT_STREQ("This string is from private namespace (dlopened library)",
898               ns_get_dlopened_string_private());
899
900  ASSERT_TRUE(ns_get_dlopened_string_anon() != ns_get_dlopened_string_private());
901}
902