Introduce anonymous namespace

The anonymous namespace is introduced to
handle cases when linker can not find the
caller. This usually happens when caller
code was not loaded by dynamic linker;
for example mono-generated code.

Bug: http://b/25844435
Bug: http://b/22548808
Change-Id: I9e5b1d23c1c75bc78548d68e79216a6a943a33cf
diff --git a/libc/include/android/dlext.h b/libc/include/android/dlext.h
index d59de29..ed9a3b9 100644
--- a/libc/include/android/dlext.h
+++ b/libc/include/android/dlext.h
@@ -131,12 +131,16 @@
 extern void* android_dlopen_ext(const char* filename, int flag, const android_dlextinfo* extinfo);
 
 /*
- * Initializes public namespace. The path is the list of sonames
- * separated by colon. Example: "libc.so:libm.so:libdl.so".
- *
+ * Initializes public and anonymous namespaces. The public_ns_sonames is the list of sonames
+ * to be included into public namespace separated by colon. Example: "libc.so:libm.so:libdl.so".
  * The libraries in this list should be loaded prior to this call.
+ *
+ * The anon_ns_library_path is the search path for anonymous namespace. The anonymous namespace
+ * is used in the case when linker cannot identify the caller of dlopen/dlsym. This happens
+ * for the code not loaded by dynamic linker; for example calls from the mono-compiled code.
  */
-extern bool android_init_public_namespace(const char* path);
+extern bool android_init_namespaces(const char* public_ns_sonames,
+                                    const char* anon_ns_library_path);
 
 /*
  * Creates new linker namespace.
diff --git a/libdl/Android.mk b/libdl/Android.mk
index 9a9c756..1ea5dc7 100644
--- a/libdl/Android.mk
+++ b/libdl/Android.mk
@@ -33,7 +33,13 @@
 LOCAL_CXX_STL := none
 
 LOCAL_MODULE := libdl
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk \
+                                 $(LOCAL_PATH)/libdl.arm.map \
+                                 $(LOCAL_PATH)/libdl.arm64.map \
+                                 $(LOCAL_PATH)/libdl.mips.map \
+                                 $(LOCAL_PATH)/libdl.mips64.map \
+                                 $(LOCAL_PATH)/libdl.x86.map \
+                                 $(LOCAL_PATH)/libdl.x86_64.map \
 
 # NOTE: libdl needs __aeabi_unwind_cpp_pr0 from libgcc.a but libgcc.a needs a
 # few symbols from libc. Using --no-undefined here results in having to link
diff --git a/libdl/libdl.arm.map b/libdl/libdl.arm.map
index 3417f99..5ad9f9d 100644
--- a/libdl/libdl.arm.map
+++ b/libdl/libdl.arm.map
@@ -16,7 +16,7 @@
 
 LIBC_N {
   global:
-    android_init_public_namespace;
+    android_init_namespaces;
     android_create_namespace;
 } LIBC;
 
diff --git a/libdl/libdl.arm64.map b/libdl/libdl.arm64.map
index b7e9aec..3535774 100644
--- a/libdl/libdl.arm64.map
+++ b/libdl/libdl.arm64.map
@@ -15,7 +15,7 @@
 
 LIBC_N {
   global:
-    android_init_public_namespace;
+    android_init_namespaces;
     android_create_namespace;
 } LIBC;
 
diff --git a/libdl/libdl.c b/libdl/libdl.c
index 3cde5eb..3928ba2 100644
--- a/libdl/libdl.c
+++ b/libdl/libdl.c
@@ -49,7 +49,11 @@
 void android_set_application_target_sdk_version(uint32_t target __unused) { }
 uint32_t android_get_application_target_sdk_version() { return 0; }
 
-bool android_init_public_namespace(const char* paths __unused) { return false; }
+bool android_init_namespaces(const char* public_ns_sonames __unused,
+                             const char* anon_ns_library_path __unused) {
+  return false;
+}
+
 struct android_namespace_t* android_create_namespace(const char* name __unused,
                                                      const char* ld_library_path __unused,
                                                      const char* default_library_path __unused,
diff --git a/libdl/libdl.map.txt b/libdl/libdl.map.txt
index 421d825..8d123fe 100644
--- a/libdl/libdl.map.txt
+++ b/libdl/libdl.map.txt
@@ -30,7 +30,7 @@
 
 LIBC_N {
   global:
-    android_init_public_namespace;
+    android_init_namespaces;
     android_create_namespace;
 } LIBC;
 
diff --git a/libdl/libdl.mips.map b/libdl/libdl.mips.map
index b7e9aec..3535774 100644
--- a/libdl/libdl.mips.map
+++ b/libdl/libdl.mips.map
@@ -15,7 +15,7 @@
 
 LIBC_N {
   global:
-    android_init_public_namespace;
+    android_init_namespaces;
     android_create_namespace;
 } LIBC;
 
diff --git a/libdl/libdl.mips64.map b/libdl/libdl.mips64.map
index b7e9aec..3535774 100644
--- a/libdl/libdl.mips64.map
+++ b/libdl/libdl.mips64.map
@@ -15,7 +15,7 @@
 
 LIBC_N {
   global:
-    android_init_public_namespace;
+    android_init_namespaces;
     android_create_namespace;
 } LIBC;
 
diff --git a/libdl/libdl.x86.map b/libdl/libdl.x86.map
index b7e9aec..3535774 100644
--- a/libdl/libdl.x86.map
+++ b/libdl/libdl.x86.map
@@ -15,7 +15,7 @@
 
 LIBC_N {
   global:
-    android_init_public_namespace;
+    android_init_namespaces;
     android_create_namespace;
 } LIBC;
 
diff --git a/libdl/libdl.x86_64.map b/libdl/libdl.x86_64.map
index b7e9aec..3535774 100644
--- a/libdl/libdl.x86_64.map
+++ b/libdl/libdl.x86_64.map
@@ -15,7 +15,7 @@
 
 LIBC_N {
   global:
-    android_init_public_namespace;
+    android_init_namespaces;
     android_create_namespace;
 } LIBC;
 
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 7957921..d07ec86 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -89,9 +89,12 @@
   return dlopen_ext(filename, flags, nullptr, caller_addr);
 }
 
+extern android_namespace_t* g_anonymous_namespace;
+
 void* dlsym(void* handle, const char* symbol) {
   ScopedPthreadMutexLocker locker(&g_dl_mutex);
 
+  // TODO(dimitry): move (most of) the code below to linker.cpp
 #if !defined(__LP64__)
   if (handle == nullptr) {
     __bionic_format_dlerror("dlsym library handle is null", nullptr);
@@ -108,16 +111,10 @@
   const ElfW(Sym)* sym = nullptr;
   void* caller_addr = __builtin_return_address(0);
   soinfo* caller = find_containing_library(caller_addr);
-  if (caller == nullptr) {
-    char buf[256];
-    __libc_format_buffer(buf, sizeof(buf), "dlsym couldn't locate its caller address=%p; "
-                         "the caller was code not loaded by the dynamic linker", caller_addr);
-    __bionic_format_dlerror(buf, nullptr);
-    return nullptr;
-  }
+  android_namespace_t* ns = caller != nullptr ? caller->get_namespace() : g_anonymous_namespace;
 
   if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
-    sym = dlsym_linear_lookup(caller->get_namespace(), symbol, &found, caller, handle);
+    sym = dlsym_linear_lookup(ns, symbol, &found, caller, handle);
   } else {
     sym = dlsym_handle_lookup(reinterpret_cast<soinfo*>(handle), &found, symbol);
   }
@@ -184,11 +181,12 @@
   return get_application_target_sdk_version();
 }
 
-bool android_init_public_namespace(const char* path) {
+bool android_init_namespaces(const char* public_ns_sonames,
+                             const char* anon_ns_library_path) {
   ScopedPthreadMutexLocker locker(&g_dl_mutex);
-  bool success = init_public_namespace(path);
+  bool success = init_namespaces(public_ns_sonames, anon_ns_library_path);
   if (!success) {
-    __bionic_format_dlerror("android_init_public_namespace failed", linker_get_error_buffer());
+    __bionic_format_dlerror("android_init_namespaces failed", linker_get_error_buffer());
   }
 
   return success;
@@ -234,11 +232,11 @@
   // 00000000001 1111111112222222222 3333333333444444444455555555556666666666777 777777788888888889999999999
   // 01234567890 1234567890123456789 0123456789012345678901234567890123456789012 345678901234567890123456789
     "erate_phdr\0android_dlopen_ext\0android_set_application_target_sdk_version\0android_get_application_tar"
-  // 0000000000111111 111122222222223333333333444444 4444555555555566666666667
-  // 0123456789012345 678901234567890123456789012345 6789012345678901234567890
-    "get_sdk_version\0android_init_public_namespace\0android_create_namespace\0"
+  // 0000000000111111 111122222222223333333333 4444444444555555555566666
+  // 0123456789012345 678901234567890123456789 0123456789012345678901234
+    "get_sdk_version\0android_init_namespaces\0android_create_namespace\0"
 #if defined(__arm__)
-  // 271
+  // 265
     "dl_unwind_find_exidx\0"
 #endif
     ;
@@ -260,10 +258,10 @@
   ELFW(SYM_INITIALIZER)(111, &android_dlopen_ext, 1),
   ELFW(SYM_INITIALIZER)(130, &android_set_application_target_sdk_version, 1),
   ELFW(SYM_INITIALIZER)(173, &android_get_application_target_sdk_version, 1),
-  ELFW(SYM_INITIALIZER)(216, &android_init_public_namespace, 1),
-  ELFW(SYM_INITIALIZER)(246, &android_create_namespace, 1),
+  ELFW(SYM_INITIALIZER)(216, &android_init_namespaces, 1),
+  ELFW(SYM_INITIALIZER)(240, &android_create_namespace, 1),
 #if defined(__arm__)
-  ELFW(SYM_INITIALIZER)(271, &dl_unwind_find_exidx, 1),
+  ELFW(SYM_INITIALIZER)(265, &dl_unwind_find_exidx, 1),
 #endif
 };
 
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 1ecf65b..9780231 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -111,6 +111,7 @@
 };
 
 android_namespace_t g_default_namespace;
+android_namespace_t* g_anonymous_namespace = &g_default_namespace;
 
 static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
 
@@ -2201,7 +2202,7 @@
     return nullptr;
   }
 
-  android_namespace_t* ns = caller->get_namespace();
+  android_namespace_t* ns = caller != nullptr ? caller->get_namespace() : g_anonymous_namespace;
 
   if (extinfo != nullptr) {
     if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
@@ -2246,14 +2247,14 @@
   soinfo_unload(si);
 }
 
-bool init_public_namespace(const char* libs) {
-  CHECK(libs != nullptr);
+bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path) {
+  CHECK(public_ns_sonames != nullptr);
   if (g_public_namespace_initialized) {
-    DL_ERR("Public namespace has already been initialized.");
+    DL_ERR("public namespace has already been initialized.");
     return false;
   }
 
-  std::vector<std::string> sonames = android::base::Split(libs, ":");
+  std::vector<std::string> sonames = android::base::Split(public_ns_sonames, ":");
 
   ProtectedDataGuard guard;
 
@@ -2267,7 +2268,7 @@
     find_loaded_library_by_soname(&g_default_namespace, soname.c_str(), &candidate);
 
     if (candidate == nullptr) {
-      DL_ERR("Error initializing public namespace: \"%s\" was not found"
+      DL_ERR("error initializing public namespace: \"%s\" was not found"
              " in the default namespace", soname.c_str());
       return false;
     }
@@ -2276,8 +2277,18 @@
     g_public_namespace.push_back(candidate);
   }
 
-  failure_guard.disable();
   g_public_namespace_initialized = true;
+
+  // create anonymous namespace
+  android_namespace_t* anon_ns =
+      create_namespace("(anonymous)", nullptr, anon_ns_library_path, false);
+
+  if (anon_ns == nullptr) {
+    g_public_namespace_initialized = false;
+    return false;
+  }
+  g_anonymous_namespace = anon_ns;
+  failure_guard.disable();
   return true;
 }
 
@@ -2286,7 +2297,7 @@
                                       const char* default_library_path,
                                       bool is_isolated) {
   if (!g_public_namespace_initialized) {
-    DL_ERR("Cannot create namespace: public namespace is not initialized.");
+    DL_ERR("cannot create namespace: public namespace is not initialized.");
     return nullptr;
   }
 
diff --git a/linker/linker.h b/linker/linker.h
index c46b4e1..b391fc3 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -444,7 +444,7 @@
 void set_application_target_sdk_version(uint32_t target);
 uint32_t get_application_target_sdk_version();
 
-bool init_public_namespace(const char* path);
+bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path);
 android_namespace_t* create_namespace(const char* name, const char* ld_library_path,
                                       const char* default_library_path, bool is_isolated);
 
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index a56c771..83791eb 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -32,6 +32,7 @@
 #include <pagemap/pagemap.h>
 
 #include "TemporaryFile.h"
+#include "utils.h"
 
 #define ASSERT_DL_NOTNULL(ptr) \
     ASSERT_TRUE(ptr != nullptr) << "dlerror: " << dlerror()
@@ -610,8 +611,8 @@
   static const char* root_lib = "libnstest_root.so";
   std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
 
-  ASSERT_FALSE(android_init_public_namespace(path.c_str()));
-  ASSERT_STREQ("android_init_public_namespace failed: Error initializing public namespace: "
+  ASSERT_FALSE(android_init_namespaces(path.c_str(), nullptr));
+  ASSERT_STREQ("android_init_namespaces failed: error initializing public namespace: "
                "\"libnstest_public.so\" was not found in the default namespace", dlerror());
 
   const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
@@ -619,7 +620,7 @@
   void* handle_public = dlopen((lib_path + "/public_namespace_libs/" + g_public_lib).c_str(), RTLD_NOW);
   ASSERT_TRUE(handle_public != nullptr) << dlerror();
 
-  ASSERT_TRUE(android_init_public_namespace(path.c_str())) << dlerror();
+  ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
 
   // Check that libraries added to public namespace are NODELETE
   dlclose(handle_public);
@@ -719,7 +720,7 @@
 
   android_set_application_target_sdk_version(42U); // something > 23
 
-  ASSERT_TRUE(android_init_public_namespace(path.c_str())) << dlerror();
+  ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
 
   android_namespace_t* ns_not_isolated = android_create_namespace("private", nullptr, (lib_path + "/private_namespace_libs").c_str(), false);
   ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror();
@@ -795,3 +796,94 @@
 
   dlclose(handle1);
 }
+
+TEST(dlext, ns_anonymous) {
+  static const char* root_lib = "libnstest_root.so";
+  std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
+
+  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
+
+  void* handle_public = dlopen((lib_path + "/public_namespace_libs/" + g_public_lib).c_str(),
+                               RTLD_NOW);
+  ASSERT_TRUE(handle_public != nullptr) << dlerror();
+
+  ASSERT_TRUE(android_init_namespaces(path.c_str(), (lib_path + "/private_namespace_libs").c_str()))
+      << dlerror();
+
+  android_namespace_t* ns = android_create_namespace(
+                                "private", nullptr,
+                                (lib_path + "/private_namespace_libs").c_str(),
+                                false);
+
+  ASSERT_TRUE(ns != nullptr) << dlerror();
+
+  std::string private_library_absolute_path = lib_path + "/private_namespace_libs/" + root_lib;
+
+  android_dlextinfo extinfo;
+  extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+  extinfo.library_namespace = ns;
+
+  // we are going to copy this library to anonymous mmap and call the copy of ns_get_dlopened_string
+  void* handle = android_dlopen_ext(private_library_absolute_path.c_str(), RTLD_NOW, &extinfo);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+
+  uintptr_t ns_get_dlopened_string_addr =
+      reinterpret_cast<uintptr_t>(dlsym(handle, "ns_get_dlopened_string"));
+  ASSERT_TRUE(ns_get_dlopened_string_addr != 0) << dlerror();
+  typedef const char* (*fn_t)();
+  fn_t ns_get_dlopened_string_private = reinterpret_cast<fn_t>(ns_get_dlopened_string_addr);
+
+  std::vector<map_record> maps;
+  Maps::parse_maps(&maps);
+
+  uintptr_t addr_start = 0;
+  uintptr_t addr_end = 0;
+  std::vector<map_record> maps_to_copy;
+
+  for (const auto& rec : maps) {
+    if (rec.pathname == private_library_absolute_path) {
+      if (addr_start == 0) {
+        addr_start = rec.addr_start;
+      }
+      addr_end = rec.addr_end;
+
+      maps_to_copy.push_back(rec);
+    }
+  }
+
+  // some sanity checks..
+  ASSERT_TRUE(addr_start > 0);
+  ASSERT_TRUE(addr_end > 0);
+  ASSERT_EQ(3U, maps_to_copy.size());
+  ASSERT_TRUE(ns_get_dlopened_string_addr > addr_start);
+  ASSERT_TRUE(ns_get_dlopened_string_addr < addr_end);
+
+  // copy
+  uintptr_t reserved_addr = reinterpret_cast<uintptr_t>(mmap(nullptr, addr_end - addr_start,
+                                                             PROT_NONE, MAP_ANON | MAP_PRIVATE,
+                                                             -1, 0));
+  ASSERT_TRUE(reinterpret_cast<void*>(reserved_addr) != MAP_FAILED);
+
+  for (const auto& rec : maps_to_copy) {
+    uintptr_t offset = rec.addr_start - addr_start;
+    size_t size = rec.addr_end - rec.addr_start;
+    void* addr = reinterpret_cast<void*>(reserved_addr + offset);
+    void* map = mmap(addr, size, PROT_READ | PROT_WRITE,
+                     MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
+    ASSERT_TRUE(map != MAP_FAILED);
+    memcpy(map, reinterpret_cast<void*>(rec.addr_start), size);
+    mprotect(map, size, rec.perms);
+  }
+
+  // call the function copy
+  uintptr_t ns_get_dlopened_string_offset  = ns_get_dlopened_string_addr - addr_start;
+  fn_t ns_get_dlopened_string_anon = reinterpret_cast<fn_t>(reserved_addr + ns_get_dlopened_string_offset);
+  ASSERT_STREQ("This string is from private namespace (dlopened library)",
+               ns_get_dlopened_string_anon());
+
+  // They should belong to different namespaces (private and anonymous)
+  ASSERT_STREQ("This string is from private namespace (dlopened library)",
+               ns_get_dlopened_string_private());
+
+  ASSERT_TRUE(ns_get_dlopened_string_anon() != ns_get_dlopened_string_private());
+}
diff --git a/tests/libs/namespaces_root.cpp b/tests/libs/namespaces_root.cpp
index 0bb4611..b0006c7 100644
--- a/tests/libs/namespaces_root.cpp
+++ b/tests/libs/namespaces_root.cpp
@@ -40,10 +40,12 @@
     return nullptr;
   }
 
-  const char* result = *static_cast<const char**>(dlsym(handle, "g_private_dlopened_string"));
-  if (result != nullptr) {
+  const char** result = static_cast<const char**>(dlsym(handle, "g_private_dlopened_string"));
+  if (result == nullptr) {
+    return nullptr;
+  } else {
     g_dlopened = true;
   }
 
-  return result;
+  return *result;
 }