Add permitted_when_isolated_path to linker namespaces
The permitted_when_isolated_path is a way to white-list directories not present in search-path. It is ignored for not isolated namespaces. Bug: http://b/25853516 Bug: http://b/22548808 Change-Id: Ib1538037268eea69323ea49968a34a4a1d1938a5
This commit is contained in:
parent
df196131f3
commit
284ae3559e
9 changed files with 70 additions and 25 deletions
|
@ -152,16 +152,20 @@ extern bool android_init_namespaces(const char* public_ns_sonames,
|
|||
* 2. In directories specified by DT_RUNPATH of the "needed by" binary.
|
||||
* 3. deault_library_path (This of this as namespace-local default library path)
|
||||
*
|
||||
* When is_isolated is true the resulted namespace requires all of the libraries
|
||||
* to be on the search path; the search_path is ld_library_path:default_library_path.
|
||||
* When is_isolated is true the resulting namespace requires all of the libraries
|
||||
* to be on the search path or under the permitted_when_isolated_path; the search_path is
|
||||
* ld_library_path:default_library_path. Note that the permitted_when_isolated_path path
|
||||
* is not part of the search_path and does not affect the search order. It is a way
|
||||
* to allow loading libraries from specific locations when using absolute path.
|
||||
*
|
||||
* If a library or any of its dependencies are outside of the search path and not
|
||||
* part of the public namespace dlopen will fail.
|
||||
* If a library or any of its dependencies are outside of the permitted_when_isolated_path
|
||||
* and search_path, and it is not part of the public namespace dlopen will fail.
|
||||
*/
|
||||
extern struct android_namespace_t* android_create_namespace(const char* name,
|
||||
const char* ld_library_path,
|
||||
const char* default_library_path,
|
||||
bool is_isolated);
|
||||
bool is_isolated,
|
||||
const char* permitted_when_isolated_path);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ bool android_init_namespaces(const char* public_ns_sonames __unused,
|
|||
struct android_namespace_t* android_create_namespace(const char* name __unused,
|
||||
const char* ld_library_path __unused,
|
||||
const char* default_library_path __unused,
|
||||
bool isolated __unused) {
|
||||
bool isolated __unused,
|
||||
const char* permitted_when_isolated_path __unused) {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -193,11 +193,12 @@ bool android_init_namespaces(const char* public_ns_sonames,
|
|||
}
|
||||
|
||||
android_namespace_t* android_create_namespace(const char* name, const char* ld_library_path,
|
||||
const char* default_library_path, bool is_isolated) {
|
||||
const char* default_library_path, bool is_isolated,
|
||||
const char* permitted_when_isolated_path) {
|
||||
ScopedPthreadMutexLocker locker(&g_dl_mutex);
|
||||
|
||||
android_namespace_t* result = create_namespace(name, ld_library_path,
|
||||
default_library_path, is_isolated);
|
||||
android_namespace_t* result = create_namespace(name, ld_library_path, default_library_path,
|
||||
is_isolated, permitted_when_isolated_path);
|
||||
|
||||
if (result == nullptr) {
|
||||
__bionic_format_dlerror("android_create_namespace failed", linker_get_error_buffer());
|
||||
|
|
|
@ -94,6 +94,10 @@ struct android_namespace_t {
|
|||
default_library_paths_ = library_paths;
|
||||
}
|
||||
|
||||
void set_permitted_paths(std::vector<std::string>&& permitted_paths) {
|
||||
permitted_paths_ = permitted_paths;
|
||||
}
|
||||
|
||||
soinfo::soinfo_list_t& soinfo_list() { return soinfo_list_; }
|
||||
|
||||
// For isolated namespaces - checks if the file is on the search path;
|
||||
|
@ -105,6 +109,7 @@ struct android_namespace_t {
|
|||
bool is_isolated_;
|
||||
std::vector<std::string> ld_library_paths_;
|
||||
std::vector<std::string> default_library_paths_;
|
||||
std::vector<std::string> permitted_paths_;
|
||||
soinfo::soinfo_list_t soinfo_list_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(android_namespace_t);
|
||||
|
@ -316,6 +321,12 @@ bool android_namespace_t::is_accessible(const std::string& file) {
|
|||
}
|
||||
}
|
||||
|
||||
for (const auto& dir : permitted_paths_) {
|
||||
if (file_is_under_dir(file, dir)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2285,7 +2296,7 @@ bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_
|
|||
|
||||
// create anonymous namespace
|
||||
android_namespace_t* anon_ns =
|
||||
create_namespace("(anonymous)", nullptr, anon_ns_library_path, false);
|
||||
create_namespace("(anonymous)", nullptr, anon_ns_library_path, false, nullptr);
|
||||
|
||||
if (anon_ns == nullptr) {
|
||||
g_public_namespace_initialized = false;
|
||||
|
@ -2299,7 +2310,8 @@ bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_
|
|||
android_namespace_t* create_namespace(const char* name,
|
||||
const char* ld_library_path,
|
||||
const char* default_library_path,
|
||||
bool is_isolated) {
|
||||
bool is_isolated,
|
||||
const char* permitted_when_isolated_path) {
|
||||
if (!g_public_namespace_initialized) {
|
||||
DL_ERR("cannot create namespace: public namespace is not initialized.");
|
||||
return nullptr;
|
||||
|
@ -2308,15 +2320,18 @@ android_namespace_t* create_namespace(const char* name,
|
|||
ProtectedDataGuard guard;
|
||||
std::vector<std::string> ld_library_paths;
|
||||
std::vector<std::string> default_library_paths;
|
||||
std::vector<std::string> permitted_paths;
|
||||
|
||||
parse_path(ld_library_path, ":", &ld_library_paths);
|
||||
parse_path(default_library_path, ":", &default_library_paths);
|
||||
parse_path(permitted_when_isolated_path, ":", &permitted_paths);
|
||||
|
||||
android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
|
||||
ns->set_name(name);
|
||||
ns->set_isolated(is_isolated);
|
||||
ns->set_ld_library_paths(std::move(ld_library_paths));
|
||||
ns->set_default_library_paths(std::move(default_library_paths));
|
||||
ns->set_permitted_paths(std::move(permitted_paths));
|
||||
|
||||
// TODO(dimtiry): Should this be global group of caller's namespace?
|
||||
auto global_group = make_global_group(&g_default_namespace);
|
||||
|
|
|
@ -446,6 +446,7 @@ uint32_t get_application_target_sdk_version();
|
|||
|
||||
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);
|
||||
const char* default_library_path, bool is_isolated,
|
||||
const char* permitted_when_isolated_path);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -66,9 +66,18 @@ bool file_is_in_dir(const std::string& file, const std::string& dir) {
|
|||
const char* haystack = file.c_str();
|
||||
size_t needle_len = strlen(needle);
|
||||
|
||||
return (strncmp(haystack, needle, needle_len) == 0 &&
|
||||
haystack[needle_len] == '/' &&
|
||||
strchr(haystack + needle_len + 1, '/') == nullptr);
|
||||
return strncmp(haystack, needle, needle_len) == 0 &&
|
||||
haystack[needle_len] == '/' &&
|
||||
strchr(haystack + needle_len + 1, '/') == nullptr;
|
||||
}
|
||||
|
||||
bool file_is_under_dir(const std::string& file, const std::string& dir) {
|
||||
const char* needle = dir.c_str();
|
||||
const char* haystack = file.c_str();
|
||||
size_t needle_len = strlen(needle);
|
||||
|
||||
return strncmp(haystack, needle, needle_len) == 0 &&
|
||||
haystack[needle_len] == '/';
|
||||
}
|
||||
|
||||
const char* const kZipFileSeparator = "!/";
|
||||
|
|
|
@ -22,6 +22,7 @@ extern const char* const kZipFileSeparator;
|
|||
|
||||
bool normalize_path(const char* path, std::string* normalized_path);
|
||||
bool file_is_in_dir(const std::string& file, const std::string& dir);
|
||||
bool file_is_under_dir(const std::string& file, const std::string& dir);
|
||||
bool parse_zip_path(const char* input_path, std::string* zip_path, std::string* entry_path);
|
||||
|
||||
off64_t page_start(off64_t offset);
|
||||
|
|
|
@ -54,6 +54,18 @@ TEST(linker_utils, file_is_in_dir_smoke) {
|
|||
ASSERT_FALSE(file_is_in_dir("/file", "/"));
|
||||
}
|
||||
|
||||
TEST(linker_utils, file_is_under_dir_smoke) {
|
||||
ASSERT_TRUE(file_is_under_dir("/foo/bar/file", "/foo/bar"));
|
||||
ASSERT_TRUE(file_is_under_dir("/foo/bar/file", "/foo"));
|
||||
|
||||
ASSERT_FALSE(file_is_under_dir("/foo/bar/file", "/bar/foo"));
|
||||
|
||||
ASSERT_TRUE(file_is_under_dir("/file", ""));
|
||||
ASSERT_TRUE(file_is_under_dir("/foo/bar/file", ""));
|
||||
ASSERT_FALSE(file_is_under_dir("/file", "/"));
|
||||
ASSERT_FALSE(file_is_under_dir("/foo/bar/file", "/"));
|
||||
}
|
||||
|
||||
TEST(linker_utils, parse_zip_path_smoke) {
|
||||
std::string zip_path;
|
||||
std::string entry_path;
|
||||
|
|
|
@ -628,10 +628,10 @@ TEST(dlext, ns_smoke) {
|
|||
handle_public = dlopen((lib_path + "/public_namespace_libs/" + g_public_lib).c_str(), RTLD_NOW | RTLD_NOLOAD);
|
||||
ASSERT_TRUE(handle_public != nullptr) << dlerror();
|
||||
|
||||
android_namespace_t* ns1 = android_create_namespace("private", nullptr, (lib_path + "/private_namespace_libs").c_str(), false);
|
||||
android_namespace_t* ns1 = android_create_namespace("private", nullptr, (lib_path + "/private_namespace_libs").c_str(), false, nullptr);
|
||||
ASSERT_TRUE(ns1 != nullptr) << dlerror();
|
||||
|
||||
android_namespace_t* ns2 = android_create_namespace("private_isolated", nullptr, (lib_path + "/private_namespace_libs").c_str(), true);
|
||||
android_namespace_t* ns2 = android_create_namespace("private_isolated", nullptr, (lib_path + "/private_namespace_libs").c_str(), true, nullptr);
|
||||
ASSERT_TRUE(ns2 != nullptr) << dlerror();
|
||||
|
||||
// This should not have affect search path for default namespace:
|
||||
|
@ -732,13 +732,13 @@ TEST(dlext, ns_isolated) {
|
|||
|
||||
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);
|
||||
android_namespace_t* ns_not_isolated = android_create_namespace("private", nullptr, (lib_path + "/private_namespace_libs").c_str(), false, nullptr);
|
||||
ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror();
|
||||
|
||||
android_namespace_t* ns_isolated = android_create_namespace("private_isolated1", nullptr, (lib_path + "/private_namespace_libs").c_str(), true);
|
||||
android_namespace_t* ns_isolated = android_create_namespace("private_isolated1", nullptr, (lib_path + "/private_namespace_libs").c_str(), true, nullptr);
|
||||
ASSERT_TRUE(ns_isolated != nullptr) << dlerror();
|
||||
|
||||
android_namespace_t* ns_isolated2 = android_create_namespace("private_isolated2", (lib_path + "/private_namespace_libs").c_str(), nullptr, true);
|
||||
android_namespace_t* ns_isolated2 = android_create_namespace("private_isolated2", (lib_path + "/private_namespace_libs").c_str(), nullptr, true, lib_path.c_str());
|
||||
ASSERT_TRUE(ns_isolated2 != nullptr) << dlerror();
|
||||
|
||||
ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
|
||||
|
@ -772,14 +772,15 @@ TEST(dlext, ns_isolated) {
|
|||
|
||||
extinfo.library_namespace = ns_isolated2;
|
||||
|
||||
// this should work because isolation_path for private_isolated2 includes lib_path
|
||||
handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
|
||||
ASSERT_TRUE(handle2 == nullptr);
|
||||
ASSERT_STREQ("dlopen failed: library \"libnstest_private_external.so\" not found", dlerror());
|
||||
ASSERT_TRUE(handle2 != nullptr) << dlerror();
|
||||
dlclose(handle2);
|
||||
|
||||
// Check dlopen by absolute path
|
||||
handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
|
||||
ASSERT_TRUE(handle2 == nullptr);
|
||||
ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" is not accessible for the namespace \"private_isolated2\"", dlerror());
|
||||
ASSERT_TRUE(handle2 != nullptr) << dlerror();
|
||||
dlclose(handle2);
|
||||
|
||||
typedef const char* (*fn_t)();
|
||||
fn_t ns_get_local_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string"));
|
||||
|
@ -824,7 +825,7 @@ TEST(dlext, ns_anonymous) {
|
|||
android_namespace_t* ns = android_create_namespace(
|
||||
"private", nullptr,
|
||||
(lib_path + "/private_namespace_libs").c_str(),
|
||||
false);
|
||||
false, nullptr);
|
||||
|
||||
ASSERT_TRUE(ns != nullptr) << dlerror();
|
||||
|
||||
|
|
Loading…
Reference in a new issue