From 2d020e43fb098dde99d6f9a1c5f4aeebdda914ea Mon Sep 17 00:00:00 2001 From: Vic Yang Date: Sat, 12 Jan 2019 21:03:25 -0800 Subject: [PATCH] linker: Add support for "whitelisted" property in linker config files In order to enable no-vendor-variant VNDK, we need a way to restrict a namespace to only a list of whitelisted libraries. We add a new "whitelisted" property for this. If the property is not set, all libraries in the search paths are available in a namespace. If the property is set, only the libraries named are available. Bug: 119423884 Test: Boot with no-vendor-variant VNDK enabled using the new property. Change-Id: Id808c1733c8e2c2c3462b04c72461f9698403571 --- linker/ld.config.format.md | 3 +++ linker/linker.cpp | 1 + linker/linker_config.cpp | 6 ++++++ linker/linker_config.h | 9 +++++++++ linker/linker_config_test.cpp | 20 ++++++++++++++++++-- linker/linker_namespaces.cpp | 8 ++++++++ linker/linker_namespaces.h | 11 +++++++++++ 7 files changed, 56 insertions(+), 2 deletions(-) diff --git a/linker/ld.config.format.md b/linker/ld.config.format.md index 686d6befb..faf5cc8a6 100644 --- a/linker/ld.config.format.md +++ b/linker/ld.config.format.md @@ -79,5 +79,8 @@ namespace.ns1.asan.permitted.paths = /data/vendor/${LIB} # and links it to default namespace namespace.ns.links = default namespace.ns.link.default.shared_libs = libc.so:libdl.so:libm.so:libstdc++.so + +# This defines what libraries are allowed to be loaded from ns1 +namespace.ns1.whitelisted = libsomething.so ``` diff --git a/linker/linker.cpp b/linker/linker.cpp index 49c8f11aa..c60ab6a50 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -4156,6 +4156,7 @@ std::vector init_default_namespaces(const char* executable ns->set_isolated(ns_config->isolated()); ns->set_default_library_paths(ns_config->search_paths()); ns->set_permitted_paths(ns_config->permitted_paths()); + ns->set_whitelisted_libs(ns_config->whitelisted_libs()); namespaces[ns_config->name()] = ns; if (ns_config->visible()) { diff --git a/linker/linker_config.cpp b/linker/linker_config.cpp index f7f9c41a7..437aa86bc 100644 --- a/linker/linker_config.cpp +++ b/linker/linker_config.cpp @@ -552,6 +552,12 @@ bool Config::read_binary_config(const char* ld_config_file_path, ns_config->set_isolated(properties.get_bool(property_name_prefix + ".isolated")); ns_config->set_visible(properties.get_bool(property_name_prefix + ".visible")); + std::string whitelisted = + properties.get_string(property_name_prefix + ".whitelisted", &lineno); + if (!whitelisted.empty()) { + ns_config->set_whitelisted_libs(android::base::Split(whitelisted, ":")); + } + // these are affected by is_asan flag if (is_asan) { property_name_prefix += ".asan"; diff --git a/linker/linker_config.h b/linker/linker_config.h index 49739ee90..a318bba2c 100644 --- a/linker/linker_config.h +++ b/linker/linker_config.h @@ -92,6 +92,10 @@ class NamespaceConfig { return permitted_paths_; } + const std::vector& whitelisted_libs() const { + return whitelisted_libs_; + } + const std::vector& links() const { return namespace_links_; } @@ -116,12 +120,17 @@ class NamespaceConfig { void set_permitted_paths(std::vector&& permitted_paths) { permitted_paths_ = permitted_paths; } + + void set_whitelisted_libs(std::vector&& whitelisted_libs) { + whitelisted_libs_ = whitelisted_libs; + } private: const std::string name_; bool isolated_; bool visible_; std::vector search_paths_; std::vector permitted_paths_; + std::vector whitelisted_libs_; std::vector namespace_links_; DISALLOW_IMPLICIT_CONSTRUCTORS(NamespaceConfig); diff --git a/linker/linker_config_test.cpp b/linker/linker_config_test.cpp index 6a55bb2b3..49370566c 100644 --- a/linker/linker_config_test.cpp +++ b/linker/linker_config_test.cpp @@ -56,6 +56,7 @@ static const char* config_str = "enable.target.sdk.version = true\n" "additional.namespaces=system\n" "additional.namespaces+=vndk\n" + "additional.namespaces+=vndk_in_system\n" "namespace.default.isolated = true\n" "namespace.default.search.paths = /vendor/${LIB}\n" "namespace.default.permitted.paths = /vendor/${LIB}\n" @@ -82,6 +83,12 @@ static const char* config_str = "namespace.vndk.asan.search.paths += /system/${LIB}/vndk\n" "namespace.vndk.links = default\n" "namespace.vndk.link.default.allow_all_shared_libs = true\n" + "namespace.vndk.link.vndk_in_system.allow_all_shared_libs = true\n" + "namespace.vndk_in_system.isolated = true\n" + "namespace.vndk_in_system.visible = true\n" + "namespace.vndk_in_system.search.paths = /system/${LIB}\n" + "namespace.vndk_in_system.permitted.paths = /system/${LIB}\n" + "namespace.vndk_in_system.whitelisted = libz.so:libyuv.so:libtinyxml2.so\n" "\n"; static bool write_version(const std::string& path, uint32_t version) { @@ -165,20 +172,24 @@ static void run_linker_config_smoke_test(bool is_asan) { ASSERT_FALSE(default_ns_links[1].allow_all_shared_libs()); auto& ns_configs = config->namespace_configs(); - ASSERT_EQ(3U, ns_configs.size()); + ASSERT_EQ(4U, ns_configs.size()); // find second namespace const NamespaceConfig* ns_system = nullptr; const NamespaceConfig* ns_vndk = nullptr; + const NamespaceConfig* ns_vndk_in_system = nullptr; for (auto& ns : ns_configs) { std::string ns_name = ns->name(); - ASSERT_TRUE(ns_name == "system" || ns_name == "default" || ns_name == "vndk") + ASSERT_TRUE(ns_name == "system" || ns_name == "default" || + ns_name == "vndk" || ns_name == "vndk_in_system") << "unexpected ns name: " << ns->name(); if (ns_name == "system") { ns_system = ns.get(); } else if (ns_name == "vndk") { ns_vndk = ns.get(); + } else if (ns_name == "vndk_in_system") { + ns_vndk_in_system = ns.get(); } } @@ -199,6 +210,11 @@ static void run_linker_config_smoke_test(bool is_asan) { 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()); + + ASSERT_TRUE(ns_vndk_in_system != nullptr) << "vndk_in_system namespace was not found"; + ASSERT_EQ( + std::vector({"libz.so", "libyuv.so", "libtinyxml2.so"}), + ns_vndk_in_system->whitelisted_libs()); } TEST(linker_config, smoke) { diff --git a/linker/linker_namespaces.cpp b/linker/linker_namespaces.cpp index fd72cdc73..e870ef7ad 100644 --- a/linker/linker_namespaces.cpp +++ b/linker/linker_namespaces.cpp @@ -38,6 +38,14 @@ bool android_namespace_t::is_accessible(const std::string& file) { return true; } + if (!whitelisted_libs_.empty()) { + const char *lib_name = basename(file.c_str()); + if (std::find(whitelisted_libs_.begin(), whitelisted_libs_.end(), + lib_name) == whitelisted_libs_.end()) { + return false; + } + } + for (const auto& dir : ld_library_paths_) { if (file_is_in_dir(file, dir)) { return true; diff --git a/linker/linker_namespaces.h b/linker/linker_namespaces.h index cd8b09d96..31aeeb66d 100644 --- a/linker/linker_namespaces.h +++ b/linker/linker_namespaces.h @@ -110,6 +110,16 @@ struct android_namespace_t { permitted_paths_ = permitted_paths; } + const std::vector& get_whitelisted_libs() const { + return whitelisted_libs_; + } + void set_whitelisted_libs(std::vector&& whitelisted_libs) { + whitelisted_libs_ = whitelisted_libs; + } + void set_whitelisted_libs(const std::vector& whitelisted_libs) { + whitelisted_libs_ = whitelisted_libs; + } + const std::vector& linked_namespaces() const { return linked_namespaces_; } @@ -157,6 +167,7 @@ struct android_namespace_t { std::vector ld_library_paths_; std::vector default_library_paths_; std::vector permitted_paths_; + std::vector whitelisted_libs_; // Loader looks into linked namespace if it was not able // to find a library in this namespace. Note that library // lookup in linked namespaces are limited by the list of