Skip to content

Commit

Permalink
Ignore symbols of imported libs' dependencies
Browse files Browse the repository at this point in the history
When a library is present in a namespace via the secondary_namespaces
list (i.e. the executable, LD_PRELOAD, DF_1_GLOBAL, or
android_create_namespace inheritance), then we want to search that
library's symbols, but not the symbols of its dependencies. Otherwise,
we want to search the dependencies to handle cross-NS dependency.

Bug: http://b/148569846
Test: bionic unit tests
Change-Id: If798d69de28ed5c0f1a155e4ff85c7e08934e531
  • Loading branch information
rprichard committed Feb 3, 2020
1 parent e503383 commit 22fa3dd
Show file tree
Hide file tree
Showing 10 changed files with 346 additions and 7 deletions.
29 changes: 23 additions & 6 deletions linker/linker_namespaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ bool android_namespace_t::is_accessible(const std::string& file) {
// Are symbols from this shared object accessible for symbol lookups in a library from this
// namespace?
bool android_namespace_t::is_accessible(soinfo* s) {
auto is_accessible_ftor = [this] (soinfo* si) {
auto is_accessible_ftor = [this] (soinfo* si, bool allow_secondary) {
// This is workaround for apps hacking into soinfo list.
// and inserting their own entries into it. (http://b/37191433)
if (!si->has_min_version(3)) {
Expand All @@ -84,20 +84,37 @@ bool android_namespace_t::is_accessible(soinfo* s) {
return true;
}

const android_namespace_list_t& secondary_namespaces = si->get_secondary_namespaces();
if (secondary_namespaces.find(this) != secondary_namespaces.end()) {
return true;
// When we're looking up symbols, we want to search libraries from the same namespace (whether
// the namespace membership is primary or secondary), but we also want to search the immediate
// dependencies of libraries in our namespace. (e.g. Supposing that libapp.so -> libandroid.so
// crosses a namespace boundary, we want to search libandroid.so but not any of libandroid.so's
// dependencies).
//
// Some libraries may be present in this namespace via the secondary namespace list:
// - the executable
// - LD_PRELOAD and DF_1_GLOBAL libraries
// - libraries inherited during dynamic namespace creation (e.g. because of
// RTLD_GLOBAL / DF_1_GLOBAL / ANDROID_NAMESPACE_TYPE_SHARED)
//
// When a library's membership is secondary, we want to search its symbols, but not the symbols
// of its dependencies. The executable may depend on internal system libraries which should not
// be searched.
if (allow_secondary) {
const android_namespace_list_t& secondary_namespaces = si->get_secondary_namespaces();
if (secondary_namespaces.find(this) != secondary_namespaces.end()) {
return true;
}
}

return false;
};

if (is_accessible_ftor(s)) {
if (is_accessible_ftor(s, true)) {
return true;
}

return !s->get_parents().visit([&](soinfo* si) {
return !is_accessible_ftor(si);
return !is_accessible_ftor(si, false);
});
}

Expand Down
5 changes: 5 additions & 0 deletions tests/Android.bp
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,11 @@ cc_defaults {
"libnstest_ns_a_public1_internal",
"libnstest_ns_b_public2",
"libnstest_ns_b_public3",
"ns_hidden_child_helper",
"libns_hidden_child_global",
"libns_hidden_child_internal",
"libns_hidden_child_public",
"libns_hidden_child_app",
"libsegment_gap_inner",
"libsegment_gap_outer",
"ld_preload_test_helper",
Expand Down
32 changes: 32 additions & 0 deletions tests/core_shared_libs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (C) 2020 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

#pragma once

// A new namespace should have these libraries on a link to the default namespace.
static constexpr const char* kCoreSharedLibs = "libc.so:libc++.so:libdl.so:libm.so";
20 changes: 19 additions & 1 deletion tests/dlext_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include <procinfo/process_map.h>
#include <ziparchive/zip_archive.h>

#include "core_shared_libs.h"
#include "gtest_globals.h"
#include "utils.h"
#include "dlext_private.h"
Expand Down Expand Up @@ -713,7 +714,7 @@ std::string DlExtRelroSharingTest::FindMappingName(void* ptr) {
static const char* g_public_lib = "libnstest_public.so";

// These are libs shared with default namespace
static const std::string g_core_shared_libs = "libc.so:libc++.so:libdl.so:libm.so";
static const std::string g_core_shared_libs = kCoreSharedLibs;

TEST(dlext, ns_smoke) {
static const char* root_lib = "libnstest_root.so";
Expand Down Expand Up @@ -2055,6 +2056,23 @@ TEST(dlext, ns_anonymous) {
ASSERT_TRUE(ns_get_dlopened_string_anon() != ns_get_dlopened_string_private());
}

TEST(dlext, ns_hidden_child) {
ExecTestHelper eth;

std::string helper = GetTestlibRoot() + "/ns_hidden_child_helper/ns_hidden_child_helper";
chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607
std::string app_ns_dir = GetTestlibRoot() + "/ns_hidden_child_app";
eth.SetArgs({ helper.c_str(), app_ns_dir.c_str(), nullptr });

// Add the main libns_hidden_child_*.so libraries to the search path of the default namespace.
std::string env = "LD_LIBRARY_PATH=" + GetTestlibRoot();
eth.SetEnv({ env.c_str(), nullptr });

eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0,
"public_function is non-null\n"
"internal_function is null\n");
}

TEST(dlext, dlopen_handle_value_platform) {
void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_NOW | RTLD_LOCAL);
ASSERT_TRUE((reinterpret_cast<uintptr_t>(handle) & 1) != 0)
Expand Down
50 changes: 50 additions & 0 deletions tests/libs/Android.bp
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,56 @@ cc_test_library {
relative_install_path: "bionic-loader-test-libs/private_namespace_libs_external",
}

// -----------------------------------------------------------------------------
// ns_hidden_child linker namespace test
// -----------------------------------------------------------------------------

cc_test {
name: "ns_hidden_child_helper",
host_supported: false,
defaults: ["bionic_testlib_defaults"],
srcs: ["ns_hidden_child_helper.cpp"],
shared_libs: [
"libns_hidden_child_internal",
"libns_hidden_child_global",
"libdl_android",
],
ldflags: ["-Wl,--rpath,${ORIGIN}/.."],
}

cc_test_library {
name: "libns_hidden_child_global",
defaults: ["bionic_testlib_defaults"],
host_supported: false,
srcs: ["ns_hidden_child_global.cpp"],
shared_libs: ["libns_hidden_child_internal"],
ldflags: ["-Wl,-z,global"],
}

cc_test_library {
name: "libns_hidden_child_internal",
defaults: ["bionic_testlib_defaults"],
host_supported: false,
srcs: ["ns_hidden_child_internal.cpp"],
}

cc_test_library {
name: "libns_hidden_child_public",
defaults: ["bionic_testlib_defaults"],
host_supported: false,
srcs: ["ns_hidden_child_public.cpp"],
shared_libs: ["libns_hidden_child_internal"],
}

cc_test_library {
name: "libns_hidden_child_app",
defaults: ["bionic_testlib_defaults"],
host_supported: false,
srcs: ["ns_hidden_child_app.cpp"],
shared_libs: ["libns_hidden_child_public"],
relative_install_path: "bionic-loader-test-libs/ns_hidden_child_app",
}

// -----------------------------------------------------------------------------
// Build DT_RUNPATH test helper libraries
//
Expand Down
37 changes: 37 additions & 0 deletions tests/libs/ns_hidden_child_app.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (C) 2020 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

#include <stdio.h>

__attribute__((weak)) extern "C" void public_function();
__attribute__((weak)) extern "C" void internal_function();

extern "C" void app_function() {
printf("public_function is %s\n", public_function == nullptr ? "null" : "non-null");
printf("internal_function is %s\n", internal_function == nullptr ? "null" : "non-null");
}
33 changes: 33 additions & 0 deletions tests/libs/ns_hidden_child_global.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2020 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

extern "C" void internal_function();

extern "C" void global_function() {
internal_function();
}
85 changes: 85 additions & 0 deletions tests/libs/ns_hidden_child_helper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright (C) 2020 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

#include <android/dlext.h>
#include <dlfcn.h>
#include <stdlib.h>

#include <string>

#include "../core_shared_libs.h"
#include "../dlext_private.h"

extern "C" void global_function();
extern "C" void internal_function();

int main(int argc, char* argv[]) {
if (argc != 2) {
fprintf(stderr, "usage: %s NS_PATH\n", argv[0]);
fprintf(stderr, "NS_PATH path to the ns_hidden_child_app directory\n");
exit(1);
}

// Ensure that -Wl,--needed doesn't break the test by removing DT_NEEDED entries.
global_function();
internal_function();

const char* app_lib_dir = argv[1];
android_namespace_t* app_ns =
android_create_namespace("app", nullptr, app_lib_dir, ANDROID_NAMESPACE_TYPE_ISOLATED,
nullptr, nullptr);
if (app_ns == nullptr) {
fprintf(stderr, "android_create_namespace failed: %s\n", dlerror());
exit(1);
}

std::string public_libs = std::string(kCoreSharedLibs) + ":libns_hidden_child_public.so";
if (!android_link_namespaces(app_ns, nullptr, public_libs.c_str())) {
fprintf(stderr, "android_link_namespaces failed: %s\n", dlerror());
exit(1);
}

android_dlextinfo ext = {
.flags = ANDROID_DLEXT_USE_NAMESPACE,
.library_namespace = app_ns,
};
void* app_lib = android_dlopen_ext("libns_hidden_child_app.so", RTLD_NOW | RTLD_LOCAL, &ext);
if (app_lib == nullptr) {
fprintf(stderr, "android_dlopen_ext failed: %s\n", dlerror());
exit(1);
}

auto app_function = reinterpret_cast<void(*)()>(dlsym(app_lib, "app_function"));
if (app_function == nullptr) {
fprintf(stderr, "dlsym failed to find app_function: %s\n", dlerror());
exit(1);
}

app_function();
return 0;
}
29 changes: 29 additions & 0 deletions tests/libs/ns_hidden_child_internal.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2020 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

extern "C" void internal_function() {}
Loading

0 comments on commit 22fa3dd

Please sign in to comment.