linker: fix error message for inaccessible libs
Added a test to make sure linker produces correct error message
when user attempts to load a library in a linked namespace and fails.
Bug: http://b/67866190
Bug: http://b/64950640
Bug: http://b/64888291
Test: bionic-unit-test --gtest_filter=dlext*
Change-Id: I5b5c2070d1388eff123118350b2b5c8fc7571a29
diff --git a/linker/linker.cpp b/linker/linker.cpp
index ec92c92..5f906c8 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1433,6 +1433,8 @@
if (search_linked_namespaces) {
// if a library was not found - look into linked namespaces
+ // preserve current dlerror in the case it fails.
+ DlErrorRestorer dlerror_restorer;
for (auto& linked_namespace : ns->linked_namespaces()) {
if (find_library_in_linked_namespace(linked_namespace,
task)) {
diff --git a/linker/linker_globals.h b/linker/linker_globals.h
index d8134af..11ccbd5 100644
--- a/linker/linker_globals.h
+++ b/linker/linker_globals.h
@@ -32,6 +32,7 @@
#include <link.h>
#include <stddef.h>
+#include <string>
#include <unordered_map>
#include <async_safe/log.h>
@@ -39,7 +40,6 @@
#define DL_ERR(fmt, x...) \
do { \
async_safe_format_buffer(linker_get_error_buffer(), linker_get_error_buffer_size(), fmt, ##x); \
- /* If LD_DEBUG is set high enough, log every dlerror(3) message. */ \
} while (false)
#define DL_WARN(fmt, x...) \
@@ -75,4 +75,16 @@
char* linker_get_error_buffer();
size_t linker_get_error_buffer_size();
+class DlErrorRestorer {
+ public:
+ DlErrorRestorer() {
+ saved_error_msg_ = linker_get_error_buffer();
+ }
+ ~DlErrorRestorer() {
+ strlcpy(linker_get_error_buffer(), saved_error_msg_.c_str(), linker_get_error_buffer_size());
+ }
+ private:
+ std::string saved_error_msg_;
+};
+
#endif /* __LINKER_GLOBALS_H */
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index 7028ca7..3f6da59 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -1589,6 +1589,54 @@
ASSERT_STREQ("dlopen failed: library \"libnstest_public.so\" not found", dlerror());
}
+TEST(dlext, ns_inaccessible_error_message) {
+ // We set up 2 namespaces (a and b) and link a->b with a shared library
+ // libtestshared.so. Then try to dlopen different library with the same
+ // name from in namespace a. Note that library should not be accessible
+ // in either namespace but since it's soname is in the list of shared libs
+ // the linker will attempt to find it in linked namespace.
+ //
+ // Check the error message and make sure it mentions correct namespace name.
+ 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() + "/private_namespace_libs").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().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_a, ns_b, "libtestshared.so")) << dlerror();
+
+ android_dlextinfo extinfo;
+ extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+ extinfo.library_namespace = ns_a;
+
+ std::string library_path = get_testlib_root() + "/inaccessible_libs/libtestshared.so";
+
+ void* handle = android_dlopen_ext(library_path.c_str(), RTLD_NOW, &extinfo);
+ ASSERT_TRUE(handle == nullptr);
+ std::string expected_dlerror =
+ android::base::StringPrintf("dlopen failed: library \"%s\" needed or dlopened by \"%s\""
+ " is not accessible for the namespace \"ns_a\"",
+ library_path.c_str(),
+ get_executable_path().c_str());
+ ASSERT_EQ(expected_dlerror, dlerror());
+}
+
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 ba0b1aa..5f27387 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -440,6 +440,16 @@
}
// -----------------------------------------------------------------------------
+// Library for inaccessible shared library test
+// -----------------------------------------------------------------------------
+cc_test_library {
+ name: "libtestshared",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["empty.cpp"],
+ relative_install_path: "/inaccessible_libs",
+}
+
+// -----------------------------------------------------------------------------
// Library with weak undefined function
// -----------------------------------------------------------------------------
cc_test_library {