linker: Allow link namespaces without name filters

This commit allows users to create a link without soname filters between
two linker namespaces.

The motivation is to establish one-way shared library isolation.  For
example, assume that there are two linker namespaces `default` and
`vndk`.  We would like to limit the shared libraries that can be used by
the `default` namespace.  In the meanwhile, we would like to allow the
`vndk` namespace to use shared libs from the `default` namespace if the
soname cannot be find in the search path or loaded sonames of the `vndk`
namespace.

          shared_libs  = %VNDK_CORE_LIBRARIES%
          shared_libs += %VNDK_SAMEPROCESS_LIBRARIES%
    vndk <-------------------------------------------- default
       \_______________________________________________/^
                allow_all_shared_libs = true

android_link_namespaces_all_libs() is added to libdl, but it is
versioned as LIBC_PRIVATE.  android_link_namespaces_all_libs() is only
for unit tests.

Bug: 69824336

Test: adb shell /data/nativetest/linker-unit-tests/linker-unit-tests32
Test: adb shell /data/nativetest64/linker-unit-tests/linker-unit-tests64

Test: adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests
Test: adb shell /data/nativetest64/bionic-unit-tests/bionic-unit-tests

Test: Update /system/etc/ld.config*.txt and check whether the vndk
linker namespace of the vendor process can access the shared libs from
the default linker namespace.

Change-Id: I2879f0c5f5af60c7e56f8f743ebd2872e552286b
diff --git a/libdl/libdl.arm.map b/libdl/libdl.arm.map
index 1fcfc58..7ed9503 100644
--- a/libdl/libdl.arm.map
+++ b/libdl/libdl.arm.map
@@ -41,6 +41,11 @@
     __cfi_slowpath_diag;
 } LIBC_N;
 
+LIBC_PRIVATE {
+  global:
+    android_link_namespaces_all_libs;
+} LIBC_OMR1;
+
 LIBC_PLATFORM {
   global:
     __cfi_init;
diff --git a/libdl/libdl.arm64.map b/libdl/libdl.arm64.map
index 8d4019c..199f2e3 100644
--- a/libdl/libdl.arm64.map
+++ b/libdl/libdl.arm64.map
@@ -40,6 +40,11 @@
     __cfi_slowpath_diag;
 } LIBC_N;
 
+LIBC_PRIVATE {
+  global:
+    android_link_namespaces_all_libs;
+} LIBC_OMR1;
+
 LIBC_PLATFORM {
   global:
     __cfi_init;
diff --git a/libdl/libdl.cpp b/libdl/libdl.cpp
index c834088..4c2415f 100644
--- a/libdl/libdl.cpp
+++ b/libdl/libdl.cpp
@@ -93,6 +93,11 @@
                                 const char* shared_libs_sonames);
 
 __attribute__((__weak__, visibility("default")))
+bool __loader_android_link_namespaces_all_libs(
+                                struct android_namespace_t* namespace_from,
+                                struct android_namespace_t* namespace_to);
+
+__attribute__((__weak__, visibility("default")))
 void __loader_android_dlwarning(void* obj, void (*f)(void*, const char*));
 
 __attribute__((__weak__, visibility("default")))
@@ -205,6 +210,12 @@
 }
 
 __attribute__((__weak__))
+bool android_link_namespaces_all_libs(struct android_namespace_t* namespace_from,
+                                      struct android_namespace_t* namespace_to) {
+  return __loader_android_link_namespaces_all_libs(namespace_from, namespace_to);
+}
+
+__attribute__((__weak__))
 void android_dlwarning(void* obj, void (*f)(void*, const char*)) {
   __loader_android_dlwarning(obj, f);
 }
diff --git a/libdl/libdl.map.txt b/libdl/libdl.map.txt
index 002e9f8..579ffa7 100644
--- a/libdl/libdl.map.txt
+++ b/libdl/libdl.map.txt
@@ -40,6 +40,11 @@
     __cfi_slowpath_diag;
 } LIBC_N;
 
+LIBC_PRIVATE {
+  global:
+    android_link_namespaces_all_libs;
+} LIBC_OMR1;
+
 LIBC_PLATFORM {
   global:
     __cfi_init;
diff --git a/libdl/libdl.mips.map b/libdl/libdl.mips.map
index 8d4019c..199f2e3 100644
--- a/libdl/libdl.mips.map
+++ b/libdl/libdl.mips.map
@@ -40,6 +40,11 @@
     __cfi_slowpath_diag;
 } LIBC_N;
 
+LIBC_PRIVATE {
+  global:
+    android_link_namespaces_all_libs;
+} LIBC_OMR1;
+
 LIBC_PLATFORM {
   global:
     __cfi_init;
diff --git a/libdl/libdl.mips64.map b/libdl/libdl.mips64.map
index 8d4019c..199f2e3 100644
--- a/libdl/libdl.mips64.map
+++ b/libdl/libdl.mips64.map
@@ -40,6 +40,11 @@
     __cfi_slowpath_diag;
 } LIBC_N;
 
+LIBC_PRIVATE {
+  global:
+    android_link_namespaces_all_libs;
+} LIBC_OMR1;
+
 LIBC_PLATFORM {
   global:
     __cfi_init;
diff --git a/libdl/libdl.x86.map b/libdl/libdl.x86.map
index 8d4019c..199f2e3 100644
--- a/libdl/libdl.x86.map
+++ b/libdl/libdl.x86.map
@@ -40,6 +40,11 @@
     __cfi_slowpath_diag;
 } LIBC_N;
 
+LIBC_PRIVATE {
+  global:
+    android_link_namespaces_all_libs;
+} LIBC_OMR1;
+
 LIBC_PLATFORM {
   global:
     __cfi_init;
diff --git a/libdl/libdl.x86_64.map b/libdl/libdl.x86_64.map
index 8d4019c..199f2e3 100644
--- a/libdl/libdl.x86_64.map
+++ b/libdl/libdl.x86_64.map
@@ -40,6 +40,11 @@
     __cfi_slowpath_diag;
 } LIBC_N;
 
+LIBC_PRIVATE {
+  global:
+    android_link_namespaces_all_libs;
+} LIBC_OMR1;
+
 LIBC_PLATFORM {
   global:
     __cfi_init;
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 7f40f90..4b84537 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -65,6 +65,8 @@
 bool __loader_android_link_namespaces(android_namespace_t* namespace_from,
                                       android_namespace_t* namespace_to,
                                       const char* shared_libs_sonames) __LINKER_PUBLIC__;
+bool __loader_android_link_namespaces_all_libs(android_namespace_t* namespace_from,
+                                               android_namespace_t* namespace_to) __LINKER_PUBLIC__;
 void __loader_android_set_application_target_sdk_version(uint32_t target) __LINKER_PUBLIC__;
 void __loader_android_update_LD_LIBRARY_PATH(const char* ld_library_path) __LINKER_PUBLIC__;
 void __loader_cfi_fail(uint64_t CallSiteTypeId,
@@ -266,6 +268,19 @@
   return success;
 }
 
+bool __loader_android_link_namespaces_all_libs(android_namespace_t* namespace_from,
+                                               android_namespace_t* namespace_to) {
+  ScopedPthreadMutexLocker locker(&g_dl_mutex);
+
+  bool success = link_namespaces_all_libs(namespace_from, namespace_to);
+
+  if (!success) {
+    __bionic_format_dlerror("android_link_namespaces_all_libs failed", linker_get_error_buffer());
+  }
+
+  return success;
+}
+
 android_namespace_t* __loader_android_get_exported_namespace(const char* name) {
   return get_exported_namespace(name);
 }
diff --git a/linker/ld_android.cpp b/linker/ld_android.cpp
index c4ce1b9..4a05772 100644
--- a/linker/ld_android.cpp
+++ b/linker/ld_android.cpp
@@ -49,6 +49,7 @@
 __strong_alias(__loader_android_get_exported_namespace, __internal_linker_error);
 __strong_alias(__loader_android_init_anonymous_namespace, __internal_linker_error);
 __strong_alias(__loader_android_link_namespaces, __internal_linker_error);
+__strong_alias(__loader_android_link_namespaces_all_libs, __internal_linker_error);
 __strong_alias(__loader_android_set_application_target_sdk_version, __internal_linker_error);
 __strong_alias(__loader_android_update_LD_LIBRARY_PATH, __internal_linker_error);
 __strong_alias(__loader_cfi_fail, __internal_linker_error);
diff --git a/linker/linker.arm.map b/linker/linker.arm.map
index 4a3f177..a58e7c8 100644
--- a/linker/linker.arm.map
+++ b/linker/linker.arm.map
@@ -17,6 +17,7 @@
     __loader_android_dlwarning;
     __loader_cfi_fail;
     __loader_android_link_namespaces;
+    __loader_android_link_namespaces_all_libs;
     __loader_android_get_exported_namespace;
     __loader_dl_unwind_find_exidx;
     __loader_add_thread_local_dtor;
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 05efc55..0b8d5ee 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1430,7 +1430,7 @@
   }
 
   // returning true with empty soinfo means that the library is okay to be
-  // loaded in the namespace buy has not yet been loaded there before.
+  // loaded in the namespace but has not yet been loaded there before.
   task->set_soinfo(nullptr);
   return true;
 }
@@ -2363,7 +2363,8 @@
     add_soinfos_to_namespace(parent_namespace->soinfo_list(), ns);
     // and copy parent namespace links
     for (auto& link : parent_namespace->linked_namespaces()) {
-      ns->add_linked_namespace(link.linked_namespace(), link.shared_lib_sonames());
+      ns->add_linked_namespace(link.linked_namespace(), link.shared_lib_sonames(),
+                               link.allow_all_shared_libs());
     }
   } else {
     // If not shared - copy only the shared group
@@ -2399,7 +2400,25 @@
   std::unordered_set<std::string> sonames_set(sonames.begin(), sonames.end());
 
   ProtectedDataGuard guard;
-  namespace_from->add_linked_namespace(namespace_to, sonames_set);
+  namespace_from->add_linked_namespace(namespace_to, sonames_set, false);
+
+  return true;
+}
+
+bool link_namespaces_all_libs(android_namespace_t* namespace_from,
+                              android_namespace_t* namespace_to) {
+  if (namespace_from == nullptr) {
+    DL_ERR("error linking namespaces: namespace_from is null.");
+    return false;
+  }
+
+  if (namespace_to == nullptr) {
+    DL_ERR("error linking namespaces: namespace_to is null.");
+    return false;
+  }
+
+  ProtectedDataGuard guard;
+  namespace_from->add_linked_namespace(namespace_to, std::unordered_set<std::string>(), true);
 
   return true;
 }
@@ -3763,7 +3782,11 @@
       auto it_to = namespaces.find(ns_link.ns_name());
       CHECK(it_to != namespaces.end());
       android_namespace_t* namespace_to = it_to->second;
-      link_namespaces(namespace_from, namespace_to, ns_link.shared_libs().c_str());
+      if (ns_link.allow_all_shared_libs()) {
+        link_namespaces_all_libs(namespace_from, namespace_to);
+      } else {
+        link_namespaces(namespace_from, namespace_to, ns_link.shared_libs().c_str());
+      }
     }
   }
   // we can no longer rely on the fact that libdl.so is part of default namespace
diff --git a/linker/linker.generic.map b/linker/linker.generic.map
index 04f4c8a..45bb0b5 100644
--- a/linker/linker.generic.map
+++ b/linker/linker.generic.map
@@ -17,6 +17,7 @@
     __loader_android_dlwarning;
     __loader_cfi_fail;
     __loader_android_link_namespaces;
+    __loader_android_link_namespaces_all_libs;
     __loader_android_get_exported_namespace;
     __loader_add_thread_local_dtor;
     __loader_remove_thread_local_dtor;
diff --git a/linker/linker.h b/linker/linker.h
index 6ebca4c..29d40fa 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -180,6 +180,9 @@
                      android_namespace_t* namespace_to,
                      const char* shared_lib_sonames);
 
+bool link_namespaces_all_libs(android_namespace_t* namespace_from,
+                              android_namespace_t* namespace_to);
+
 android_namespace_t* get_exported_namespace(const char* name);
 
 void increment_dso_handle_reference_counter(void* dso_handle);
diff --git a/linker/linker_config.cpp b/linker/linker_config.cpp
index 60b7ad9..83c2f36 100644
--- a/linker/linker_config.cpp
+++ b/linker/linker_config.cpp
@@ -489,12 +489,15 @@
         return false;
       }
 
+      bool allow_all_shared_libs = properties.get_bool(property_name_prefix + ".link." +
+                                                       linked_ns_name + ".allow_all_shared_libs");
+
       std::string shared_libs = properties.get_string(property_name_prefix +
                                                       ".link." +
                                                       linked_ns_name +
                                                       ".shared_libs", &lineno);
 
-      if (shared_libs.empty()) {
+      if (!allow_all_shared_libs && shared_libs.empty()) {
         *error_msg = create_error_msg(ld_config_file_path,
                                       lineno,
                                       std::string("list of shared_libs for ") +
@@ -505,7 +508,15 @@
         return false;
       }
 
-      ns_config->add_namespace_link(linked_ns_name, shared_libs);
+      if (allow_all_shared_libs && !shared_libs.empty()) {
+        *error_msg = create_error_msg(ld_config_file_path, lineno,
+                                      std::string("both shared_libs and allow_all_shared_libs "
+                                                  "are set for ") +
+                                      name + "->" + linked_ns_name + " link.");
+        return false;
+      }
+
+      ns_config->add_namespace_link(linked_ns_name, shared_libs, allow_all_shared_libs);
     }
 
     ns_config->set_isolated(properties.get_bool(property_name_prefix + ".isolated"));
diff --git a/linker/linker_config.h b/linker/linker_config.h
index dde9362..0c50d57 100644
--- a/linker/linker_config.h
+++ b/linker/linker_config.h
@@ -43,8 +43,10 @@
 class NamespaceLinkConfig {
  public:
   NamespaceLinkConfig() = default;
-  NamespaceLinkConfig(const std::string& ns_name, const std::string& shared_libs)
-      : ns_name_(ns_name), shared_libs_(shared_libs)  {}
+  NamespaceLinkConfig(const std::string& ns_name, const std::string& shared_libs,
+                      bool allow_all_shared_libs)
+      : ns_name_(ns_name), shared_libs_(shared_libs),
+        allow_all_shared_libs_(allow_all_shared_libs) {}
 
   const std::string& ns_name() const {
     return ns_name_;
@@ -54,9 +56,14 @@
     return shared_libs_;
   }
 
+  bool allow_all_shared_libs() const {
+    return allow_all_shared_libs_;
+  }
+
  private:
   std::string ns_name_;
   std::string shared_libs_;
+  bool allow_all_shared_libs_;
 };
 
 class NamespaceConfig {
@@ -89,8 +96,9 @@
     return namespace_links_;
   }
 
-  void add_namespace_link(const std::string& ns_name, const std::string& shared_libs) {
-    namespace_links_.push_back(NamespaceLinkConfig(ns_name, shared_libs));
+  void add_namespace_link(const std::string& ns_name, const std::string& shared_libs,
+                          bool allow_all_shared_libs) {
+    namespace_links_.push_back(NamespaceLinkConfig(ns_name, shared_libs, allow_all_shared_libs));
   }
 
   void set_isolated(bool isolated) {
diff --git a/linker/linker_namespaces.h b/linker/linker_namespaces.h
index 16906d6..a7fe0d5 100644
--- a/linker/linker_namespaces.h
+++ b/linker/linker_namespaces.h
@@ -40,8 +40,10 @@
 struct android_namespace_link_t {
  public:
   android_namespace_link_t(android_namespace_t* linked_namespace,
-                           const std::unordered_set<std::string>& shared_lib_sonames)
-      : linked_namespace_(linked_namespace), shared_lib_sonames_(shared_lib_sonames)
+                           const std::unordered_set<std::string>& shared_lib_sonames,
+                           bool allow_all_shared_libs)
+      : linked_namespace_(linked_namespace), shared_lib_sonames_(shared_lib_sonames),
+        allow_all_shared_libs_(allow_all_shared_libs)
   {}
 
   android_namespace_t* linked_namespace() const {
@@ -53,12 +55,17 @@
   }
 
   bool is_accessible(const char* soname) const {
-    return shared_lib_sonames_.find(soname) != shared_lib_sonames_.end();
+    return allow_all_shared_libs_ || shared_lib_sonames_.find(soname) != shared_lib_sonames_.end();
+  }
+
+  bool allow_all_shared_libs() const {
+    return allow_all_shared_libs_;
   }
 
  private:
   android_namespace_t* const linked_namespace_;
   const std::unordered_set<std::string> shared_lib_sonames_;
+  bool allow_all_shared_libs_;
 };
 
 struct android_namespace_t {
@@ -105,8 +112,10 @@
     return linked_namespaces_;
   }
   void add_linked_namespace(android_namespace_t* linked_namespace,
-                            const std::unordered_set<std::string>& shared_lib_sonames) {
-    linked_namespaces_.push_back(android_namespace_link_t(linked_namespace, shared_lib_sonames));
+                            const std::unordered_set<std::string>& shared_lib_sonames,
+                            bool allow_all_shared_libs) {
+    linked_namespaces_.push_back(
+        android_namespace_link_t(linked_namespace, shared_lib_sonames, allow_all_shared_libs));
   }
 
   void add_soinfo(soinfo* si) {
diff --git a/linker/tests/linker_config_test.cpp b/linker/tests/linker_config_test.cpp
index 4c0dcdd..e716879 100644
--- a/linker/tests/linker_config_test.cpp
+++ b/linker/tests/linker_config_test.cpp
@@ -81,6 +81,8 @@
   "namespace.vndk.search.paths = /system/${LIB}/vndk\n"
   "namespace.vndk.asan.search.paths = /data\n"
   "namespace.vndk.asan.search.paths += /system/${LIB}/vndk\n"
+  "namespace.vndk.links = default\n"
+  "namespace.vndk.link.default.allow_all_shared_libs = true\n"
   "\n";
 
 static bool write_version(const std::string& path, uint32_t version) {
@@ -154,10 +156,14 @@
 
   const auto& default_ns_links = default_ns_config->links();
   ASSERT_EQ(2U, default_ns_links.size());
+
   ASSERT_EQ("system", default_ns_links[0].ns_name());
   ASSERT_EQ("libc.so:libm.so:libdl.so:libstdc++.so", default_ns_links[0].shared_libs());
+  ASSERT_FALSE(default_ns_links[0].allow_all_shared_libs());
+
   ASSERT_EQ("vndk", default_ns_links[1].ns_name());
   ASSERT_EQ("libcutils.so:libbase.so", default_ns_links[1].shared_libs());
+  ASSERT_FALSE(default_ns_links[1].allow_all_shared_libs());
 
   auto& ns_configs = config->namespace_configs();
   ASSERT_EQ(3U, ns_configs.size());
@@ -187,8 +193,13 @@
   ASSERT_TRUE(ns_vndk != nullptr) << "vndk namespace was not found";
 
   ASSERT_FALSE(ns_vndk->isolated()); // malformed bool property
-  ASSERT_FALSE(ns_vndk->visible()); // undefined bool property 
+  ASSERT_FALSE(ns_vndk->visible()); // undefined bool property
   ASSERT_EQ(kExpectedVndkSearchPath, ns_vndk->search_paths());
+
+  const auto& ns_vndk_links = ns_vndk->links();
+  ASSERT_EQ(1U, ns_vndk_links.size());
+  ASSERT_EQ("default", ns_vndk_links[0].ns_name());
+  ASSERT_TRUE(ns_vndk_links[0].allow_all_shared_libs());
 }
 
 TEST(linker_config, smoke) {
@@ -198,3 +209,40 @@
 TEST(linker_config, asan_smoke) {
   run_linker_config_smoke_test(true);
 }
+
+TEST(linker_config, ns_link_shared_libs_invalid_settings) {
+  // This unit test ensures an error is emitted when a namespace link in ld.config.txt specifies
+  // both shared_libs and allow_all_shared_libs.
+
+  static const char config_str[] =
+    "dir.test = /data/local/tmp\n"
+    "\n"
+    "[test]\n"
+    "additional.namespaces = system\n"
+    "namespace.default.links = system\n"
+    "namespace.default.link.system.shared_libs = libc.so:libm.so\n"
+    "namespace.default.link.system.allow_all_shared_libs = true\n"
+    "\n";
+
+  TemporaryFile tmp_file;
+  close(tmp_file.fd);
+  tmp_file.fd = -1;
+
+  android::base::WriteStringToFile(config_str, tmp_file.path);
+
+  TemporaryDir tmp_dir;
+
+  std::string executable_path = std::string(tmp_dir.path) + "/some-binary";
+
+  const Config* config = nullptr;
+  std::string error_msg;
+  ASSERT_FALSE(Config::read_binary_config(tmp_file.path,
+                                          executable_path.c_str(),
+                                          false,
+                                          &config,
+                                          &error_msg));
+  ASSERT_TRUE(config == nullptr);
+  ASSERT_EQ(std::string(tmp_file.path) + ":6: "
+            "error: both shared_libs and allow_all_shared_libs are set for default->system link.",
+            error_msg);
+}
diff --git a/tests/Android.bp b/tests/Android.bp
index c1e455d..1521b73 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -554,6 +554,10 @@
         "libnstest_root",
         "libnstest_public",
         "libnstest_public_internal",
+        "libnstest_ns_a_public1",
+        "libnstest_ns_a_public1_internal",
+        "libnstest_ns_b_public2",
+        "libnstest_ns_b_public3",
     ],
 }
 
diff --git a/tests/dlext_private.h b/tests/dlext_private.h
index dea92ee..2621a68 100644
--- a/tests/dlext_private.h
+++ b/tests/dlext_private.h
@@ -95,6 +95,9 @@
                                     android_namespace_t* to,
                                     const char* shared_libs_sonames);
 
+extern bool android_link_namespaces_all_libs(android_namespace_t* from,
+                                             android_namespace_t* to);
+
 extern void android_set_application_target_sdk_version(uint32_t target);
 
 __END_DECLS
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index 64cfa08..bb2d8a3 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -1737,6 +1737,123 @@
   ASSERT_EQ(expected_dlerror, dlerror());
 }
 
+TEST(dlext, ns_link_namespaces_invalid_arguments) {
+  ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
+
+  android_namespace_t* ns =
+          android_create_namespace("private",
+                                   nullptr,
+                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
+                                   ANDROID_NAMESPACE_TYPE_REGULAR,
+                                   nullptr,
+                                   nullptr);
+  ASSERT_TRUE(ns != nullptr) << dlerror();
+
+  // Test android_link_namespaces()
+  ASSERT_FALSE(android_link_namespaces(nullptr, nullptr, "libc.so"));
+  ASSERT_STREQ("android_link_namespaces failed: error linking namespaces: namespace_from is null.",
+               dlerror());
+
+  ASSERT_FALSE(android_link_namespaces(ns, nullptr, nullptr));
+  ASSERT_STREQ("android_link_namespaces failed: "
+               "error linking namespaces \"private\"->\"(default)\": "
+               "the list of shared libraries is empty.", dlerror());
+
+  ASSERT_FALSE(android_link_namespaces(ns, nullptr, ""));
+  ASSERT_STREQ("android_link_namespaces failed: "
+               "error linking namespaces \"private\"->\"(default)\": "
+               "the list of shared libraries is empty.", dlerror());
+
+  // Test android_link_namespaces_all_libs()
+  ASSERT_FALSE(android_link_namespaces_all_libs(nullptr, nullptr));
+  ASSERT_STREQ("android_link_namespaces_all_libs failed: "
+               "error linking namespaces: namespace_from is null.", dlerror());
+
+  ASSERT_FALSE(android_link_namespaces_all_libs(nullptr, ns));
+  ASSERT_STREQ("android_link_namespaces_all_libs failed: "
+               "error linking namespaces: namespace_from is null.", dlerror());
+
+  ASSERT_FALSE(android_link_namespaces_all_libs(ns, nullptr));
+  ASSERT_STREQ("android_link_namespaces_all_libs failed: "
+               "error linking namespaces: namespace_to is null.", dlerror());
+}
+
+TEST(dlext, ns_allow_all_shared_libs) {
+  ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
+
+  android_namespace_t* ns_a =
+          android_create_namespace("ns_a",
+                                   nullptr,
+                                   (get_testlib_root() + "/ns_a").c_str(),
+                                   ANDROID_NAMESPACE_TYPE_ISOLATED,
+                                   nullptr,
+                                   nullptr);
+  ASSERT_TRUE(ns_a != nullptr) << dlerror();
+  ASSERT_TRUE(android_link_namespaces(ns_a, nullptr, g_core_shared_libs.c_str())) << dlerror();
+
+  android_namespace_t* ns_b =
+          android_create_namespace("ns_b",
+                                   nullptr,
+                                   (get_testlib_root() + "/ns_b").c_str(),
+                                   ANDROID_NAMESPACE_TYPE_ISOLATED,
+                                   nullptr,
+                                   nullptr);
+  ASSERT_TRUE(ns_b != nullptr) << dlerror();
+  ASSERT_TRUE(android_link_namespaces(ns_b, nullptr, g_core_shared_libs.c_str())) << dlerror();
+
+  ASSERT_TRUE(android_link_namespaces(ns_b, ns_a, "libnstest_ns_a_public1.so")) << dlerror();
+  ASSERT_TRUE(android_link_namespaces_all_libs(ns_a, ns_b)) << dlerror();
+
+  // Load libs with android_dlopen_ext() from namespace b
+  android_dlextinfo extinfo;
+  extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+  extinfo.library_namespace = ns_b;
+
+  void* ns_b_handle1 = android_dlopen_ext("libnstest_ns_a_public1.so", RTLD_NOW, &extinfo);
+  ASSERT_TRUE(ns_b_handle1 != nullptr) << dlerror();
+
+  void* ns_b_handle1_internal =
+      android_dlopen_ext("libnstest_ns_a_public1_internal.so", RTLD_NOW, &extinfo);
+  ASSERT_TRUE(ns_b_handle1_internal == nullptr);
+
+  void* ns_b_handle2 = android_dlopen_ext("libnstest_ns_b_public2.so", RTLD_NOW, &extinfo);
+  ASSERT_TRUE(ns_b_handle2 != nullptr) << dlerror();
+
+  void* ns_b_handle3 = android_dlopen_ext("libnstest_ns_b_public3.so", RTLD_NOW, &extinfo);
+  ASSERT_TRUE(ns_b_handle3 != nullptr) << dlerror();
+
+  // Load libs with android_dlopen_ext() from namespace a
+  extinfo.library_namespace = ns_a;
+
+  void* ns_a_handle1 = android_dlopen_ext("libnstest_ns_a_public1.so", RTLD_NOW, &extinfo);
+  ASSERT_TRUE(ns_a_handle1 != nullptr) << dlerror();
+
+  void* ns_a_handle1_internal =
+      android_dlopen_ext("libnstest_ns_a_public1_internal.so", RTLD_NOW, &extinfo);
+  ASSERT_TRUE(ns_a_handle1_internal != nullptr) << dlerror();
+
+  void* ns_a_handle2 = android_dlopen_ext("libnstest_ns_b_public2.so", RTLD_NOW, &extinfo);
+  ASSERT_TRUE(ns_a_handle2 != nullptr) << dlerror();
+
+  void* ns_a_handle3 = android_dlopen_ext("libnstest_ns_b_public3.so", RTLD_NOW, &extinfo);
+  ASSERT_TRUE(ns_a_handle3 != nullptr) << dlerror();
+
+  // Compare the dlopen handle
+  ASSERT_EQ(ns_b_handle1, ns_a_handle1);
+  ASSERT_EQ(ns_b_handle2, ns_a_handle2);
+  ASSERT_EQ(ns_b_handle3, ns_a_handle3);
+
+  // Close libs
+  dlclose(ns_b_handle1);
+  dlclose(ns_b_handle2);
+  dlclose(ns_b_handle3);
+
+  dlclose(ns_a_handle1);
+  dlclose(ns_a_handle1_internal);
+  dlclose(ns_a_handle2);
+  dlclose(ns_a_handle3);
+}
+
 TEST(dlext, ns_anonymous) {
   static const char* root_lib = "libnstest_root.so";
   std::string shared_libs = g_core_shared_libs + ":" + g_public_lib;
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index 61a837f..cae30b5 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -259,6 +259,58 @@
 }
 
 // -----------------------------------------------------------------------------
+// Build test helper libraries for linker namespaces for allow all shared libs
+//
+// This set of libraries is used to verify linker namespaces for allow all
+// shared libs.
+//
+// Test cases
+// 1. Check that namespace a exposes libnstest_ns_a_public1 to
+//    namespace b while keeping libnstest_ns_a_public1_internal as an
+//    internal lib.
+// 2. Check that namespace b exposes all libraries to namespace a.
+//
+// Dependency tree (visibility)
+// libnstest_ns_b_public2.so  (ns:b)
+// +-> libnstest_ns_a_public1.so  (ns:a)
+//     +-> libnstest_ns_a_public2_internal.so  (ns:a)
+//     +-> libnstest_ns_b_public3.so  (ns:b)
+//
+// -----------------------------------------------------------------------------
+cc_test_library {
+    name: "libnstest_ns_a_public1",
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["libnstest_ns_a_public1.cpp"],
+    relative_install_path: "bionic-loader-test-libs/ns_a",
+    shared_libs: [
+        "libnstest_ns_a_public1_internal",
+        "libnstest_ns_b_public3",
+    ],
+}
+
+cc_test_library {
+    name: "libnstest_ns_a_public1_internal",
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["libnstest_ns_a_public1_internal.cpp"],
+    relative_install_path: "bionic-loader-test-libs/ns_a",
+}
+
+cc_test_library {
+    name: "libnstest_ns_b_public2",
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["libnstest_ns_b_public2.cpp"],
+    relative_install_path: "bionic-loader-test-libs/ns_b",
+    shared_libs: ["libnstest_ns_a_public1"],
+}
+
+cc_test_library {
+    name: "libnstest_ns_b_public3",
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["libnstest_ns_b_public3.cpp"],
+    relative_install_path: "bionic-loader-test-libs/ns_b",
+}
+
+// -----------------------------------------------------------------------------
 // Build DT_RUNPATH test helper libraries
 // -----------------------------------------------------------------------------
 // include $(LOCAL_PATH)/Android.build.dt_runpath.mk
diff --git a/tests/libs/libnstest_ns_a_public1.cpp b/tests/libs/libnstest_ns_a_public1.cpp
new file mode 100644
index 0000000..c095e60
--- /dev/null
+++ b/tests/libs/libnstest_ns_a_public1.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+static const char ns_a_public1_string[] = "libnstest_ns_a_public1.so";
+
+extern "C" const char* get_ns_a_public1_string() {
+  return ns_a_public1_string;
+}
+
+
+extern "C" const char *get_ns_a_public1_internal_string();
+
+extern "C" const char *delegate_get_ns_a_public1_internal_string() {
+  return get_ns_a_public1_internal_string();
+}
+
+
+extern "C" const char *get_ns_b_public3_string();
+
+extern "C" const char *delegate_get_ns_b_public3_string() {
+  return get_ns_b_public3_string();
+}
diff --git a/tests/libs/libnstest_ns_a_public1_internal.cpp b/tests/libs/libnstest_ns_a_public1_internal.cpp
new file mode 100644
index 0000000..6529936
--- /dev/null
+++ b/tests/libs/libnstest_ns_a_public1_internal.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+static const char ns_a_public1_internal_string[] = "libnstest_ns_a_public1_internal.so";
+
+extern "C" const char* get_ns_a_public1_internal_string() {
+  return ns_a_public1_internal_string;
+}
diff --git a/tests/libs/libnstest_ns_b_public2.cpp b/tests/libs/libnstest_ns_b_public2.cpp
new file mode 100644
index 0000000..6251a8d
--- /dev/null
+++ b/tests/libs/libnstest_ns_b_public2.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+static const char ns_b_public2_string[] = "libnstest_ns_b_public2.so";
+
+extern "C" const char* get_ns_b_public2_string() {
+  return ns_b_public2_string;
+}
+
+
+extern "C" const char* get_ns_a_public1_string();
+
+extern "C" const char* delegate_get_ns_a_public1_string() {
+  return get_ns_a_public1_string();
+}
diff --git a/tests/libs/libnstest_ns_b_public3.cpp b/tests/libs/libnstest_ns_b_public3.cpp
new file mode 100644
index 0000000..b332445
--- /dev/null
+++ b/tests/libs/libnstest_ns_b_public3.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+static const char ns_b_public3_string[] = "libnstest_ns_b_public3.so";
+
+extern "C" const char* get_ns_b_public3_string() {
+  return ns_b_public3_string;
+}