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