aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2017-11-28 23:33:01 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2017-11-28 23:33:01 +0000
commit52213f17440221f0d5806cb8cd970fd3db704a2c (patch)
treed9e4a3e7a14293d7397d1f5d9690703d55f195f4
parent17929be412cfb0d8c85c110cb2dd9f06c9c6feab (diff)
parentfcabaf45b7a17a2b67b3a7cc019da4b396966bce (diff)
downloadbionic-52213f17440221f0d5806cb8cd970fd3db704a2c.tar.gz
Change-Id: I70fc2f7889874c3ce6260976373ff82d00ec6c68
-rw-r--r--libc/Android.bp6
-rw-r--r--libc/async_safe/async_safe_log.cpp15
-rw-r--r--libc/bionic/__bionic_get_shell_path.cpp20
-rw-r--r--libc/bionic/__libc_init_main_thread.cpp2
-rw-r--r--libc/bionic/pthread_create.cpp22
-rw-r--r--libc/bionic/pthread_internal.cpp10
-rw-r--r--libc/bionic/pthread_internal.h2
-rw-r--r--libdl/libdl_cfi.cpp5
-rw-r--r--linker/linker_config.cpp28
-rw-r--r--tests/Android.bp12
-rw-r--r--tests/cfi_test.cpp17
-rw-r--r--tests/dl_test.cpp23
-rw-r--r--tests/libs/cfi_test_lib.cpp7
-rwxr-xr-xtests/pthread_test.cpp46
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));
+ }
+}