diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2017-11-28 23:33:01 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2017-11-28 23:33:01 +0000 |
commit | 52213f17440221f0d5806cb8cd970fd3db704a2c (patch) | |
tree | d9e4a3e7a14293d7397d1f5d9690703d55f195f4 | |
parent | 17929be412cfb0d8c85c110cb2dd9f06c9c6feab (diff) | |
parent | fcabaf45b7a17a2b67b3a7cc019da4b396966bce (diff) | |
download | bionic-52213f17440221f0d5806cb8cd970fd3db704a2c.tar.gz |
Snap for 4448085 from fcabaf45b7a17a2b67b3a7cc019da4b396966bce to oc-m3-releaseandroid-8.1.0_r9android-8.1.0_r7android-8.1.0_r22android-8.1.0_r21android-8.1.0_r18android-8.1.0_r17android-8.1.0_r14android-8.1.0_r13oreo-m5-releaseoreo-m3-release
Change-Id: I70fc2f7889874c3ce6260976373ff82d00ec6c68
-rw-r--r-- | libc/Android.bp | 6 | ||||
-rw-r--r-- | libc/async_safe/async_safe_log.cpp | 15 | ||||
-rw-r--r-- | libc/bionic/__bionic_get_shell_path.cpp | 20 | ||||
-rw-r--r-- | libc/bionic/__libc_init_main_thread.cpp | 2 | ||||
-rw-r--r-- | libc/bionic/pthread_create.cpp | 22 | ||||
-rw-r--r-- | libc/bionic/pthread_internal.cpp | 10 | ||||
-rw-r--r-- | libc/bionic/pthread_internal.h | 2 | ||||
-rw-r--r-- | libdl/libdl_cfi.cpp | 5 | ||||
-rw-r--r-- | linker/linker_config.cpp | 28 | ||||
-rw-r--r-- | tests/Android.bp | 12 | ||||
-rw-r--r-- | tests/cfi_test.cpp | 17 | ||||
-rw-r--r-- | tests/dl_test.cpp | 23 | ||||
-rw-r--r-- | tests/libs/cfi_test_lib.cpp | 7 | ||||
-rwxr-xr-x | tests/pthread_test.cpp | 46 |
14 files changed, 154 insertions, 61 deletions
diff --git a/libc/Android.bp b/libc/Android.bp index b5229cbbf..a0d1f237c 100644 --- a/libc/Android.bp +++ b/libc/Android.bp @@ -1509,7 +1509,11 @@ cc_library_static { srcs: ["bionic/mmap.cpp"], }, }, - + product_variables: { + treble: { + cflags: ["-D__ANDROID_TREBLE__"], + }, + }, cppflags: ["-Wold-style-cast"], local_include_dirs: ["stdio"], include_dirs: ["bionic/libstdc++/include"], diff --git a/libc/async_safe/async_safe_log.cpp b/libc/async_safe/async_safe_log.cpp index 99ff0c7f9..bc2a7999a 100644 --- a/libc/async_safe/async_safe_log.cpp +++ b/libc/async_safe/async_safe_log.cpp @@ -477,19 +477,6 @@ static int open_log_socket() { return log_fd; } -static clockid_t log_clockid() { - static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - ScopedPthreadMutexLocker locker(&mutex); - - static CachedProperty ro_logd_timestamp("ro.logd.timestamp"); - static CachedProperty persist_logd_timestamp("persist.logd.timestamp"); - - char ch = persist_logd_timestamp.Get()[0]; - if (ch == '\0') ch = ro_logd_timestamp.Get()[0]; - - return (tolower(ch) == 'm') ? CLOCK_MONOTONIC : CLOCK_REALTIME; -} - struct log_time { // Wire format uint32_t tv_sec; uint32_t tv_nsec; @@ -510,7 +497,7 @@ int async_safe_write_log(int priority, const char* tag, const char* msg) { vec[1].iov_base = &tid; vec[1].iov_len = sizeof(tid); timespec ts; - clock_gettime(log_clockid(), &ts); + clock_gettime(CLOCK_REALTIME, &ts); log_time realtime_ts; realtime_ts.tv_sec = ts.tv_sec; realtime_ts.tv_nsec = ts.tv_nsec; diff --git a/libc/bionic/__bionic_get_shell_path.cpp b/libc/bionic/__bionic_get_shell_path.cpp index 477fa4a1b..41162e93e 100644 --- a/libc/bionic/__bionic_get_shell_path.cpp +++ b/libc/bionic/__bionic_get_shell_path.cpp @@ -31,18 +31,24 @@ #include <sys/cdefs.h> #include <unistd.h> -__LIBC_HIDDEN__ static const char* __libc_system_sh = "/system/bin/sh"; -__LIBC_HIDDEN__ static const char* __libc_vendor_sh = "/vendor/bin/sh"; +#define VENDOR_PREFIX "/vendor/" static const char* init_sh_path() { + /* If the device is not treble enabled, return the path to the system shell. + * Vendor code, on non-treble enabled devices could use system() / popen() + * with relative paths for executables on /system. Since /system will not be + * in $PATH for the vendor shell, simply return the system shell. + */ + +#ifdef __ANDROID_TREBLE__ /* look for /system or /vendor prefix */ - char exe_path[7]; + char exe_path[strlen(VENDOR_PREFIX)]; ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path)); - if (len != -1 && !strncmp(exe_path, __libc_vendor_sh, sizeof(exe_path))) { - return __libc_vendor_sh; + if (len != -1 && !strncmp(exe_path, VENDOR_PREFIX, strlen(VENDOR_PREFIX))) { + return "/vendor/bin/sh"; } - - return __libc_system_sh; +#endif + return "/system/bin/sh"; } __LIBC_HIDDEN__ extern "C" const char* __bionic_get_shell_path() { diff --git a/libc/bionic/__libc_init_main_thread.cpp b/libc/bionic/__libc_init_main_thread.cpp index f3dbfa537..9cbff11af 100644 --- a/libc/bionic/__libc_init_main_thread.cpp +++ b/libc/bionic/__libc_init_main_thread.cpp @@ -70,7 +70,7 @@ void __libc_init_main_thread(KernelArgumentBlock& args) { // set up before we call any function that might get a stack check inserted. // TLS also needs to be set up before errno (and therefore syscalls) can be used. __set_tls(main_thread.tls); - __init_tls(&main_thread); + if (!__init_tls(&main_thread)) async_safe_fatal("failed to initialize TLS: %s", strerror(errno)); // Tell the kernel to clear our tid field when we exit, so we're like any other pthread. // As a side-effect, this tells us our pid (which is the same as the main thread's tid). diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp index 9197aa3fe..7a266501d 100644 --- a/libc/bionic/pthread_create.cpp +++ b/libc/bionic/pthread_create.cpp @@ -50,7 +50,7 @@ void __init_user_desc(struct user_desc*, bool, void*); #endif // This code is used both by each new pthread and the code that initializes the main thread. -void __init_tls(pthread_internal_t* thread) { +bool __init_tls(pthread_internal_t* thread) { // Slot 0 must point to itself. The x86 Linux kernel reads the TLS from %fs:0. thread->tls[TLS_SLOT_SELF] = thread->tls; thread->tls[TLS_SLOT_THREAD_ID] = thread; @@ -59,15 +59,24 @@ void __init_tls(pthread_internal_t* thread) { size_t allocation_size = BIONIC_TLS_SIZE + 2 * PAGE_SIZE; void* allocation = mmap(nullptr, allocation_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (allocation == MAP_FAILED) { - async_safe_fatal("failed to allocate TLS"); + async_safe_format_log(ANDROID_LOG_WARN, "libc", + "pthread_create failed: couldn't allocate TLS: %s", strerror(errno)); + return false; } - prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, allocation, allocation_size, "bionic TLS guard page"); + prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, allocation, allocation_size, "bionic TLS guard"); + + // Carve out the writable TLS section. thread->bionic_tls = reinterpret_cast<bionic_tls*>(static_cast<char*>(allocation) + PAGE_SIZE); if (mprotect(thread->bionic_tls, BIONIC_TLS_SIZE, PROT_READ | PROT_WRITE) != 0) { - async_safe_fatal("failed to mprotect TLS"); + async_safe_format_log(ANDROID_LOG_WARN, "libc", + "pthread_create failed: couldn't mprotect TLS: %s", strerror(errno)); + munmap(allocation, allocation_size); + return false; } + prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, thread->bionic_tls, BIONIC_TLS_SIZE, "bionic TLS"); + return true; } void __init_thread_stack_guard(pthread_internal_t* thread) { @@ -192,7 +201,10 @@ static int __allocate_thread(pthread_attr_t* attr, pthread_internal_t** threadp, thread->mmap_size = mmap_size; thread->attr = *attr; - __init_tls(thread); + if (!__init_tls(thread)) { + if (thread->mmap_size != 0) munmap(thread->attr.stack_base, thread->mmap_size); + return EAGAIN; + } __init_thread_stack_guard(thread); *threadp = thread; diff --git a/libc/bionic/pthread_internal.cpp b/libc/bionic/pthread_internal.cpp index abd403bd4..829194cc7 100644 --- a/libc/bionic/pthread_internal.cpp +++ b/libc/bionic/pthread_internal.cpp @@ -104,9 +104,13 @@ pthread_internal_t* __pthread_internal_find(pthread_t thread_id) { // Check if we're looking for ourselves before acquiring the lock. if (thread == __get_thread()) return thread; - ScopedReadLock locker(&g_thread_list_lock); - for (pthread_internal_t* t = g_thread_list; t != nullptr; t = t->next) { - if (t == thread) return thread; + { + // Make sure to release the lock before the abort below. Otherwise, + // some apps might deadlock in their own crash handlers (see b/6565627). + ScopedReadLock locker(&g_thread_list_lock); + for (pthread_internal_t* t = g_thread_list; t != nullptr; t = t->next) { + if (t == thread) return thread; + } } // Historically we'd return null, but diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h index 6faf5a4ff..4ba6ee059 100644 --- a/libc/bionic/pthread_internal.h +++ b/libc/bionic/pthread_internal.h @@ -115,7 +115,7 @@ class pthread_internal_t { }; __LIBC_HIDDEN__ int __init_thread(pthread_internal_t* thread); -__LIBC_HIDDEN__ void __init_tls(pthread_internal_t* thread); +__LIBC_HIDDEN__ bool __init_tls(pthread_internal_t* thread); __LIBC_HIDDEN__ void __init_thread_stack_guard(pthread_internal_t* thread); __LIBC_HIDDEN__ void __init_alternate_signal_stack(pthread_internal_t*); diff --git a/libdl/libdl_cfi.cpp b/libdl/libdl_cfi.cpp index 483364fcf..1dd5b21cd 100644 --- a/libdl/libdl_cfi.cpp +++ b/libdl/libdl_cfi.cpp @@ -52,7 +52,10 @@ static uint16_t shadow_load(void* p) { static uintptr_t cfi_check_addr(uint16_t v, void* Ptr) { uintptr_t addr = reinterpret_cast<uintptr_t>(Ptr); - uintptr_t aligned_addr = align_up(addr, CFIShadow::kShadowAlign); + // The aligned range of [0, kShadowAlign) uses a single shadow element, therefore all pointers in + // this range must get the same aligned_addr below. This matches CFIShadowWriter::Add; not the + // same as align_up(). + uintptr_t aligned_addr = align_down(addr, CFIShadow::kShadowAlign) + CFIShadow::kShadowAlign; uintptr_t p = aligned_addr - (static_cast<uintptr_t>(v - CFIShadow::kRegularShadowMin) << CFIShadow::kCfiCheckGranularity); #ifdef __arm__ diff --git a/linker/linker_config.cpp b/linker/linker_config.cpp index 0a9aeab2a..e036c05d9 100644 --- a/linker/linker_config.cpp +++ b/linker/linker_config.cpp @@ -320,7 +320,7 @@ class Properties { return (it == properties_.end()) ? "" : it->second.value(); } - std::vector<std::string> get_paths(const std::string& name, size_t* lineno = nullptr) { + std::vector<std::string> get_paths(const std::string& name, bool resolve, size_t* lineno = nullptr) { std::string paths_str = get_string(name, lineno); std::vector<std::string> paths; @@ -338,12 +338,16 @@ class Properties { format_string(&path, params); } - std::vector<std::string> resolved_paths; + if (resolve) { + std::vector<std::string> resolved_paths; - // do not remove paths that do not exist - resolve_paths(paths, &resolved_paths); + // do not remove paths that do not exist + resolve_paths(paths, &resolved_paths); - return resolved_paths; + return resolved_paths; + } else { + return paths; + } } void set_target_sdk_version(int target_sdk_version) { @@ -465,8 +469,18 @@ bool Config::read_binary_config(const char* ld_config_file_path, property_name_prefix += ".asan"; } - ns_config->set_search_paths(properties.get_paths(property_name_prefix + ".search.paths")); - ns_config->set_permitted_paths(properties.get_paths(property_name_prefix + ".permitted.paths")); + // search paths are resolved (canonicalized). This is required mainly for + // the case when /vendor is a symlink to /system/vendor, which is true for + // non Treble-ized legacy devices. + ns_config->set_search_paths(properties.get_paths(property_name_prefix + ".search.paths", true)); + + // However, for permitted paths, we are not required to resolve the paths + // since they are only set for isolated namespaces, which implies the device + // is Treble-ized (= /vendor is not a symlink to /system/vendor). + // In fact, the resolving is causing an unexpected side effect of selinux + // denials on some executables which are not allowed to access some of the + // permitted paths. + ns_config->set_permitted_paths(properties.get_paths(property_name_prefix + ".permitted.paths", false)); } failure_guard.Disable(); diff --git a/tests/Android.bp b/tests/Android.bp index e8fa5bdf9..29204b558 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -299,12 +299,6 @@ cc_test_library { ], } }, - - product_variables: { - debuggable: { - cppflags: ["-DUSE_LD_CONFIG_FILE"], - }, - }, } // ----------------------------------------------------------------------------- @@ -605,12 +599,6 @@ cc_test_host { sanitize: { never: false, }, - - product_variables: { - debuggable: { - cppflags: ["-DUSE_LD_CONFIG_FILE"], - }, - }, } subdirs = ["libs"] diff --git a/tests/cfi_test.cpp b/tests/cfi_test.cpp index 088dda603..5e2518f07 100644 --- a/tests/cfi_test.cpp +++ b/tests/cfi_test.cpp @@ -22,6 +22,10 @@ #include "gtest_globals.h" #include "utils.h" +#if defined(__BIONIC__) +#include "private/CFIShadow.h" +#endif + // Private libdl interface. extern "C" { void __cfi_slowpath(uint64_t CallSiteTypeId, void* Ptr); @@ -40,15 +44,16 @@ TEST(cfi_test, basic) { EXPECT_NE(0U, __cfi_shadow_size()); #define SYM(type, name) auto name = reinterpret_cast<type>(dlsym(handle, #name)) - SYM(int (*)(), get_count); + SYM(size_t (*)(), get_count); SYM(uint64_t(*)(), get_last_type_id); SYM(void* (*)(), get_last_address); SYM(void* (*)(), get_last_diag); SYM(void* (*)(), get_global_address); SYM(void (*)(uint64_t, void*, void*), __cfi_check); + SYM(char*, bss); #undef SYM - int c = get_count(); + size_t c = get_count(); // CFI check for code inside the DSO. Can't use just any function address - this is only // guaranteed to work for code addresses above __cfi_check. @@ -88,6 +93,14 @@ TEST(cfi_test, basic) { EXPECT_DEATH(__cfi_slowpath(46, p), ""); free(p); + // Check all the addresses. + const size_t bss_size = 1024 * 1024; + static_assert(bss_size >= kLibraryAlignment * 2, "test range not big enough"); + for (size_t i = 0; i < bss_size; ++i) { + __cfi_slowpath(47, bss + i); + EXPECT_EQ(++c, get_count()); + } + // Load the same library again. void* handle2 = dlopen("libcfi-test.so", RTLD_NOW | RTLD_LOCAL); ASSERT_TRUE(handle2 != nullptr) << dlerror(); diff --git a/tests/dl_test.cpp b/tests/dl_test.cpp index aaf2c3742..d09330dbc 100644 --- a/tests/dl_test.cpp +++ b/tests/dl_test.cpp @@ -180,12 +180,24 @@ static void create_ld_config_file(std::string& config_file) { } #endif -#ifdef USE_LD_CONFIG_FILE +#if defined(__BIONIC__) +static bool is_user_build() { + std::string build_type = android::base::GetProperty("ro.build.type", "user"); + if (build_type == "userdebug" || build_type == "eng") { + return false; + } + return true; +} +#endif // _lib1.so and _lib2.so are now searchable by having another namespace 'ns2' // whose search paths include the 'ns2/' subdir. TEST(dl, exec_with_ld_config_file) { #if defined(__BIONIC__) + if (is_user_build()) { + // LD_CONFIG_FILE is not supported on user build + return; + } std::string helper = get_testlib_root() + "/ld_config_test_helper/ld_config_test_helper"; std::string config_file = get_testlib_root() + "/ld.config.txt"; @@ -204,6 +216,10 @@ TEST(dl, exec_with_ld_config_file) { // additional namespaces other than the default namespace. TEST(dl, exec_with_ld_config_file_with_ld_preload) { #if defined(__BIONIC__) + if (is_user_build()) { + // LD_CONFIG_FILE is not supported on user build + return; + } std::string helper = get_testlib_root() + "/ld_config_test_helper/ld_config_test_helper"; std::string config_file = get_testlib_root() + "/ld.config.txt"; @@ -218,8 +234,6 @@ TEST(dl, exec_with_ld_config_file_with_ld_preload) { #endif } -#endif // USE_LD_CONFIG_FILE - // ensures that LD_CONFIG_FILE env var does not work for production builds. // The test input is the same as exec_with_ld_config_file, but it must fail in // this case. @@ -230,8 +244,7 @@ TEST(dl, disable_ld_config_file) { // This test is only for CTS. return; } - std::string build_type = android::base::GetProperty("ro.build.type", "user"); - if (build_type == "userdebug" || build_type == "eng") { + if (!is_user_build()) { // Skip the test for non production devices return; } diff --git a/tests/libs/cfi_test_lib.cpp b/tests/libs/cfi_test_lib.cpp index 959b1020f..9f456d39b 100644 --- a/tests/libs/cfi_test_lib.cpp +++ b/tests/libs/cfi_test_lib.cpp @@ -22,13 +22,16 @@ // present. But it is only used in the bionic loader tests. extern "C" __attribute__((weak)) void __cfi_slowpath(uint64_t, void*); -static int g_count; +static size_t g_count; static uint64_t g_last_type_id; static void* g_last_address; static void* g_last_diag; extern "C" { +// Make sure the library crosses at least one kLibraryAlignment(=256KB) boundary. +char bss[1024 * 1024]; + // Mock a CFI-enabled library without relying on the compiler. __attribute__((aligned(4096))) void __cfi_check(uint64_t CallSiteTypeId, void* TargetAddr, void* Diag) { @@ -38,7 +41,7 @@ __attribute__((aligned(4096))) void __cfi_check(uint64_t CallSiteTypeId, void* T g_last_diag = Diag; } -int get_count() { +size_t get_count() { return g_count; } diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp index d64bc48bc..bf6ed9a56 100755 --- a/tests/pthread_test.cpp +++ b/tests/pthread_test.cpp @@ -2076,3 +2076,49 @@ TEST(pthread, pthread_spinlock_smoke) { ASSERT_EQ(0, pthread_spin_unlock(&lock)); ASSERT_EQ(0, pthread_spin_destroy(&lock)); } + +TEST(pthread, pthread_attr_setdetachstate) { + pthread_attr_t attr; + ASSERT_EQ(0, pthread_attr_init(&attr)); + + ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)); + ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)); + ASSERT_EQ(EINVAL, pthread_attr_setdetachstate(&attr, 123)); +} + +TEST(pthread, pthread_create__mmap_failures) { + pthread_attr_t attr; + ASSERT_EQ(0, pthread_attr_init(&attr)); + ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)); + + const auto kPageSize = sysconf(_SC_PAGE_SIZE); + + // Use up all the VMAs. By default this is 64Ki. + std::vector<void*> pages; + int prot = PROT_NONE; + while (true) { + void* page = mmap(nullptr, kPageSize, prot, MAP_ANON|MAP_PRIVATE, -1, 0); + if (page == MAP_FAILED) break; + pages.push_back(page); + prot = (prot == PROT_NONE) ? PROT_READ : PROT_NONE; + } + + // Try creating threads, freeing up a page each time we fail. + size_t EAGAIN_count = 0; + size_t i = 0; + for (; i < pages.size(); ++i) { + pthread_t t; + int status = pthread_create(&t, &attr, IdFn, nullptr); + if (status != EAGAIN) break; + ++EAGAIN_count; + ASSERT_EQ(0, munmap(pages[i], kPageSize)); + } + + // Creating a thread uses at least six VMAs: the stack, the TLS, and a guard each side of both. + // So we should have seen at least six failures. + ASSERT_GE(EAGAIN_count, 6U); + + for (; i < pages.size(); ++i) { + ASSERT_EQ(0, munmap(pages[i], kPageSize)); + } +} |