diff options
65 files changed, 761 insertions, 473 deletions
diff --git a/benchmarks/linker_relocation/include/linker_reloc_bench_asm.h b/benchmarks/linker_relocation/include/linker_reloc_bench_asm.h index 885e47fb4..ea63e36ef 100644 --- a/benchmarks/linker_relocation/include/linker_reloc_bench_asm.h +++ b/benchmarks/linker_relocation/include/linker_reloc_bench_asm.h @@ -44,9 +44,7 @@ #elif defined(__riscv) -// No `lga` in clang unless https://reviews.llvm.org/D107278 lands. -// `la` is equivalent when using PIC (which we do) though. -#define GOT_RELOC(sym) la a0, sym +#define GOT_RELOC(sym) lga a0, sym #define CALL(sym) call sym@plt #define DATA_WORD(val) .quad val #define MAIN .globl main; main: li a0, 0; ret diff --git a/benchmarks/util.h b/benchmarks/util.h index 99eed5f0a..347dc3571 100644 --- a/benchmarks/util.h +++ b/benchmarks/util.h @@ -71,7 +71,7 @@ char* GetAlignedPtrFilled(std::vector<char>* buf, size_t alignment, size_t nbyte bool LockToCPU(int cpu_to_lock); -static __inline __attribute__ ((__always_inline__)) void MakeAllocationResident( +static inline __attribute__((__always_inline__)) void MakeAllocationResident( void* ptr, size_t nbytes, int pagesize) { uint8_t* data = reinterpret_cast<uint8_t*>(ptr); for (size_t i = 0; i < nbytes; i += pagesize) { diff --git a/docs/status.md b/docs/status.md index 2919471e8..bc8ab6a4f 100644 --- a/docs/status.md +++ b/docs/status.md @@ -397,22 +397,25 @@ automatic bounds checking for common libc functions. If a buffer overrun is detected, the program is safely aborted as in this [example](https://source.android.com/devices/tech/debug/native-crash#fortify). -Note that in recent releases Android's FORTIFY has been extended to -cover other issues. It can now detect, for example, passing `O_CREAT` -to open(2) without specifying a mode. It also performs some checking -regardless of whether the caller was built with FORTIFY enabled. In P, -for example, calling a `pthread_mutex_` function on a destroyed mutex, -calling a `<dirent.h>` function on a null pointer, using `%n` with the -printf(3) family, or using the scanf(3) `m` modifier incorrectly will -all result in FORTIFY failures even for code not built with FORTIFY. +Note that Android's FORTIFY has been extended to cover other issues. It can +detect, for example, passing `O_CREAT` to open(2) without specifying a mode. It +also performs some checking regardless of whether the caller was built with +FORTIFY enabled. From API level 28, for example, calling a `pthread_mutex_` +function on a destroyed mutex, calling a `<dirent.h>` function on a null +pointer, using `%n` with the printf(3) family, or using the scanf(3) `m` +modifier incorrectly will all result in FORTIFY failures even for code not built +with FORTIFY. More background information is available in our [FORTIFY in Android](https://android-developers.googleblog.com/2017/04/fortify-in-android.html) -blog post. - -The Android platform is built with `-D_FORTIFY_SOURCE=2`, but NDK users -need to manually enable FORTIFY by setting that themselves in whatever -build system they're using. The exact subset of FORTIFY available to +blog post, and there's more detail about the implementation in +[The Anatomy of Clang FORTIFY](clang_fortify_anatomy.md). + +The Android platform is built with `-D_FORTIFY_SOURCE=2`. Users of ndk-build +or the NDK's CMake toolchain file also get this by default with NDK r21 or +newer. Users of other build systems +need to manually enable FORTIFY by setting `_FORTIFY_SOURCE` themselves in +whatever build system they're using. The exact subset of FORTIFY available to NDK users will depend on their target ABI level, because when a FORTIFY check can't be guaranteed at compile-time, a call to a run-time `_chk` function is added. diff --git a/libc/Android.bp b/libc/Android.bp index 84fa498d3..2efca6855 100644 --- a/libc/Android.bp +++ b/libc/Android.bp @@ -55,7 +55,9 @@ libc_common_flags = [ cc_defaults { name: "libc_defaults", defaults: ["linux_bionic_supported"], - cflags: libc_common_flags, + cflags: libc_common_flags + [ + "-DUSE_SCUDO", + ], asflags: libc_common_flags, conlyflags: ["-std=gnu99"], cppflags: [], @@ -98,8 +100,8 @@ cc_defaults { malloc_pattern_fill_contents: { cflags: ["-DSCUDO_PATTERN_FILL_CONTENTS"], }, - malloc_not_svelte: { - cflags: ["-DUSE_SCUDO"], + malloc_low_memory: { + cflags: ["-UUSE_SCUDO"], }, }, @@ -112,32 +114,31 @@ cc_defaults { tidy_disabled_srcs: ["upstream-*/**/*.c"], } -libc_scudo_product_variables = { - malloc_not_svelte: { - cflags: ["-DUSE_SCUDO"], - whole_static_libs: ["libscudo"], - exclude_static_libs: [ - "libjemalloc5", - "libc_jemalloc_wrapper", - ], - }, -} - // Defaults for native allocator libs/includes to make it // easier to change. -// To disable scudo for the non-svelte config remove the line: -// product_variables: libc_scudo_product_variables, -// in the cc_defaults below. // ======================================================== cc_defaults { name: "libc_native_allocator_defaults", whole_static_libs: [ - "libjemalloc5", - "libc_jemalloc_wrapper", + "libscudo", + ], + cflags: [ + "-DUSE_SCUDO", ], header_libs: ["gwp_asan_headers"], - product_variables: libc_scudo_product_variables, + product_variables: { + malloc_low_memory: { + cflags: ["-UUSE_SCUDO"], + whole_static_libs: [ + "libjemalloc5", + "libc_jemalloc_wrapper", + ], + exclude_static_libs: [ + "libscudo", + ], + }, + }, } // Functions not implemented by jemalloc directly, or that need to @@ -2990,3 +2991,8 @@ filegroup { name: "versioner-dependencies", srcs: ["versioner-dependencies/**/*"], } + +filegroup { + name: "linux_capability_header", + srcs: ["kernel/uapi/linux/capability.h"], +} diff --git a/libc/bionic/execinfo.cpp b/libc/bionic/execinfo.cpp index d129f7cae..e53a0377c 100644 --- a/libc/bionic/execinfo.cpp +++ b/libc/bionic/execinfo.cpp @@ -73,6 +73,11 @@ static _Unwind_Reason_Code TraceFunction(_Unwind_Context* context, void* arg) { #elif defined(__aarch64__) // All instructions are 4 bytes long, skip back one instruction. ip -= 4; +#elif defined(__riscv) + // C instructions are the shortest at 2 bytes long. (Unlike thumb, it's + // non-trivial to recognize C instructions when going backwards in the + // instruction stream.) + ip -= 2; #elif defined(__i386__) || defined(__x86_64__) // It's difficult to decode exactly where the previous instruction is, // so subtract 1 to estimate where the instruction lives. diff --git a/libc/bionic/gwp_asan_wrappers.cpp b/libc/bionic/gwp_asan_wrappers.cpp index 11f7cedd2..2124f515d 100644 --- a/libc/bionic/gwp_asan_wrappers.cpp +++ b/libc/bionic/gwp_asan_wrappers.cpp @@ -57,7 +57,7 @@ static gwp_asan::GuardedPoolAllocator GuardedAlloc; static const MallocDispatch* prev_dispatch; -using Action = android_mallopt_gwp_asan_options_t::Action; +using Mode = android_mallopt_gwp_asan_options_t::Mode; using Options = gwp_asan::options::Options; // basename() is a mess, see the manpage. Let's be explicit what handling we @@ -261,8 +261,8 @@ void SetDefaultGwpAsanOptions(Options* options, unsigned* process_sample_rate, options->Recoverable = true; GwpAsanRecoverable = true; - if (mallopt_options.desire == Action::TURN_ON_WITH_SAMPLING || - mallopt_options.desire == Action::TURN_ON_FOR_APP_SAMPLED_NON_CRASHING) { + if (mallopt_options.mode == Mode::SYSTEM_PROCESS_OR_SYSTEM_APP || + mallopt_options.mode == Mode::APP_MANIFEST_DEFAULT) { *process_sample_rate = kDefaultProcessSampling; } else { *process_sample_rate = 1; @@ -285,7 +285,7 @@ bool GetGwpAsanOptionImpl(char* value_out, // be used. Tests still continue to use the environment variable though. if (*basename != '\0') { const char* default_sysprop = system_sysprop; - if (mallopt_options.desire == Action::TURN_ON_FOR_APP) { + if (mallopt_options.mode == Mode::APP_MANIFEST_ALWAYS) { default_sysprop = app_sysprop; } async_safe_format_buffer(&program_specific_sysprop[0], kSyspropMaxLen, "%s%s", @@ -425,7 +425,7 @@ bool MaybeInitGwpAsan(libc_globals* globals, Options options; unsigned process_sample_rate = kDefaultProcessSampling; if (!GetGwpAsanOptions(&options, &process_sample_rate, mallopt_options) && - mallopt_options.desire == Action::DONT_TURN_ON_UNLESS_OVERRIDDEN) { + mallopt_options.mode == Mode::APP_MANIFEST_NEVER) { return false; } @@ -492,7 +492,7 @@ bool MaybeInitGwpAsanFromLibc(libc_globals* globals) { android_mallopt_gwp_asan_options_t mallopt_options; mallopt_options.program_name = progname; - mallopt_options.desire = Action::TURN_ON_WITH_SAMPLING; + mallopt_options.mode = Mode::SYSTEM_PROCESS_OR_SYSTEM_APP; return MaybeInitGwpAsan(globals, mallopt_options); } diff --git a/libc/bionic/heap_tagging.cpp b/libc/bionic/heap_tagging.cpp index 4d1981c30..c8a025f57 100644 --- a/libc/bionic/heap_tagging.cpp +++ b/libc/bionic/heap_tagging.cpp @@ -38,6 +38,11 @@ extern "C" void scudo_malloc_disable_memory_tagging(); extern "C" void scudo_malloc_set_track_allocation_stacks(int); +extern "C" const char* __scudo_get_stack_depot_addr(); +extern "C" const char* __scudo_get_ring_buffer_addr(); +extern "C" size_t __scudo_get_ring_buffer_size(); +extern "C" size_t __scudo_get_stack_depot_size(); + // Protected by `g_heap_tagging_lock`. static HeapTaggingLevel heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE; @@ -158,6 +163,10 @@ bool SetHeapTaggingLevel(HeapTaggingLevel tag_level) { set_tcf_on_all_threads(PR_MTE_TCF_SYNC); #if defined(USE_SCUDO) && !__has_feature(hwaddress_sanitizer) scudo_malloc_set_track_allocation_stacks(1); + __libc_shared_globals()->scudo_ring_buffer = __scudo_get_ring_buffer_addr(); + __libc_shared_globals()->scudo_ring_buffer_size = __scudo_get_ring_buffer_size(); + __libc_shared_globals()->scudo_stack_depot = __scudo_get_stack_depot_addr(); + __libc_shared_globals()->scudo_stack_depot_size = __scudo_get_stack_depot_size(); #endif } break; diff --git a/libc/bionic/jemalloc_wrapper.cpp b/libc/bionic/jemalloc_wrapper.cpp index a2bb1dbb4..1bbdb296c 100644 --- a/libc/bionic/jemalloc_wrapper.cpp +++ b/libc/bionic/jemalloc_wrapper.cpp @@ -77,9 +77,13 @@ void* je_aligned_alloc_wrapper(size_t alignment, size_t size) { int je_mallopt(int param, int value) { // The only parameter we currently understand is M_DECAY_TIME. if (param == M_DECAY_TIME) { - // Only support setting the value to 1 or 0. + // Only support setting the value to -1 or 0 or 1. ssize_t decay_time_ms; - if (value) { + if (value < 0) { + // Given that SSIZE_MAX may not be supported in jemalloc, set this to a + // sufficiently large number that essentially disables the decay timer. + decay_time_ms = 10000000; + } else if (value) { decay_time_ms = 1000; } else { decay_time_ms = 0; diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp index 1180a513e..2dde2f10f 100644 --- a/libc/bionic/libc_init_dynamic.cpp +++ b/libc/bionic/libc_init_dynamic.cpp @@ -61,7 +61,7 @@ extern "C" { }; void memtag_stack_dlopen_callback() { - async_safe_format_log(ANDROID_LOG_INFO, "libc", "remapping stacks as PROT_MTE"); + async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "remapping stacks as PROT_MTE"); __pthread_internal_remap_stack_with_mte(); } diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp index d86df3093..3da0a92d3 100644 --- a/libc/bionic/libc_init_static.cpp +++ b/libc/bionic/libc_init_static.cpp @@ -297,6 +297,30 @@ static HeapTaggingLevel __get_tagging_level(const memtag_dynamic_entries_t* memt return level; } +static int64_t __get_memtag_upgrade_secs() { + char* env = getenv("BIONIC_MEMTAG_UPGRADE_SECS"); + if (!env) return 0; + int64_t timed_upgrade = 0; + static const char kAppProcessName[] = "app_process64"; + const char* progname = __libc_shared_globals()->init_progname; + progname = progname ? __gnu_basename(progname) : nullptr; + // disable timed upgrade for zygote, as the thread spawned will violate the requirement + // that it be single-threaded. + if (!progname || strncmp(progname, kAppProcessName, sizeof(kAppProcessName)) != 0) { + char* endptr; + timed_upgrade = strtoll(env, &endptr, 10); + if (*endptr != '\0' || timed_upgrade < 0) { + async_safe_format_log(ANDROID_LOG_ERROR, "libc", + "Invalid value for BIONIC_MEMTAG_UPGRADE_SECS: %s", env); + timed_upgrade = 0; + } + } + // Make sure that this does not get passed to potential processes inheriting + // this environment. + unsetenv("BIONIC_MEMTAG_UPGRADE_SECS"); + return timed_upgrade; +} + // Figure out the desired memory tagging mode (sync/async, heap/globals/stack) for this executable. // This function is called from the linker before the main executable is relocated. __attribute__((no_sanitize("hwaddress", "memtag"))) void __libc_init_mte( @@ -313,31 +337,7 @@ __attribute__((no_sanitize("hwaddress", "memtag"))) void __libc_init_mte( } memtag_stack = true; } - char* env = getenv("BIONIC_MEMTAG_UPGRADE_SECS"); - static const char kAppProcessName[] = "app_process64"; - const char* progname = __libc_shared_globals()->init_progname; - progname = progname ? __gnu_basename(progname) : nullptr; - if (progname && - strncmp(progname, kAppProcessName, sizeof(kAppProcessName)) == 0) { - // disable timed upgrade for zygote, as the thread spawned will violate the requirement - // that it be single-threaded. - env = nullptr; - } - int64_t timed_upgrade = 0; - if (env) { - char* endptr; - timed_upgrade = strtoll(env, &endptr, 10); - if (*endptr != '\0' || timed_upgrade < 0) { - async_safe_format_log(ANDROID_LOG_ERROR, "libc", - "Invalid value for BIONIC_MEMTAG_UPGRADE_SECS: %s", - env); - timed_upgrade = 0; - } - // Make sure that this does not get passed to potential processes inheriting - // this environment. - unsetenv("BIONIC_MEMTAG_UPGRADE_SECS"); - } - if (timed_upgrade) { + if (int64_t timed_upgrade = __get_memtag_upgrade_secs()) { if (level == M_HEAP_TAGGING_LEVEL_ASYNC) { async_safe_format_log(ANDROID_LOG_INFO, "libc", "Attempting timed MTE upgrade from async to sync."); diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp index 9932e3e53..596a1fc82 100644 --- a/libc/bionic/malloc_common.cpp +++ b/libc/bionic/malloc_common.cpp @@ -123,7 +123,7 @@ extern "C" int mallopt(int param, int value) { // Track the M_DECAY_TIME mallopt calls. if (param == M_DECAY_TIME && retval == 1) { __libc_globals.mutate([value](libc_globals* globals) { - if (value == 0) { + if (value <= 0) { atomic_store(&globals->decay_time_enabled, false); } else { atomic_store(&globals->decay_time_enabled, true); diff --git a/libc/bionic/posix_timers.cpp b/libc/bionic/posix_timers.cpp index f522516af..ccbbfcf8f 100644 --- a/libc/bionic/posix_timers.cpp +++ b/libc/bionic/posix_timers.cpp @@ -34,6 +34,8 @@ #include <string.h> #include <time.h> +#include "private/bionic_lock.h" + // System calls. extern "C" int __rt_sigprocmask(int, const sigset64_t*, sigset64_t*, size_t); extern "C" int __rt_sigtimedwait(const sigset64_t*, siginfo_t*, const timespec*, size_t); @@ -60,6 +62,7 @@ struct PosixTimer { int sigev_notify; // The fields below are only needed for a SIGEV_THREAD timer. + Lock startup_handshake_lock; pthread_t callback_thread; void (*callback)(sigval_t); sigval_t callback_argument; @@ -73,6 +76,18 @@ static __kernel_timer_t to_kernel_timer_id(timer_t timer) { static void* __timer_thread_start(void* arg) { PosixTimer* timer = reinterpret_cast<PosixTimer*>(arg); + // Check that our parent managed to create the kernel timer and bail if not... + timer->startup_handshake_lock.lock(); + if (timer->kernel_timer_id == -1) { + free(timer); + return nullptr; + } + + // Give ourselves a specific meaningful name now we have a kernel timer. + char name[16]; // 16 is the kernel-imposed limit. + snprintf(name, sizeof(name), "POSIX timer %d", to_kernel_timer_id(timer)); + pthread_setname_np(timer->callback_thread, name); + sigset64_t sigset = {}; sigaddset64(&sigset, TIMER_SIGNAL); @@ -109,6 +124,7 @@ int timer_create(clockid_t clock_id, sigevent* evp, timer_t* timer_id) { return -1; } + timer->kernel_timer_id = -1; timer->sigev_notify = (evp == nullptr) ? SIGEV_SIGNAL : evp->sigev_notify; // If not a SIGEV_THREAD timer, the kernel can handle it without our help. @@ -149,6 +165,10 @@ int timer_create(clockid_t clock_id, sigevent* evp, timer_t* timer_id) { sigaddset64(&sigset, TIMER_SIGNAL); sigset64_t old_sigset; + // Prevent the child thread from running until the timer has been created. + timer->startup_handshake_lock.init(false); + timer->startup_handshake_lock.lock(); + // Use __rt_sigprocmask instead of sigprocmask64 to avoid filtering out TIMER_SIGNAL. __rt_sigprocmask(SIG_BLOCK, &sigset, &old_sigset, sizeof(sigset)); @@ -162,21 +182,21 @@ int timer_create(clockid_t clock_id, sigevent* evp, timer_t* timer_id) { return -1; } + // Try to create the kernel timer. sigevent se = *evp; se.sigev_signo = TIMER_SIGNAL; se.sigev_notify = SIGEV_THREAD_ID; se.sigev_notify_thread_id = pthread_gettid_np(timer->callback_thread); - if (__timer_create(clock_id, &se, &timer->kernel_timer_id) == -1) { - __timer_thread_stop(timer); + rc = __timer_create(clock_id, &se, &timer->kernel_timer_id); + + // Let the child run (whether we created the kernel timer or not). + timer->startup_handshake_lock.unlock(); + // If __timer_create(2) failed, the child will kill itself and free the + // timer struct, so we just need to exit. + if (rc == -1) { return -1; } - // Give the thread a specific meaningful name. - // It can't do this itself because the kernel timer isn't created until after it's running. - char name[16]; // 16 is the kernel-imposed limit. - snprintf(name, sizeof(name), "POSIX timer %d", to_kernel_timer_id(timer)); - pthread_setname_np(timer->callback_thread, name); - *timer_id = timer; return 0; } diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h index 091f711eb..c2abdea29 100644 --- a/libc/bionic/pthread_internal.h +++ b/libc/bionic/pthread_internal.h @@ -240,7 +240,7 @@ __LIBC_HIDDEN__ void pthread_key_clean_all(void); // On LP64, we could use more but there's no obvious advantage to doing // so, and the various media processes use RLIMIT_AS as a way to limit // the amount of allocation they'll do. -#define PTHREAD_GUARD_SIZE max_page_size() +#define PTHREAD_GUARD_SIZE max_android_page_size() // SIGSTKSZ (8KiB) is not big enough. // An snprintf to a stack buffer of size PATH_MAX consumes ~7KiB of stack. diff --git a/libc/bionic/sys_thread_properties.cpp b/libc/bionic/sys_thread_properties.cpp index d1a73b7f9..d7188f521 100644 --- a/libc/bionic/sys_thread_properties.cpp +++ b/libc/bionic/sys_thread_properties.cpp @@ -77,22 +77,20 @@ static inline __always_inline bionic_tcb* __get_bionic_tcb_for_thread(pid_t tid) // Find the thread-pointer register for the given thread. void** tp_reg = nullptr; -#if defined(__x86_64__) - { - ErrnoRestorer errno_restorer; - errno = 0; - uintptr_t fs_base = ptrace(PTRACE_PEEKUSER, tid, offsetof(user_regs_struct, fs_base), nullptr); - if (errno == 0) { - tp_reg = reinterpret_cast<void**>(fs_base); - } +#if defined(__aarch64__) + uint64_t reg; + struct iovec pt_iov { .iov_base = ®, .iov_len = sizeof(reg) }; + if (ptrace(PTRACE_GETREGSET, tid, NT_ARM_TLS, &pt_iov) == 0) { + tp_reg = reinterpret_cast<void**>(reg); + } +#elif defined(__arm__) + if (ptrace(PTRACE_GET_THREAD_AREA, tid, nullptr, &tp_reg) != 0) { + // Reset the tp_reg if ptrace was unsuccessful. + tp_reg = nullptr; } #elif defined(__i386__) struct user_regs_struct regs; - struct iovec pt_iov = { - .iov_base = ®s, - .iov_len = sizeof(regs), - }; - + struct iovec pt_iov = { .iov_base = ®s, .iov_len = sizeof(regs) }; if (ptrace(PTRACE_GETREGSET, tid, NT_PRSTATUS, &pt_iov) == 0) { struct user_desc u_info; u_info.entry_number = regs.xgs >> 3; @@ -100,19 +98,20 @@ static inline __always_inline bionic_tcb* __get_bionic_tcb_for_thread(pid_t tid) tp_reg = reinterpret_cast<void**>(u_info.base_addr); } } -#elif defined(__aarch64__) - uint64_t reg; - struct iovec pt_iov { - .iov_base = ®, .iov_len = sizeof(reg), - }; - - if (ptrace(PTRACE_GETREGSET, tid, NT_ARM_TLS, &pt_iov) == 0) { - tp_reg = reinterpret_cast<void**>(reg); +#elif defined(__riscv) + struct user_regs_struct regs; + struct iovec pt_iov = { .iov_base = ®s, .iov_len = sizeof(regs) }; + if (ptrace(PTRACE_GETREGSET, tid, NT_PRSTATUS, &pt_iov) == 0) { + tp_reg = reinterpret_cast<void**>(regs.tp); } -#elif defined(__arm__) - if (ptrace(PTRACE_GET_THREAD_AREA, tid, nullptr, &tp_reg) != 0) { - // Reset the tp_reg if ptrace was unsuccessful. - tp_reg = nullptr; +#elif defined(__x86_64__) + { + ErrnoRestorer errno_restorer; + errno = 0; + uintptr_t fs_base = ptrace(PTRACE_PEEKUSER, tid, offsetof(user_regs_struct, fs_base), nullptr); + if (errno == 0) { + tp_reg = reinterpret_cast<void**>(fs_base); + } } #endif diff --git a/libc/dns/resolv/res_cache.c b/libc/dns/resolv/res_cache.c index d6416e5c5..38de84b5f 100644 --- a/libc/dns/resolv/res_cache.c +++ b/libc/dns/resolv/res_cache.c @@ -1166,23 +1166,19 @@ entry_free( Entry* e ) } } -static inline void -entry_mru_remove( Entry* e ) -{ - e->mru_prev->mru_next = e->mru_next; - e->mru_next->mru_prev = e->mru_prev; +static __inline__ void entry_mru_remove(Entry* e) { + e->mru_prev->mru_next = e->mru_next; + e->mru_next->mru_prev = e->mru_prev; } -static inline void -entry_mru_add( Entry* e, Entry* list ) -{ - Entry* first = list->mru_next; +static __inline__ void entry_mru_add(Entry* e, Entry* list) { + Entry* first = list->mru_next; - e->mru_next = first; - e->mru_prev = list; + e->mru_next = first; + e->mru_prev = list; - list->mru_next = e; - first->mru_prev = e; + list->mru_next = e; + first->mru_prev = e; } /* compute the hash of a given entry, this is a hash of most diff --git a/libc/include/android/api-level.h b/libc/include/android/api-level.h index 113897c97..1bde3a598 100644 --- a/libc/include/android/api-level.h +++ b/libc/include/android/api-level.h @@ -168,7 +168,10 @@ __BEGIN_DECLS */ #define __ANDROID_API_U__ 34 -/** Names the "V" API level (35), for comparison against `__ANDROID_API__`. */ +/** + * Names the Android 15 (aka "V" or "VanillaIceCream") API level (35), + * for comparison against `__ANDROID_API__`. + */ #define __ANDROID_API_V__ 35 /* This file is included in <features.h>, and might be used from .S files. */ @@ -191,7 +194,7 @@ int android_get_application_target_sdk_version() __INTRODUCED_IN(24); #if __ANDROID_API__ < 29 /* android_get_device_api_level is a static inline before API level 29. */ -#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static inline +#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline #include <bits/get_device_api_level_inlines.h> #undef __BIONIC_GET_DEVICE_API_LEVEL_INLINE diff --git a/libc/include/android/dlext.h b/libc/include/android/dlext.h index a5061c741..b42e5b22f 100644 --- a/libc/include/android/dlext.h +++ b/libc/include/android/dlext.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef __ANDROID_DLEXT_H__ -#define __ANDROID_DLEXT_H__ +#pragma once #include <stdbool.h> #include <stddef.h> @@ -101,7 +100,7 @@ enum { ANDROID_DLEXT_FORCE_LOAD = 0x40, // Historically we had two other options for ART. - // They were last available in Android P. + // They were last available in API level 28. // Reuse these bits last! // ANDROID_DLEXT_FORCE_FIXED_VADDR = 0x80 // ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS = 0x100 @@ -115,7 +114,7 @@ enum { ANDROID_DLEXT_USE_NAMESPACE = 0x200, /** - * Instructs dlopen to apply `ANDROID_DLEXT_RESERVED_ADDRESS`, + * Instructs dlopen() to apply `ANDROID_DLEXT_RESERVED_ADDRESS`, * `ANDROID_DLEXT_RESERVED_ADDRESS_HINT`, `ANDROID_DLEXT_WRITE_RELRO` and * `ANDROID_DLEXT_USE_RELRO` to any libraries loaded as dependencies of the * main library as well. @@ -151,7 +150,7 @@ enum { struct android_namespace_t; -/** Used to pass Android-specific arguments to `android_dlopen_ext`. */ +/** Used to pass Android-specific arguments to android_dlopen_ext(). */ typedef struct { /** A bitmask of `ANDROID_DLEXT_` enum values. */ uint64_t flags; @@ -183,5 +182,3 @@ void* _Nullable android_dlopen_ext(const char* _Nullable __filename, int __flags __END_DECLS /** @} */ - -#endif diff --git a/libc/include/android/legacy_stdlib_inlines.h b/libc/include/android/legacy_stdlib_inlines.h index 0ca1022e8..f0985fe61 100644 --- a/libc/include/android/legacy_stdlib_inlines.h +++ b/libc/include/android/legacy_stdlib_inlines.h @@ -38,15 +38,15 @@ __BEGIN_DECLS -static inline double strtod_l(const char* _Nonnull __s, char* _Nullable * _Nullable __end_ptr, locale_t _Nonnull __l) { +static __inline double strtod_l(const char* _Nonnull __s, char* _Nullable * _Nullable __end_ptr, locale_t _Nonnull __l) { return strtod(__s, __end_ptr); } -static inline float strtof_l(const char* _Nonnull __s, char* _Nullable * _Nullable __end_ptr, locale_t _Nonnull __l) { +static __inline float strtof_l(const char* _Nonnull __s, char* _Nullable * _Nullable __end_ptr, locale_t _Nonnull __l) { return strtof(__s, __end_ptr); } -static inline long strtol_l(const char* _Nonnull __s, char* _Nullable * _Nullable __end_ptr, int __base, locale_t _Nonnull __l) { +static __inline long strtol_l(const char* _Nonnull __s, char* _Nullable * _Nullable __end_ptr, int __base, locale_t _Nonnull __l) { return strtol(__s, __end_ptr, __base); } diff --git a/libc/include/android/legacy_termios_inlines.h b/libc/include/android/legacy_termios_inlines.h index e557525ab..a816b4048 100644 --- a/libc/include/android/legacy_termios_inlines.h +++ b/libc/include/android/legacy_termios_inlines.h @@ -39,14 +39,14 @@ #include <sys/ioctl.h> #include <sys/types.h> -#define __BIONIC_TERMIOS_INLINE static inline +#define __BIONIC_TERMIOS_INLINE static __inline #include <bits/termios_inlines.h> #endif #if __ANDROID_API__ < 35 -#define __BIONIC_TERMIOS_WINSIZE_INLINE static inline +#define __BIONIC_TERMIOS_WINSIZE_INLINE static __inline #include <bits/termios_winsize_inlines.h> #endif diff --git a/libc/include/android/legacy_threads_inlines.h b/libc/include/android/legacy_threads_inlines.h index 06e743813..c614cd01a 100644 --- a/libc/include/android/legacy_threads_inlines.h +++ b/libc/include/android/legacy_threads_inlines.h @@ -32,7 +32,7 @@ #if __ANDROID_API__ < 30 -#define __BIONIC_THREADS_INLINE static inline +#define __BIONIC_THREADS_INLINE static __inline #include <bits/threads_inlines.h> #endif diff --git a/libc/include/android/legacy_unistd_inlines.h b/libc/include/android/legacy_unistd_inlines.h index ac9f3b354..4a5206b88 100644 --- a/libc/include/android/legacy_unistd_inlines.h +++ b/libc/include/android/legacy_unistd_inlines.h @@ -32,7 +32,7 @@ #if __ANDROID_API__ < 28 -#define __BIONIC_SWAB_INLINE static inline +#define __BIONIC_SWAB_INLINE static __inline #include <bits/swab.h> #endif diff --git a/libc/include/android/versioning.h b/libc/include/android/versioning.h index cd61f3393..64528e1b5 100644 --- a/libc/include/android/versioning.h +++ b/libc/include/android/versioning.h @@ -22,8 +22,8 @@ #define __INTRODUCED_IN(api_level) __attribute__((__annotate__("introduced_in=" #api_level))) #define __INTRODUCED_IN_NO_GUARD_FOR_NDK(api_level) __attribute__((__annotate__("introduced_in=" #api_level))) __VERSIONER_NO_GUARD -#define __DEPRECATED_IN(api_level) __attribute__((__annotate__("deprecated_in=" #api_level))) -#define __REMOVED_IN(api_level) __attribute__((__annotate__("obsoleted_in=" #api_level))) +#define __DEPRECATED_IN(api_level, ...) __attribute__((__annotate__("deprecated_in=" #api_level))) +#define __REMOVED_IN(api_level, ...) __attribute__((__annotate__("obsoleted_in=" #api_level))) #define __INTRODUCED_IN_32(api_level) __attribute__((__annotate__("introduced_in_32=" #api_level))) #define __INTRODUCED_IN_64(api_level) __attribute__((__annotate__("introduced_in_64=" #api_level))) @@ -47,16 +47,16 @@ // libc++ doesn't currently guard these calls. There's no risk to the apps though because using // those APIs will still cause a link error. #if defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__) -#define __BIONIC_AVAILABILITY(__what) __attribute__((__availability__(android,__what))) +#define __BIONIC_AVAILABILITY(__what, ...) __attribute__((__availability__(android,__what __VA_OPT__(,) __VA_ARGS__))) #define __INTRODUCED_IN_NO_GUARD_FOR_NDK(api_level) __INTRODUCED_IN(api_level) #else -#define __BIONIC_AVAILABILITY(__what) __attribute__((__availability__(android,strict,__what))) +#define __BIONIC_AVAILABILITY(__what, ...) __attribute__((__availability__(android,strict,__what __VA_OPT__(,) __VA_ARGS__))) #define __INTRODUCED_IN_NO_GUARD_FOR_NDK(api_level) #endif #define __INTRODUCED_IN(api_level) __BIONIC_AVAILABILITY(introduced=api_level) -#define __DEPRECATED_IN(api_level) __BIONIC_AVAILABILITY(deprecated=api_level) -#define __REMOVED_IN(api_level) __BIONIC_AVAILABILITY(obsoleted=api_level) +#define __DEPRECATED_IN(api_level, ...) __BIONIC_AVAILABILITY(deprecated=api_level __VA_OPT__(,message=) __VA_ARGS__) +#define __REMOVED_IN(api_level, ...) __BIONIC_AVAILABILITY(obsoleted=api_level __VA_OPT__(,message=) __VA_ARGS__) // The same availability attribute can't be annotated multiple times. Therefore, the macros are // defined for the configuration that it is valid for so that declarations like the below doesn't @@ -80,5 +80,5 @@ // Vendor modules do not follow SDK versioning. Ignore NDK guards for vendor modules. #if defined(__ANDROID_VENDOR__) #undef __BIONIC_AVAILABILITY -#define __BIONIC_AVAILABILITY(x) +#define __BIONIC_AVAILABILITY(api_level, ...) #endif // defined(__ANDROID_VENDOR__) diff --git a/libc/include/bits/stdatomic.h b/libc/include/bits/stdatomic.h index 8df86e2ad..c74eafdec 100644 --- a/libc/include/bits/stdatomic.h +++ b/libc/include/bits/stdatomic.h @@ -138,11 +138,11 @@ typedef enum { * 7.17.4 Fences. */ -static inline void atomic_thread_fence(memory_order __order __attribute__((__unused__))) { +static __inline void atomic_thread_fence(memory_order __order __attribute__((__unused__))) { __c11_atomic_thread_fence(__order); } -static inline void atomic_signal_fence(memory_order __order __attribute__((__unused__))) { +static __inline void atomic_signal_fence(memory_order __order __attribute__((__unused__))) { __c11_atomic_signal_fence(__order); } @@ -269,18 +269,18 @@ typedef struct { #define ATOMIC_FLAG_INIT { ATOMIC_VAR_INIT(false) } -static inline bool atomic_flag_test_and_set_explicit(volatile atomic_flag * _Nonnull __object, memory_order __order) { +static __inline bool atomic_flag_test_and_set_explicit(volatile atomic_flag * _Nonnull __object, memory_order __order) { return (atomic_exchange_explicit(&__object->__flag, 1, __order)); } -static inline void atomic_flag_clear_explicit(volatile atomic_flag * _Nonnull __object, memory_order __order) { +static __inline void atomic_flag_clear_explicit(volatile atomic_flag * _Nonnull __object, memory_order __order) { atomic_store_explicit(&__object->__flag, 0, __order); } -static inline bool atomic_flag_test_and_set(volatile atomic_flag * _Nonnull __object) { +static __inline bool atomic_flag_test_and_set(volatile atomic_flag * _Nonnull __object) { return (atomic_flag_test_and_set_explicit(__object, memory_order_seq_cst)); } -static inline void atomic_flag_clear(volatile atomic_flag * _Nonnull __object) { +static __inline void atomic_flag_clear(volatile atomic_flag * _Nonnull __object) { atomic_flag_clear_explicit(__object, memory_order_seq_cst); } diff --git a/libc/include/bits/swab.h b/libc/include/bits/swab.h index ebb7c7406..9591c2ede 100644 --- a/libc/include/bits/swab.h +++ b/libc/include/bits/swab.h @@ -33,7 +33,7 @@ #include <sys/types.h> #if !defined(__BIONIC_SWAB_INLINE) -#define __BIONIC_SWAB_INLINE static inline +#define __BIONIC_SWAB_INLINE static __inline #endif __BEGIN_DECLS diff --git a/libc/include/bits/termios_inlines.h b/libc/include/bits/termios_inlines.h index 702f43346..a884b595f 100644 --- a/libc/include/bits/termios_inlines.h +++ b/libc/include/bits/termios_inlines.h @@ -37,7 +37,7 @@ #include <linux/termios.h> #if !defined(__BIONIC_TERMIOS_INLINE) -#define __BIONIC_TERMIOS_INLINE static inline +#define __BIONIC_TERMIOS_INLINE static __inline #endif __BEGIN_DECLS @@ -45,7 +45,7 @@ __BEGIN_DECLS // Supporting separate input and output speeds would require an ABI // change for `struct termios`. -static inline speed_t cfgetspeed(const struct termios* _Nonnull s) { +static __inline speed_t cfgetspeed(const struct termios* _Nonnull s) { return __BIONIC_CAST(static_cast, speed_t, s->c_cflag & CBAUD); } diff --git a/libc/include/bits/termios_winsize_inlines.h b/libc/include/bits/termios_winsize_inlines.h index 0d188e75e..ae246e401 100644 --- a/libc/include/bits/termios_winsize_inlines.h +++ b/libc/include/bits/termios_winsize_inlines.h @@ -36,7 +36,7 @@ #include <linux/termios.h> #if !defined(__BIONIC_TERMIOS_WINSIZE_INLINE) -#define __BIONIC_TERMIOS_WINSIZE_INLINE static inline +#define __BIONIC_TERMIOS_WINSIZE_INLINE static __inline #endif __BEGIN_DECLS diff --git a/libc/include/bits/threads_inlines.h b/libc/include/bits/threads_inlines.h index 074e1ca98..459866ed8 100644 --- a/libc/include/bits/threads_inlines.h +++ b/libc/include/bits/threads_inlines.h @@ -38,7 +38,7 @@ __BEGIN_DECLS -static inline int __bionic_thrd_error(int __pthread_code) { +static __inline int __bionic_thrd_error(int __pthread_code) { switch (__pthread_code) { case 0: return 0; case ENOMEM: return thrd_nomem; @@ -124,7 +124,7 @@ struct __bionic_thrd_data { }; #pragma clang diagnostic pop -static inline void* _Nonnull __bionic_thrd_trampoline(void* _Nonnull __arg) { +static __inline void* _Nonnull __bionic_thrd_trampoline(void* _Nonnull __arg) { struct __bionic_thrd_data __data = *__BIONIC_CAST(static_cast, struct __bionic_thrd_data*, __arg); free(__arg); diff --git a/libc/include/ctype.h b/libc/include/ctype.h index 5cad412d6..c15ee5618 100644 --- a/libc/include/ctype.h +++ b/libc/include/ctype.h @@ -42,7 +42,7 @@ * also provide actual symbols for any caller that needs them. */ #if !defined(__BIONIC_CTYPE_INLINE) -#define __BIONIC_CTYPE_INLINE static inline +#define __BIONIC_CTYPE_INLINE static __inline #endif /** Internal implementation detail. Do not use. */ diff --git a/libc/include/link.h b/libc/include/link.h index 33fea49fc..ee1fc42ea 100644 --- a/libc/include/link.h +++ b/libc/include/link.h @@ -25,8 +25,13 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ -#ifndef _LINK_H_ -#define _LINK_H_ + +#pragma once + +/** + * @file link.h + * @brief Extra dynamic linker functionality (see also <dlfcn.h>). + */ #include <stdint.h> #include <sys/cdefs.h> @@ -37,32 +42,80 @@ __BEGIN_DECLS #if defined(__LP64__) +/** Convenience macro to get the appropriate 32-bit or 64-bit <elf.h> type for the caller's bitness. */ #define ElfW(type) Elf64_ ## type #else +/** Convenience macro to get the appropriate 32-bit or 64-bit <elf.h> type for the caller's bitness. */ #define ElfW(type) Elf32_ ## type #endif +/** + * Information passed by dl_iterate_phdr() to the callback. + */ struct dl_phdr_info { + /** The address of the shared object. */ ElfW(Addr) dlpi_addr; + /** The name of the shared object. */ const char* _Nullable dlpi_name; + /** Pointer to the shared object's program headers. */ const ElfW(Phdr)* _Nullable dlpi_phdr; + /** Number of program headers pointed to by `dlpi_phdr`. */ ElfW(Half) dlpi_phnum; - // These fields were added in Android R. + /** + * The total number of library load events at the time dl_iterate_phdr() was + * called. + * + * This field is only available since API level 30; you can use the size + * passed to the callback to determine whether you have the full struct, + * or just the fields up to and including `dlpi_phnum`. + */ unsigned long long dlpi_adds; + /** + * The total number of library unload events at the time dl_iterate_phdr() was + * called. + * + * This field is only available since API level 30; you can use the size + * passed to the callback to determine whether you have the full struct, + * or just the fields up to and including `dlpi_phnum`. + */ unsigned long long dlpi_subs; + /** + * The module ID for TLS relocations in this shared object. + * + * This field is only available since API level 30; you can use the size + * passed to the callback to determine whether you have the full struct, + * or just the fields up to and including `dlpi_phnum`. + */ size_t dlpi_tls_modid; + /** + * The caller's TLS data for this shared object. + * + * This field is only available since API level 30; you can use the size + * passed to the callback to determine whether you have the full struct, + * or just the fields up to and including `dlpi_phnum`. + */ void* _Nullable dlpi_tls_data; }; -int dl_iterate_phdr(int (* _Nonnull __callback)(struct dl_phdr_info* _Nonnull, size_t, void* _Nullable), void* _Nullable __data); +/** + * [dl_iterate_phdr(3)](http://man7.org/linux/man-pages/man3/dl_iterate_phdr.3.html) + * calls the given callback once for every loaded shared object. The size + * argument to the callback lets you determine whether you have a smaller + * `dl_phdr_info` from before API level 30, or the newer full one. + * The data argument to the callback is whatever you pass as the data argument + * to dl_iterate_phdr(). + * + * Returns the value returned by the final call to the callback. + */ +int dl_iterate_phdr(int (* _Nonnull __callback)(struct dl_phdr_info* _Nonnull __info, size_t __size, void* _Nullable __data), void* _Nullable __data); #ifdef __arm__ typedef uintptr_t _Unwind_Ptr; _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr, int* _Nonnull); #endif -/* Used by the dynamic linker to communicate with the debugger. */ +/** Used by the dynamic linker to communicate with the debugger. */ struct link_map { ElfW(Addr) l_addr; char* _Nullable l_name; @@ -71,7 +124,7 @@ struct link_map { struct link_map* _Nullable l_prev; }; -/* Used by the dynamic linker to communicate with the debugger. */ +/** Used by the dynamic linker to communicate with the debugger. */ struct r_debug { int32_t r_version; struct link_map* _Nullable r_map; @@ -85,5 +138,3 @@ struct r_debug { }; __END_DECLS - -#endif diff --git a/libc/include/malloc.h b/libc/include/malloc.h index d22b85ce5..ef1e27d5f 100644 --- a/libc/include/malloc.h +++ b/libc/include/malloc.h @@ -186,7 +186,11 @@ struct mallinfo2 mallinfo2(void) __RENAME(mallinfo); int malloc_info(int __must_be_zero, FILE* _Nonnull __fp) __INTRODUCED_IN(23); /** - * mallopt() option to set the decay time. Valid values are 0 and 1. + * mallopt() option to set the decay time. Valid values are -1, 0 and 1. + * -1 : Disable the releasing of unused pages. This value is available since + * API level 35. + * 0 : Release the unused pages immediately. + * 1 : Release the unused pages at a device-specific interval. * * Available since API level 27. */ diff --git a/libc/include/stdio.h b/libc/include/stdio.h index 32264d6d9..78114c38c 100644 --- a/libc/include/stdio.h +++ b/libc/include/stdio.h @@ -69,7 +69,7 @@ extern FILE* _Nonnull stderr __INTRODUCED_IN(23); #define stderr stderr #else /* Before M the actual symbols for stdin and friends had different names. */ -extern FILE __sF[] __REMOVED_IN(23); +extern FILE __sF[] __REMOVED_IN(23, "Use stdin/stdout/stderr"); #define stdin (&__sF[0]) #define stdout (&__sF[1]) diff --git a/libc/include/strings.h b/libc/include/strings.h index 6ec3bdf58..4b8cc08e3 100644 --- a/libc/include/strings.h +++ b/libc/include/strings.h @@ -50,7 +50,7 @@ #include <bits/strcasecmp.h> #if !defined(__BIONIC_STRINGS_INLINE) -#define __BIONIC_STRINGS_INLINE static inline +#define __BIONIC_STRINGS_INLINE static __inline #endif #undef ffs @@ -61,13 +61,13 @@ __BEGIN_DECLS /** Deprecated. Use memmove() instead. */ #define bcopy(b1, b2, len) __bionic_bcopy((b1), (b2), (len)) -static inline __always_inline void __bionic_bcopy(const void* _Nonnull b1, void* _Nonnull b2, size_t len) { +static __inline __always_inline void __bionic_bcopy(const void* _Nonnull b1, void* _Nonnull b2, size_t len) { __builtin_memmove(b2, b1, len); } /** Deprecated. Use memset() instead. */ #define bzero(b, len) __bionic_bzero((b), (len)) -static inline __always_inline void __bionic_bzero(void* _Nonnull b, size_t len) { +static __inline __always_inline void __bionic_bzero(void* _Nonnull b, size_t len) { __builtin_memset(b, 0, len); } diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h index 3218d1554..5d1718e94 100644 --- a/libc/include/sys/cdefs.h +++ b/libc/include/sys/cdefs.h @@ -87,9 +87,12 @@ #define __STRING(x) #x #define ___STRING(x) __STRING(x) -#if defined(__cplusplus) -#define __inline inline /* convert to C++ keyword */ -#endif /* !__cplusplus */ +// C++ has `inline` as a keyword, as does C99, but ANSI C (aka C89 aka C90) +// does not. Everything accepts the `__inline__` extension though. We could +// just use that directly in our own code, but there's historical precedent +// for `__inline` meaning it's still used in upstream BSD code (and potentially +// downstream in vendor or app code). +#define __inline __inline__ #define __always_inline __attribute__((__always_inline__)) #define __attribute_const__ __attribute__((__const__)) @@ -260,7 +263,7 @@ * them available externally. FORTIFY'ed functions try to be as close to possible as 'invisible'; * having stack protectors detracts from that (b/182948263). */ -# define __BIONIC_FORTIFY_INLINE static inline __attribute__((__no_stack_protector__)) \ +# define __BIONIC_FORTIFY_INLINE static __inline __attribute__((__no_stack_protector__)) \ __always_inline __VERSIONER_FORTIFY_INLINE /* * We should use __BIONIC_FORTIFY_VARIADIC instead of __BIONIC_FORTIFY_INLINE @@ -268,9 +271,9 @@ * The __always_inline attribute is useless, misleading, and could trigger * clang compiler bug to incorrectly inline variadic functions. */ -# define __BIONIC_FORTIFY_VARIADIC static inline +# define __BIONIC_FORTIFY_VARIADIC static __inline /* Error functions don't have bodies, so they can just be static. */ -# define __BIONIC_ERROR_FUNCTION_VISIBILITY static __attribute__((__unused__)) +# define __BIONIC_ERROR_FUNCTION_VISIBILITY static __unused #else /* Further increase sharing for some inline functions */ # define __pass_object_size_n(n) diff --git a/libc/include/sys/system_properties.h b/libc/include/sys/system_properties.h index dc869da62..ae94db56c 100644 --- a/libc/include/sys/system_properties.h +++ b/libc/include/sys/system_properties.h @@ -26,8 +26,12 @@ * SUCH DAMAGE. */ -#ifndef _INCLUDE_SYS_SYSTEM_PROPERTIES_H -#define _INCLUDE_SYS_SYSTEM_PROPERTIES_H +#pragma once + +/** + * @file system_properties.h + * @brief System properties. + */ #include <sys/cdefs.h> #include <stdbool.h> @@ -36,39 +40,53 @@ __BEGIN_DECLS +/** An opaque structure representing a system property. */ typedef struct prop_info prop_info; +/** + * The limit on the length of a property value. + * (See PROP_NAME_MAX for property names.) + */ #define PROP_VALUE_MAX 92 -/* +/** * Sets system property `name` to `value`, creating the system property if it doesn't already exist. + * + * Returns 0 on success, or -1 on failure. */ int __system_property_set(const char* _Nonnull __name, const char* _Nonnull __value); -/* +/** * Returns a `prop_info` corresponding system property `name`, or nullptr if it doesn't exist. - * Use __system_property_read_callback to query the current value. + * Use __system_property_read_callback() to query the current value. * - * Property lookup is expensive, so it can be useful to cache the result of this function. + * Property lookup is expensive, so it can be useful to cache the result of this + * function rather than using __system_property_get(). */ const prop_info* _Nullable __system_property_find(const char* _Nonnull __name); -/* - * Calls `callback` with a consistent trio of name, value, and serial number for property `pi`. +/** + * Calls `callback` with a consistent trio of name, value, and serial number + * for property `pi`. + * + * Available since API level 26. */ void __system_property_read_callback(const prop_info* _Nonnull __pi, void (* _Nonnull __callback)(void* _Nullable __cookie, const char* _Nonnull __name, const char* _Nonnull __value, uint32_t __serial), void* _Nullable __cookie) __INTRODUCED_IN(26); -/* +/** * Passes a `prop_info` for each system property to the provided - * callback. Use __system_property_read_callback() to read the value. + * callback. Use __system_property_read_callback() to read the value of + * any of the properties. * * This method is for inspecting and debugging the property system, and not generally useful. + * + * Returns 0 on success, or -1 on failure. */ int __system_property_foreach(void (* _Nonnull __callback)(const prop_info* _Nonnull __pi, void* _Nullable __cookie), void* _Nullable __cookie); -/* +/** * Waits for the specific system property identified by `pi` to be updated * past `old_serial`. Waits no longer than `relative_timeout`, or forever * if `relative_timeout` is null. @@ -79,20 +97,24 @@ int __system_property_foreach(void (* _Nonnull __callback)(const prop_info* _Non * * Returns true and updates `*new_serial_ptr` on success, or false if the call * timed out. + * + * Available since API level 26. */ struct timespec; bool __system_property_wait(const prop_info* _Nullable __pi, uint32_t __old_serial, uint32_t* _Nonnull __new_serial_ptr, const struct timespec* _Nullable __relative_timeout) __INTRODUCED_IN(26); -/* Deprecated. In Android O and above, there's no limit on property name length. */ +/** + * Deprecated: there's no limit on the length of a property name since + * API level 26, though the limit on property values (PROP_VALUE_MAX) remains. + */ #define PROP_NAME_MAX 32 -/* Deprecated. Use __system_property_read_callback instead. */ + +/** Deprecated. Use __system_property_read_callback() instead. */ int __system_property_read(const prop_info* _Nonnull __pi, char* _Nullable __name, char* _Nonnull __value); -/* Deprecated. Use __system_property_read_callback instead. */ +/** Deprecated. Use __system_property_read_callback() instead. */ int __system_property_get(const char* _Nonnull __name, char* _Nonnull __value); -/* Deprecated. Use __system_property_foreach instead. */ +/** Deprecated. Use __system_property_foreach() instead. */ const prop_info* _Nullable __system_property_find_nth(unsigned __n); __END_DECLS - -#endif diff --git a/libc/kernel/tools/cpp.py b/libc/kernel/tools/cpp.py index 0fd6e46f9..08b786ac5 100755 --- a/libc/kernel/tools/cpp.py +++ b/libc/kernel/tools/cpp.py @@ -2345,11 +2345,11 @@ struct something_s { def test_function_keep_attribute_structs(self): text = """\ -static inline struct some_struct1 * function(struct some_struct2 * e) { +static __inline__ struct some_struct1 * function(struct some_struct2 * e) { } """ expected = """\ -static inline struct some_struct1 * function(struct some_struct2 * e) { +static __inline__ struct some_struct1 * function(struct some_struct2 * e) { } """ self.assertEqual(self.parse(text, set(["function"])), expected) diff --git a/libc/malloc_debug/MapData.cpp b/libc/malloc_debug/MapData.cpp index b22c10981..c58882a49 100644 --- a/libc/malloc_debug/MapData.cpp +++ b/libc/malloc_debug/MapData.cpp @@ -34,6 +34,8 @@ #include <stdlib.h> #include <string.h> #include <sys/mman.h> +#include <sys/uio.h> +#include <unistd.h> #include <vector> @@ -69,148 +71,132 @@ static MapEntry* parse_line(char* line) { MapEntry* entry = new MapEntry(start, end, offset, name, name_len, flags); if (!(flags & PROT_READ)) { - // Any unreadable map will just get a zero load bias. - entry->load_bias = 0; - entry->init = true; - entry->valid = false; + // This will make sure that an unreadable map will prevent attempts to read + // elf data from the map. + entry->SetInvalid(); } return entry; } -template <typename T> -static inline bool get_val(MapEntry* entry, uintptr_t addr, T* store) { - if (!(entry->flags & PROT_READ) || addr < entry->start || addr + sizeof(T) > entry->end) { - return false; +void MapEntry::Init() { + if (init_) { + return; } - // Make sure the address is aligned properly. - if (addr & (sizeof(T) - 1)) { - return false; + init_ = true; + + uintptr_t end_addr; + if (__builtin_add_overflow(start_, SELFMAG, &end_addr) || end_addr >= end_) { + return; } - *store = *reinterpret_cast<T*>(addr); - return true; + + ElfW(Ehdr) ehdr; + struct iovec src_io = {.iov_base = reinterpret_cast<void*>(start_), .iov_len = SELFMAG}; + struct iovec dst_io = {.iov_base = ehdr.e_ident, .iov_len = SELFMAG}; + ssize_t rc = process_vm_readv(getpid(), &dst_io, 1, &src_io, 1, 0); + valid_ = rc == SELFMAG && IS_ELF(ehdr); } -static bool valid_elf(MapEntry* entry) { - uintptr_t addr = entry->start; - uintptr_t end; - if (__builtin_add_overflow(addr, SELFMAG, &end) || end >= entry->end) { - return false; +uintptr_t MapEntry::GetLoadBias() { + if (!valid_) { + return 0; } - return memcmp(reinterpret_cast<void*>(addr), ELFMAG, SELFMAG) == 0; -} + if (load_bias_read_) { + return load_bias_; + } + + load_bias_read_ = true; -static void read_loadbias(MapEntry* entry) { - entry->load_bias = 0; - uintptr_t addr = entry->start; ElfW(Ehdr) ehdr; - if (!get_val<ElfW(Half)>(entry, addr + offsetof(ElfW(Ehdr), e_phnum), &ehdr.e_phnum)) { - return; - } - if (!get_val<ElfW(Off)>(entry, addr + offsetof(ElfW(Ehdr), e_phoff), &ehdr.e_phoff)) { - return; + struct iovec src_io = {.iov_base = reinterpret_cast<void*>(start_), .iov_len = sizeof(ehdr)}; + struct iovec dst_io = {.iov_base = &ehdr, .iov_len = sizeof(ehdr)}; + ssize_t rc = process_vm_readv(getpid(), &dst_io, 1, &src_io, 1, 0); + if (rc != sizeof(ehdr)) { + return 0; } - addr += ehdr.e_phoff; + + uintptr_t addr = start_ + ehdr.e_phoff; for (size_t i = 0; i < ehdr.e_phnum; i++) { ElfW(Phdr) phdr; - if (!get_val<ElfW(Word)>(entry, addr + offsetof(ElfW(Phdr), p_type), &phdr.p_type)) { - return; - } - if (!get_val<ElfW(Word)>(entry, addr + offsetof(ElfW(Phdr), p_flags), &phdr.p_flags)) { - return; - } - if (!get_val<ElfW(Off)>(entry, addr + offsetof(ElfW(Phdr), p_offset), &phdr.p_offset)) { - return; + + src_io.iov_base = reinterpret_cast<void*>(addr); + src_io.iov_len = sizeof(phdr); + dst_io.iov_base = &phdr; + dst_io.iov_len = sizeof(phdr); + rc = process_vm_readv(getpid(), &dst_io, 1, &src_io, 1, 0); + if (rc != sizeof(phdr)) { + return 0; } if ((phdr.p_type == PT_LOAD) && (phdr.p_flags & PF_X) ) { - if (!get_val<ElfW(Addr)>(entry, addr + offsetof(ElfW(Phdr), p_vaddr), &phdr.p_vaddr)) { - return; - } - entry->load_bias = phdr.p_vaddr - phdr.p_offset; - return; + load_bias_ = phdr.p_vaddr - phdr.p_offset; + return load_bias_; } addr += sizeof(phdr); } + return 0; } -static void inline init(MapEntry* entry) { - if (entry->init) { - return; - } - entry->init = true; - if (valid_elf(entry)) { - entry->valid = true; - read_loadbias(entry); - } -} - -bool MapData::ReadMaps() { +void MapData::ReadMaps() { + std::lock_guard<std::mutex> lock(m_); FILE* fp = fopen("/proc/self/maps", "re"); if (fp == nullptr) { - return false; + return; } + ClearEntries(); + std::vector<char> buffer(1024); while (fgets(buffer.data(), buffer.size(), fp) != nullptr) { MapEntry* entry = parse_line(buffer.data()); if (entry == nullptr) { - fclose(fp); - return false; - } - - auto it = entries_.find(entry); - if (it == entries_.end()) { - entries_.insert(entry); - } else { - delete entry; + break; } + entries_.insert(entry); } fclose(fp); - return true; } -MapData::~MapData() { +void MapData::ClearEntries() { for (auto* entry : entries_) { delete entry; } entries_.clear(); } +MapData::~MapData() { + ClearEntries(); +} + // Find the containing map info for the PC. const MapEntry* MapData::find(uintptr_t pc, uintptr_t* rel_pc) { MapEntry pc_entry(pc); std::lock_guard<std::mutex> lock(m_); - auto it = entries_.find(&pc_entry); if (it == entries_.end()) { - ReadMaps(); - } - it = entries_.find(&pc_entry); - if (it == entries_.end()) { return nullptr; } MapEntry* entry = *it; - init(entry); + entry->Init(); if (rel_pc != nullptr) { // Need to check to see if this is a read-execute map and the read-only // map is the previous one. - if (!entry->valid && it != entries_.begin()) { + if (!entry->valid() && it != entries_.begin()) { MapEntry* prev_entry = *--it; - if (prev_entry->flags == PROT_READ && prev_entry->offset < entry->offset && - prev_entry->name == entry->name) { - init(prev_entry); + if (prev_entry->flags() == PROT_READ && prev_entry->offset() < entry->offset() && + prev_entry->name() == entry->name()) { + prev_entry->Init(); - if (prev_entry->valid) { - entry->elf_start_offset = prev_entry->offset; - *rel_pc = pc - entry->start + entry->offset + prev_entry->load_bias; + if (prev_entry->valid()) { + entry->set_elf_start_offset(prev_entry->offset()); + *rel_pc = pc - entry->start() + entry->offset() + prev_entry->GetLoadBias(); return entry; } } } - *rel_pc = pc - entry->start + entry->offset + entry->load_bias; + *rel_pc = pc - entry->start() + entry->offset() + entry->GetLoadBias(); } return entry; } diff --git a/libc/malloc_debug/MapData.h b/libc/malloc_debug/MapData.h index f2b3c1cfe..13bf9cbea 100644 --- a/libc/malloc_debug/MapData.h +++ b/libc/malloc_debug/MapData.h @@ -36,26 +36,50 @@ #include <platform/bionic/macros.h> -struct MapEntry { - MapEntry(uintptr_t start, uintptr_t end, uintptr_t offset, const char* name, size_t name_len, int flags) - : start(start), end(end), offset(offset), name(name, name_len), flags(flags) {} - - explicit MapEntry(uintptr_t pc) : start(pc), end(pc) {} - - uintptr_t start; - uintptr_t end; - uintptr_t offset; - uintptr_t load_bias; - uintptr_t elf_start_offset = 0; - std::string name; - int flags; - bool init = false; - bool valid = false; +class MapEntry { + public: + MapEntry() = default; + MapEntry(uintptr_t start, uintptr_t end, uintptr_t offset, const char* name, size_t name_len, + int flags) + : start_(start), end_(end), offset_(offset), name_(name, name_len), flags_(flags) {} + + explicit MapEntry(uintptr_t pc) : start_(pc), end_(pc) {} + + void Init(); + + uintptr_t GetLoadBias(); + + void SetInvalid() { + valid_ = false; + init_ = true; + load_bias_read_ = true; + } + + bool valid() { return valid_; } + uintptr_t start() const { return start_; } + uintptr_t end() const { return end_; } + uintptr_t offset() const { return offset_; } + uintptr_t elf_start_offset() const { return elf_start_offset_; } + void set_elf_start_offset(uintptr_t elf_start_offset) { elf_start_offset_ = elf_start_offset; } + const std::string& name() const { return name_; } + int flags() const { return flags_; } + + private: + uintptr_t start_; + uintptr_t end_; + uintptr_t offset_; + uintptr_t load_bias_ = 0; + uintptr_t elf_start_offset_ = 0; + std::string name_; + int flags_; + bool init_ = false; + bool valid_ = false; + bool load_bias_read_ = false; }; // Ordering comparator that returns equivalence for overlapping entries struct compare_entries { - bool operator()(const MapEntry* a, const MapEntry* b) const { return a->end <= b->start; } + bool operator()(const MapEntry* a, const MapEntry* b) const { return a->end() <= b->start(); } }; class MapData { @@ -65,11 +89,15 @@ class MapData { const MapEntry* find(uintptr_t pc, uintptr_t* rel_pc = nullptr); - private: - bool ReadMaps(); + size_t NumMaps() { return entries_.size(); } + void ReadMaps(); + + private: std::mutex m_; std::set<MapEntry*, compare_entries> entries_; + void ClearEntries(); + BIONIC_DISALLOW_COPY_AND_ASSIGN(MapData); }; diff --git a/libc/malloc_debug/backtrace.cpp b/libc/malloc_debug/backtrace.cpp index ecb3a80a0..6a32fcaff 100644 --- a/libc/malloc_debug/backtrace.cpp +++ b/libc/malloc_debug/backtrace.cpp @@ -50,7 +50,7 @@ typedef struct _Unwind_Context __unwind_context; static MapData g_map_data; -static const MapEntry* g_current_code_map = nullptr; +static MapEntry g_current_code_map; static _Unwind_Reason_Code find_current_map(__unwind_context* context, void*) { uintptr_t ip = _Unwind_GetIP(context); @@ -58,11 +58,15 @@ static _Unwind_Reason_Code find_current_map(__unwind_context* context, void*) { if (ip == 0) { return _URC_END_OF_STACK; } - g_current_code_map = g_map_data.find(ip); + auto map = g_map_data.find(ip); + if (map != nullptr) { + g_current_code_map = *map; + } return _URC_END_OF_STACK; } void backtrace_startup() { + g_map_data.ReadMaps(); _Unwind_Backtrace(find_current_map, nullptr); } @@ -98,7 +102,8 @@ static _Unwind_Reason_Code trace_function(__unwind_context* context, void* arg) } // Do not record the frames that fall in our own shared library. - if (g_current_code_map && (ip >= g_current_code_map->start) && ip < g_current_code_map->end) { + if (g_current_code_map.start() != 0 && (ip >= g_current_code_map.start()) && + ip < g_current_code_map.end()) { return _URC_NO_REASON; } @@ -113,6 +118,10 @@ size_t backtrace_get(uintptr_t* frames, size_t frame_count) { } std::string backtrace_string(const uintptr_t* frames, size_t frame_count) { + if (g_map_data.NumMaps() == 0) { + g_map_data.ReadMaps(); + } + std::string str; for (size_t frame_num = 0; frame_num < frame_count; frame_num++) { @@ -130,14 +139,15 @@ std::string backtrace_string(const uintptr_t* frames, size_t frame_count) { uintptr_t rel_pc = offset; const MapEntry* entry = g_map_data.find(frames[frame_num], &rel_pc); - const char* soname = (entry != nullptr) ? entry->name.c_str() : info.dli_fname; + const char* soname = (entry != nullptr) ? entry->name().c_str() : info.dli_fname; if (soname == nullptr) { soname = "<unknown>"; } char offset_buf[128]; - if (entry != nullptr && entry->elf_start_offset != 0) { - snprintf(offset_buf, sizeof(offset_buf), " (offset 0x%" PRIxPTR ")", entry->elf_start_offset); + if (entry != nullptr && entry->elf_start_offset() != 0) { + snprintf(offset_buf, sizeof(offset_buf), " (offset 0x%" PRIxPTR ")", + entry->elf_start_offset()); } else { offset_buf[0] = '\0'; } @@ -167,5 +177,6 @@ std::string backtrace_string(const uintptr_t* frames, size_t frame_count) { } void backtrace_log(const uintptr_t* frames, size_t frame_count) { + g_map_data.ReadMaps(); error_log_string(backtrace_string(frames, frame_count).c_str()); } diff --git a/libc/platform/bionic/malloc.h b/libc/platform/bionic/malloc.h index ffc6d4a43..da85cf526 100644 --- a/libc/platform/bionic/malloc.h +++ b/libc/platform/bionic/malloc.h @@ -130,36 +130,55 @@ typedef struct { // Worth noting, the "libc.debug.gwp_asan.*.app_default" sysprops *do not* // apply to system apps. They use the "libc.debug.gwp_asan.*.system_default" // sysprops. - enum Action { - // Enable GWP-ASan. This is used by apps that have `gwpAsanMode=always` in - // the manifest. - TURN_ON_FOR_APP, - // Enable GWP-ASan, but only a small percentage of the time. This is used by - // system processes and system apps, and we use a lottery to determine which - // processes have GWP-ASan enabled. This allows us to mitigate system-wide - // memory overhead concerns, as each GWP-ASan enabled process uses ~70KiB of - // extra memory. - TURN_ON_WITH_SAMPLING, - // Don't enable GWP-ASan, unless overwritten by a system property or - // environment variable. This is used by apps that have `gwpAsanMode=never` - // in the manifest. Prior to Android 14, this also was used by non-system - // apps that didn't specify a `gwpAsanMode` in their manifest. - DONT_TURN_ON_UNLESS_OVERRIDDEN, - // Enable GWP-ASan, but only a small percentage of the time, and enable it - // in the non-crashing ("recoverable") mode. In Android 14, this is used by - // apps that don't specify `gwpAsanMode` (or use `gwpAsanMode=default`) in - // their manifest. GWP-ASan will detect heap memory safety bugs in this - // mode, and bug reports will be created by debuggerd, however the process - // will recover and continue to function as if the memory safety bug wasn't - // detected. + // + // In recoverable mode, GWP-ASan will detect heap memory safety bugs, and bug + // reports will be created by debuggerd, however the process will recover and + // continue to function as if the memory safety bug wasn't detected. This + // prevents any user-visible impact as apps and processes don't crash, and + // probably saves us some CPU time in restarting the process. + // + // Process sampling enables GWP-ASan, but only a small percentage of the time + // (~1%). This helps mitigate any recurring high-frequency problems in certain + // processes, as it's highly likely the next restart of said process won't + // have GWP-ASan. In addition, for system processes and system apps, this + // allows us to mitigate system-wide memory overhead concerns, as each + // GWP-ASan enabled process uses ~70KiB of extra memory. + enum Mode { + // Used by default for apps, or by those that have an explicit + // `gwpAsanMode=default` in the manifest. + // + // Result: + // - Android 13 and before: GWP-ASan is not enabled. + // - Android 14 and after: Enables GWP-ASan with process sampling in + // recoverable mode. + APP_MANIFEST_DEFAULT = 3, + // This is used by apps that have `gwpAsanMode=always` in the manifest. + // + // Result: + // - Android 14 and before: Enables GWP-ASan in non-recoverable mode, + // without process sampling. + // - Android 15 and after: Enables GWP-ASan in recoverable mode, without + // process sampling. + APP_MANIFEST_ALWAYS = 0, + // This is used by apps that have `gwpAsanMode=never` in the manifest. + // + // Result: + // - GWP-ASan is not enabled, unless it's force-enabled by a system + // property or environment variable. + APP_MANIFEST_NEVER = 2, + // Used by system processes and system apps. // - // In Android 15, this is the same as TURN_ON_WITH_SAMPLING, as GWP-ASan is - // only ever used in non-crashing mode (even for platform executables and - // system apps). - TURN_ON_FOR_APP_SAMPLED_NON_CRASHING, + // Result: + // - Android 14 and before: Enables GWP-ASan with process sampling in + // non-recoverable mode. + // - Android 15 and after: Enables GWP-ASan with process sampling in + // recoverable mode. + SYSTEM_PROCESS_OR_SYSTEM_APP = 1, + // Next enum value = 4. Numbered non-sequentially above to preserve ABI + // stability, but now ordered more logically. }; - Action desire = DONT_TURN_ON_UNLESS_OVERRIDDEN; + Mode mode = APP_MANIFEST_NEVER; } android_mallopt_gwp_asan_options_t; #pragma clang diagnostic pop // Manipulates bionic-specific handling of memory allocation APIs such as diff --git a/libc/platform/bionic/page.h b/libc/platform/bionic/page.h index 65faba4f0..4dbe4baea 100644 --- a/libc/platform/bionic/page.h +++ b/libc/platform/bionic/page.h @@ -32,11 +32,13 @@ inline size_t page_size() { #endif } -constexpr size_t max_page_size() { +// The maximum page size supported on any Android device. As +// of API level 35, this is limited by ART. +constexpr size_t max_android_page_size() { #if defined(PAGE_SIZE) return PAGE_SIZE; #else - return 65536; + return 16384; #endif } diff --git a/libc/private/WriteProtected.h b/libc/private/WriteProtected.h index bbe35e529..f26912546 100644 --- a/libc/private/WriteProtected.h +++ b/libc/private/WriteProtected.h @@ -30,11 +30,11 @@ template <typename T> union WriteProtectedContents { T value; - char padding[max_page_size()]; + char padding[max_android_page_size()]; WriteProtectedContents() = default; BIONIC_DISALLOW_COPY_AND_ASSIGN(WriteProtectedContents); -} __attribute__((aligned(max_page_size()))); +} __attribute__((aligned(max_android_page_size()))); // Write protected wrapper class that aligns its contents to a page boundary, // and sets the memory protection to be non-writable, except when being modified @@ -42,8 +42,8 @@ union WriteProtectedContents { template <typename T> class WriteProtected { public: - static_assert(sizeof(T) < max_page_size(), - "WriteProtected only supports contents up to max_page_size()"); + static_assert(sizeof(T) < max_android_page_size(), + "WriteProtected only supports contents up to max_android_page_size()"); WriteProtected() = default; BIONIC_DISALLOW_COPY_AND_ASSIGN(WriteProtected); @@ -89,7 +89,7 @@ class WriteProtected { // ourselves. addr = untag_address(addr); #endif - if (mprotect(reinterpret_cast<void*>(addr), max_page_size(), prot) == -1) { + if (mprotect(reinterpret_cast<void*>(addr), max_android_page_size(), prot) == -1) { async_safe_fatal("WriteProtected mprotect %x failed: %s", prot, strerror(errno)); } } diff --git a/libc/system_properties/system_properties.cpp b/libc/system_properties/system_properties.cpp index 1dedb61e7..e0d38a822 100644 --- a/libc/system_properties/system_properties.cpp +++ b/libc/system_properties/system_properties.cpp @@ -337,31 +337,42 @@ int SystemProperties::Update(prop_info* pi, const char* value, unsigned int len) int SystemProperties::Add(const char* name, unsigned int namelen, const char* value, unsigned int valuelen) { - if (valuelen >= PROP_VALUE_MAX && !is_read_only(name)) { + if (namelen < 1) { + async_safe_format_log(ANDROID_LOG_ERROR, "libc", + "__system_property_add failed: name length 0"); return -1; } - if (namelen < 1) { + if (valuelen >= PROP_VALUE_MAX && !is_read_only(name)) { + async_safe_format_log(ANDROID_LOG_ERROR, "libc", + "__system_property_add failed: \"%s\" value too long: %d >= PROP_VALUE_MAX", + name, valuelen); return -1; } if (!initialized_) { + async_safe_format_log(ANDROID_LOG_ERROR, "libc", + "__system_property_add failed: properties not initialized"); return -1; } prop_area* serial_pa = contexts_->GetSerialPropArea(); if (serial_pa == nullptr) { + async_safe_format_log(ANDROID_LOG_ERROR, "libc", + "__system_property_add failed: property area not found"); return -1; } prop_area* pa = contexts_->GetPropAreaForName(name); if (!pa) { - async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied adding property \"%s\"", name); + async_safe_format_log(ANDROID_LOG_ERROR, "libc", + "__system_property_add failed: access denied for \"%s\"", name); return -1; } - bool ret = pa->add(name, namelen, value, valuelen); - if (!ret) { + if (!pa->add(name, namelen, value, valuelen)) { + async_safe_format_log(ANDROID_LOG_ERROR, "libc", + "__system_property_add failed: add failed for \"%s\"", name); return -1; } diff --git a/libc/upstream-openbsd/android/include/openbsd-compat.h b/libc/upstream-openbsd/android/include/openbsd-compat.h index 8e6f87da8..cbc52b539 100644 --- a/libc/upstream-openbsd/android/include/openbsd-compat.h +++ b/libc/upstream-openbsd/android/include/openbsd-compat.h @@ -42,23 +42,8 @@ extern const char* __progname; #define PROTO_NORMAL(x) -/* OpenBSD's <ctype.h> uses these names, which conflicted with stlport. - * Additionally, we changed the numeric/digit type from N to D for libcxx. - */ -#define _U _CTYPE_U -#define _L _CTYPE_L -#define _N _CTYPE_D -#define _S _CTYPE_S -#define _P _CTYPE_P -#define _C _CTYPE_C -#define _X _CTYPE_X -#define _B _CTYPE_B - -/* OpenBSD has this, but we can't really implement it correctly on Linux. */ -#define issetugid() 0 - #if !defined(ANDROID_HOST_MUSL) -#define explicit_bzero(p, s) memset(p, 0, s) +#define explicit_bzero(p, s) memset_explicit(p, 0, s) #endif #if defined(ANDROID_HOST_MUSL) diff --git a/libc/upstream-openbsd/lib/libc/crypt/arc4random.c b/libc/upstream-openbsd/lib/libc/crypt/arc4random.c index 8a4ecc9e8..0737cf3fb 100644 --- a/libc/upstream-openbsd/lib/libc/crypt/arc4random.c +++ b/libc/upstream-openbsd/lib/libc/crypt/arc4random.c @@ -1,4 +1,4 @@ -/* $OpenBSD: arc4random.c,v 1.54 2015/09/13 08:31:47 guenther Exp $ */ +/* $OpenBSD: arc4random.c,v 1.58 2022/07/31 13:41:45 tb Exp $ */ /* * Copyright (c) 1996, David Mazieres <dm@uun.org> @@ -49,6 +49,8 @@ #define BLOCKSZ 64 #define RSBUFSZ (16*BLOCKSZ) +#define REKEY_BASE (1024*1024) /* NB. should be a power of 2 */ + /* Marked MAP_INHERIT_ZERO, so zero'd out in fork children. */ static struct _rs { size_t rs_have; /* valid bytes at end of rs_buf */ @@ -78,7 +80,7 @@ _rs_init(u_char *buf, size_t n) abort(); } - chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8, 0); + chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8); chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ); } @@ -86,6 +88,7 @@ static void _rs_stir(void) { u_char rnd[KEYSZ + IVSZ]; + uint32_t rekey_fuzz = 0; if (getentropy(rnd, sizeof rnd) == -1) _getentropy_fail(); @@ -100,7 +103,10 @@ _rs_stir(void) rs->rs_have = 0; memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); - rs->rs_count = 1600000; + /* rekey interval should not be predictable */ + chacha_encrypt_bytes(&rsx->rs_chacha, (uint8_t *)&rekey_fuzz, + (uint8_t *)&rekey_fuzz, sizeof(rekey_fuzz)); + rs->rs_count = REKEY_BASE + (rekey_fuzz % REKEY_BASE); } static inline void diff --git a/libc/upstream-openbsd/lib/libc/crypt/chacha_private.h b/libc/upstream-openbsd/lib/libc/crypt/chacha_private.h index 7c3680fa6..b0427b6b3 100644 --- a/libc/upstream-openbsd/lib/libc/crypt/chacha_private.h +++ b/libc/upstream-openbsd/lib/libc/crypt/chacha_private.h @@ -4,7 +4,7 @@ D. J. Bernstein Public domain. */ -/* $OpenBSD: chacha_private.h,v 1.2 2013/10/04 07:02:27 djm Exp $ */ +/* $OpenBSD: chacha_private.h,v 1.3 2022/02/28 21:56:29 dtucker Exp $ */ typedef unsigned char u8; typedef unsigned int u32; @@ -52,7 +52,7 @@ static const char sigma[16] = "expand 32-byte k"; static const char tau[16] = "expand 16-byte k"; static void -chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ivbits) +chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits) { const char *constants; diff --git a/libc/upstream-openbsd/lib/libc/gen/ctype_.c b/libc/upstream-openbsd/lib/libc/gen/ctype_.c index 897224433..9742c9f16 100644 --- a/libc/upstream-openbsd/lib/libc/gen/ctype_.c +++ b/libc/upstream-openbsd/lib/libc/gen/ctype_.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ctype_.c,v 1.12 2015/09/19 04:02:21 guenther Exp $ */ +/* $OpenBSD: ctype_.c,v 1.13 2024/02/04 13:03:18 jca Exp $ */ /* * Copyright (c) 1989 The Regents of the University of California. * All rights reserved. @@ -36,6 +36,16 @@ #include <ctype.h> #include "ctype_private.h" +/* Shorter names for the defines provided by <ctype.h> */ +#define _U _CTYPE_U +#define _L _CTYPE_L +#define _N _CTYPE_N +#define _S _CTYPE_S +#define _P _CTYPE_P +#define _C _CTYPE_C +#define _X _CTYPE_X +#define _B _CTYPE_B + const char _C_ctype_[1 + CTYPE_NUM_CHARS] = { 0, _C, _C, _C, _C, _C, _C, _C, _C, diff --git a/libc/upstream-openbsd/lib/libc/net/htonl.c b/libc/upstream-openbsd/lib/libc/net/htonl.c index 6ee6e7efb..58bfb4699 100644 --- a/libc/upstream-openbsd/lib/libc/net/htonl.c +++ b/libc/upstream-openbsd/lib/libc/net/htonl.c @@ -1,6 +1,5 @@ -/* $OpenBSD: htonl.c,v 1.7 2014/07/21 01:51:10 guenther Exp $ */ +/* $OpenBSD: htonl.c,v 1.8 2024/04/15 14:30:48 naddy Exp $ */ /* - * Written by J.T. Conklin <jtc@netbsd.org>. * Public domain. */ @@ -9,13 +8,8 @@ #undef htonl -u_int32_t -htonl(u_int32_t x) +uint32_t +htonl(uint32_t x) { -#if BYTE_ORDER == LITTLE_ENDIAN - u_char *s = (u_char *)&x; - return (u_int32_t)(s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]); -#else - return x; -#endif + return htobe32(x); } diff --git a/libc/upstream-openbsd/lib/libc/net/htons.c b/libc/upstream-openbsd/lib/libc/net/htons.c index f48d91ee0..28b13cef9 100644 --- a/libc/upstream-openbsd/lib/libc/net/htons.c +++ b/libc/upstream-openbsd/lib/libc/net/htons.c @@ -1,6 +1,5 @@ -/* $OpenBSD: htons.c,v 1.9 2014/07/21 01:51:10 guenther Exp $ */ +/* $OpenBSD: htons.c,v 1.10 2024/04/15 14:30:48 naddy Exp $ */ /* - * Written by J.T. Conklin <jtc@netbsd.org>. * Public domain. */ @@ -9,13 +8,8 @@ #undef htons -u_int16_t -htons(u_int16_t x) +uint16_t +htons(uint16_t x) { -#if BYTE_ORDER == LITTLE_ENDIAN - u_char *s = (u_char *) &x; - return (u_int16_t)(s[0] << 8 | s[1]); -#else - return x; -#endif + return htobe16(x); } diff --git a/libc/upstream-openbsd/lib/libc/net/ntohl.c b/libc/upstream-openbsd/lib/libc/net/ntohl.c index 0d05bac78..7592398e8 100644 --- a/libc/upstream-openbsd/lib/libc/net/ntohl.c +++ b/libc/upstream-openbsd/lib/libc/net/ntohl.c @@ -1,6 +1,5 @@ -/* $OpenBSD: ntohl.c,v 1.7 2014/07/21 01:51:10 guenther Exp $ */ +/* $OpenBSD: ntohl.c,v 1.8 2024/04/15 14:30:48 naddy Exp $ */ /* - * Written by J.T. Conklin <jtc@netbsd.org>. * Public domain. */ @@ -9,13 +8,8 @@ #undef ntohl -u_int32_t -ntohl(u_int32_t x) +uint32_t +ntohl(uint32_t x) { -#if BYTE_ORDER == LITTLE_ENDIAN - u_char *s = (u_char *)&x; - return (u_int32_t)(s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]); -#else - return x; -#endif + return be32toh(x); } diff --git a/libc/upstream-openbsd/lib/libc/net/ntohs.c b/libc/upstream-openbsd/lib/libc/net/ntohs.c index b5ea361f8..ef22ea306 100644 --- a/libc/upstream-openbsd/lib/libc/net/ntohs.c +++ b/libc/upstream-openbsd/lib/libc/net/ntohs.c @@ -1,6 +1,5 @@ -/* $OpenBSD: ntohs.c,v 1.9 2014/07/21 01:51:10 guenther Exp $ */ +/* $OpenBSD: ntohs.c,v 1.10 2024/04/15 14:30:48 naddy Exp $ */ /* - * Written by J.T. Conklin <jtc@netbsd.org>. * Public domain. */ @@ -9,13 +8,8 @@ #undef ntohs -u_int16_t -ntohs(u_int16_t x) +uint16_t +ntohs(uint16_t x) { -#if BYTE_ORDER == LITTLE_ENDIAN - u_char *s = (u_char *) &x; - return (u_int16_t)(s[0] << 8 | s[1]); -#else - return x; -#endif + return be16toh(x); } diff --git a/libc/upstream-openbsd/lib/libc/stdio/fvwrite.c b/libc/upstream-openbsd/lib/libc/stdio/fvwrite.c index d83de8845..d615245ab 100644 --- a/libc/upstream-openbsd/lib/libc/stdio/fvwrite.c +++ b/libc/upstream-openbsd/lib/libc/stdio/fvwrite.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fvwrite.c,v 1.21 2023/10/06 16:41:02 millert Exp $ */ +/* $OpenBSD: fvwrite.c,v 1.22 2024/04/28 14:28:02 millert Exp $ */ /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -31,6 +31,7 @@ * SUCH DAMAGE. */ +#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -76,11 +77,12 @@ __sfvwrite(FILE *fp, struct __suio *uio) } if (fp->_flags & __SNBF) { /* - * Unbuffered: write up to BUFSIZ bytes at a time. + * Unbuffered: write up to INT_MAX bytes at a time, to not + * truncate the value of len if it is greater than 2^31 bytes. */ do { GETIOV(;); - w = (*fp->_write)(fp->_cookie, p, MIN(len, BUFSIZ)); + w = (*fp->_write)(fp->_cookie, p, MIN(len, INT_MAX)); if (w <= 0) goto err; p += w; @@ -90,7 +92,8 @@ __sfvwrite(FILE *fp, struct __suio *uio) /* * Fully buffered: fill partially full buffer, if any, * and then flush. If there is no partial buffer, write - * one _bf._size byte chunk directly (without copying). + * entire payload directly (without copying) up to a + * multiple of the buffer size. * * String output is a special case: write as many bytes * as fit, but pretend we wrote everything. This makes @@ -134,7 +137,15 @@ __sfvwrite(FILE *fp, struct __suio *uio) if (__sflush(fp)) goto err; } else if (len >= (w = fp->_bf._size)) { - /* write directly */ + /* + * Write directly up to INT_MAX or greatest + * multiple of buffer size (whichever is + * smaller), keeping in the memory buffer the + * remaining part of payload that is smaller + * than buffer size. + */ + if (w != 0) + w = MIN(w * (len / w), INT_MAX); w = (*fp->_write)(fp->_cookie, p, w); if (w <= 0) goto err; diff --git a/libdl/libdl_cfi.cpp b/libdl/libdl_cfi.cpp index 23cd7f53a..8adc342ac 100644 --- a/libdl/libdl_cfi.cpp +++ b/libdl/libdl_cfi.cpp @@ -26,15 +26,15 @@ __attribute__((__weak__, visibility("default"))) extern "C" void __loader_cfi_fa // dlopen/dlclose. static struct { uintptr_t v; - char padding[max_page_size() - sizeof(v)]; -} shadow_base_storage alignas(max_page_size()); + char padding[max_android_page_size() - sizeof(v)]; +} shadow_base_storage alignas(max_android_page_size()); // __cfi_init is called by the loader as soon as the shadow is mapped. This may happen very early // during startup, before libdl.so global constructors, and, on i386, even before __libc_sysinfo is // initialized. This function should not do any system calls. extern "C" uintptr_t* __cfi_init(uintptr_t shadow_base) { shadow_base_storage.v = shadow_base; - static_assert(sizeof(shadow_base_storage) == max_page_size(), ""); + static_assert(sizeof(shadow_base_storage) == max_android_page_size(), ""); return &shadow_base_storage.v; } diff --git a/linker/linker_crt_pad_segment_test.cpp b/linker/linker_crt_pad_segment_test.cpp index 5a219f8ee..c11df50fe 100644 --- a/linker/linker_crt_pad_segment_test.cpp +++ b/linker/linker_crt_pad_segment_test.cpp @@ -72,13 +72,22 @@ bool GetPadSegment(const std::string& elf_path) { }; // anonymous namespace TEST(crt_pad_segment, note_absent) { + if (!page_size_migration_supported()) { + GTEST_SKIP() << "Kernel does not support page size migration"; + } ASSERT_FALSE(GetPadSegment("no_crt_pad_segment.so")); } TEST(crt_pad_segment, note_present_and_enabled) { + if (!page_size_migration_supported()) { + GTEST_SKIP() << "Kernel does not support page size migration"; + } ASSERT_TRUE(GetPadSegment("crt_pad_segment_enabled.so")); } TEST(crt_pad_segment, note_present_and_disabled) { + if (!page_size_migration_supported()) { + GTEST_SKIP() << "Kernel does not support page size migration"; + } ASSERT_FALSE(GetPadSegment("crt_pad_segment_disabled.so")); } diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp index f966e04db..e27fd9175 100644 --- a/linker/linker_main.cpp +++ b/linker/linker_main.cpp @@ -221,14 +221,10 @@ static ExecutableInfo get_executable_info(const char* arg_path) { exe_path = arg_path; } - // Path might be a symlink + // Path might be a symlink; we need the target so that we get the right + // linker configuration later. char sym_path[PATH_MAX]; - auto ret = realpath(exe_path, sym_path); - if (ret != nullptr) { - result.path = std::string(sym_path, strlen(sym_path)); - } else { - result.path = std::string(exe_path, strlen(exe_path)); - } + result.path = std::string(realpath(exe_path, sym_path) != nullptr ? sym_path : exe_path); result.phdr = reinterpret_cast<const ElfW(Phdr)*>(getauxval(AT_PHDR)); result.phdr_count = getauxval(AT_PHNUM); @@ -426,20 +422,11 @@ static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base); - // We haven't supported non-PIE since Lollipop for security reasons. + // For security reasons we dropped non-PIE support in API level 21, + // and the NDK no longer supports earlier API levels. if (elf_hdr->e_type != ET_DYN) { - // We don't use async_safe_fatal here because we don't want a tombstone: - // even after several years we still find ourselves on app compatibility - // investigations because some app's trying to launch an executable that - // hasn't worked in at least three years, and we've "helpfully" dropped a - // tombstone for them. The tombstone never provided any detail relevant to - // fixing the problem anyway, and the utility of drawing extra attention - // to the problem is non-existent at this late date. - async_safe_format_fd(STDERR_FILENO, - "\"%s\": error: Android 5.0 and later only support " - "position-independent executables (-fPIE).\n", - g_argv[0]); - _exit(EXIT_FAILURE); + __linker_error("error: %s: Android only supports position-independent " + "executables (-fPIE)\n", exe_info.path.c_str()); } // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid). diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp index ef7671cee..b9229caef 100644 --- a/linker/linker_phdr.cpp +++ b/linker/linker_phdr.cpp @@ -46,6 +46,8 @@ #include "private/CFIShadow.h" // For kLibraryAlignment #include "private/elf_note.h" +#include <android-base/file.h> + static int GetTargetElfMachine() { #if defined(__arm__) return EM_ARM; @@ -296,7 +298,6 @@ bool ElfReader::VerifyElfHeader() { } if (header_.e_shentsize != sizeof(ElfW(Shdr))) { - // Fail if app is targeting Android O or above if (get_application_target_sdk_version() >= 26) { DL_ERR_AND_LOG("\"%s\" has unsupported e_shentsize: 0x%x (expected 0x%zx)", name_.c_str(), header_.e_shentsize, sizeof(ElfW(Shdr))); @@ -310,12 +311,10 @@ bool ElfReader::VerifyElfHeader() { } if (header_.e_shstrndx == 0) { - // Fail if app is targeting Android O or above if (get_application_target_sdk_version() >= 26) { DL_ERR_AND_LOG("\"%s\" has invalid e_shstrndx", name_.c_str()); return false; } - DL_WARN_documented_change(26, "invalid-elf-header_section-headers-enforced-for-api-level-26", "\"%s\" has invalid e_shstrndx", name_.c_str()); @@ -707,8 +706,28 @@ bool ElfReader::ReserveAddressSpace(address_space_params* address_space) { return true; } +/* + * Returns true if the kernel supports page size migration, else false. + */ +bool page_size_migration_supported() { + static bool pgsize_migration_enabled = []() { + std::string enabled; + if (!android::base::ReadFileToString("/sys/kernel/mm/pgsize_migration/enabled", &enabled)) { + return false; + } + return enabled.find("1") != std::string::npos; + }(); + return pgsize_migration_enabled; +} + // Find the ELF note of type NT_ANDROID_TYPE_PAD_SEGMENT and check that the desc value is 1. bool ElfReader::ReadPadSegmentNote() { + if (!page_size_migration_supported()) { + // Don't attempt to read the note, since segment extension isn't + // supported; but return true so that loading can continue normally. + return true; + } + // The ELF can have multiple PT_NOTE's, check them all for (size_t i = 0; i < phdr_num_; ++i) { const ElfW(Phdr)* phdr = &phdr_table_[i]; @@ -773,7 +792,16 @@ static inline void _extend_load_segment_vma(const ElfW(Phdr)* phdr_table, size_t const ElfW(Phdr)* next = nullptr; size_t next_idx = phdr_idx + 1; - if (phdr->p_align == kPageSize || !should_pad_segments) { + // Don't do segment extension for p_align > 64KiB, such ELFs already existed in the + // field e.g. 2MiB p_align for THPs and are relatively small in number. + // + // The kernel can only represent padding for p_align up to 64KiB. This is because + // the kernel uses 4 available bits in the vm_area_struct to represent padding + // extent; and so cannot enable mitigations to avoid breaking app compatibility for + // p_aligns > 64KiB. + // + // Don't perform segment extension on these to avoid app compatibility issues. + if (phdr->p_align <= kPageSize || phdr->p_align > 64*1024 || !should_pad_segments) { return; } @@ -887,10 +915,28 @@ bool ElfReader::LoadSegments() { // 2) Break the COW backing, faulting in new anon pages for a region // that will not be used. - // _seg_file_end = unextended seg_file_end - uint64_t _seg_file_end = seg_start + phdr->p_filesz; - if ((phdr->p_flags & PF_W) != 0 && page_offset(_seg_file_end) > 0) { - memset(reinterpret_cast<void*>(_seg_file_end), 0, kPageSize - page_offset(_seg_file_end)); + uint64_t unextended_seg_file_end = seg_start + phdr->p_filesz; + if ((phdr->p_flags & PF_W) != 0 && page_offset(unextended_seg_file_end) > 0) { + memset(reinterpret_cast<void*>(unextended_seg_file_end), 0, + kPageSize - page_offset(unextended_seg_file_end)); + } + + // Pages may be brought in due to readahead. + // Drop the padding (zero) pages, to avoid reclaim work later. + // + // NOTE: The madvise() here is special, as it also serves to hint to the + // kernel the portion of the LOAD segment that is padding. + // + // See: [1] https://android-review.googlesource.com/c/kernel/common/+/3032411 + // [2] https://android-review.googlesource.com/c/kernel/common/+/3048835 + uint64_t pad_start = page_end(unextended_seg_file_end); + uint64_t pad_end = page_end(seg_file_end); + CHECK(pad_start <= pad_end); + uint64_t pad_len = pad_end - pad_start; + if (page_size_migration_supported() && pad_len > 0 && + madvise(reinterpret_cast<void*>(pad_start), pad_len, MADV_DONTNEED)) { + DL_WARN("\"%s\": madvise(0x%" PRIx64 ", 0x%" PRIx64 ", MADV_DONTNEED) failed: %m", + name_.c_str(), pad_start, pad_len); } seg_file_end = page_end(seg_file_end); diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h index 61242eb4c..aab9018b4 100644 --- a/linker/linker_phdr.h +++ b/linker/linker_phdr.h @@ -154,3 +154,5 @@ void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_co const char* phdr_table_get_interpreter_name(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias); + +bool page_size_migration_supported(); diff --git a/tests/clang_fortify_tests.cpp b/tests/clang_fortify_tests.cpp index 544af4308..f4ef4ac4a 100644 --- a/tests/clang_fortify_tests.cpp +++ b/tests/clang_fortify_tests.cpp @@ -164,9 +164,7 @@ FORTIFY_TEST(string) { const char large_string[] = "Hello!!!"; static_assert(sizeof(large_string) > sizeof(small_buffer), ""); -#if __clang_major__ > 13 - // expected-error@+3{{will always overflow}} -#endif + // expected-error@+2{{will always overflow}} // expected-error@+1{{string bigger than buffer}} EXPECT_FORTIFY_DEATH(strcpy(small_buffer, large_string)); // expected-error@+1{{string bigger than buffer}} @@ -204,9 +202,7 @@ FORTIFY_TEST(string) { static_assert(sizeof(small_string) > sizeof(split.tiny_buffer), ""); #if _FORTIFY_SOURCE > 1 -#if __clang_major__ > 13 - // expected-error@+4{{will always overflow}} -#endif + // expected-error@+3{{will always overflow}} // expected-error@+2{{string bigger than buffer}} #endif EXPECT_FORTIFY_DEATH_STRUCT(strcpy(split.tiny_buffer, small_string)); diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp index 2b48d852b..a5916d318 100644 --- a/tests/malloc_test.cpp +++ b/tests/malloc_test.cpp @@ -678,10 +678,12 @@ TEST(malloc, mallopt_smoke) { TEST(malloc, mallopt_decay) { #if defined(__BIONIC__) SKIP_WITH_HWASAN << "hwasan does not implement mallopt"; + ASSERT_EQ(1, mallopt(M_DECAY_TIME, -1)); ASSERT_EQ(1, mallopt(M_DECAY_TIME, 1)); ASSERT_EQ(1, mallopt(M_DECAY_TIME, 0)); ASSERT_EQ(1, mallopt(M_DECAY_TIME, 1)); ASSERT_EQ(1, mallopt(M_DECAY_TIME, 0)); + ASSERT_EQ(1, mallopt(M_DECAY_TIME, -1)); #else GTEST_SKIP() << "bionic-only test"; #endif @@ -1410,15 +1412,15 @@ TEST(android_mallopt, set_allocation_limit_multiple_threads) { } #if defined(__BIONIC__) -using Action = android_mallopt_gwp_asan_options_t::Action; +using Mode = android_mallopt_gwp_asan_options_t::Mode; TEST(android_mallopt, DISABLED_multiple_enable_gwp_asan) { android_mallopt_gwp_asan_options_t options; options.program_name = ""; // Don't infer GWP-ASan options from sysprops. - options.desire = Action::DONT_TURN_ON_UNLESS_OVERRIDDEN; + options.mode = Mode::APP_MANIFEST_NEVER; // GWP-ASan should already be enabled. Trying to enable or disable it should // always pass. ASSERT_TRUE(android_mallopt(M_INITIALIZE_GWP_ASAN, &options, sizeof(options))); - options.desire = Action::TURN_ON_WITH_SAMPLING; + options.mode = Mode::APP_MANIFEST_DEFAULT; ASSERT_TRUE(android_mallopt(M_INITIALIZE_GWP_ASAN, &options, sizeof(options))); } #endif // defined(__BIONIC__) @@ -1490,7 +1492,7 @@ TEST(malloc, zero_init) { // release secondary allocations back to the OS) was modified to 0ms/1ms by // mallopt_decay. Ensure that we delay for at least a second before releasing // pages to the OS in order to avoid implicit zeroing by the kernel. - mallopt(M_DECAY_TIME, 1000); + mallopt(M_DECAY_TIME, 1); TestHeapZeroing(/* num_iterations */ 32, [](int iteration) -> int { return 1 << (19 + iteration % 4); }); @@ -1764,6 +1766,10 @@ TEST(android_mallopt, get_decay_time_enabled) { EXPECT_EQ(1, mallopt(M_DECAY_TIME, 1)); EXPECT_TRUE(android_mallopt(M_GET_DECAY_TIME_ENABLED, &value, sizeof(value))); EXPECT_TRUE(value); + + EXPECT_EQ(1, mallopt(M_DECAY_TIME, -1)); + EXPECT_TRUE(android_mallopt(M_GET_DECAY_TIME_ENABLED, &value, sizeof(value))); + EXPECT_FALSE(value); #else GTEST_SKIP() << "bionic-only test"; #endif diff --git a/tests/setjmp_test.cpp b/tests/setjmp_test.cpp index 6ae8bfd3f..0de0a01ba 100644 --- a/tests/setjmp_test.cpp +++ b/tests/setjmp_test.cpp @@ -174,31 +174,23 @@ TEST(setjmp, sigsetjmp_1_signal_mask) { } } -#if defined(__aarch64__) +#if defined(__arm__) +#define SET_FREG(n, v) asm volatile("vmov.f64 d"#n ", #"#v : : : "d"#n) +#define GET_FREG(n) ({ double _r; asm volatile("fcpyd %P0, d"#n : "=w"(_r) : :); _r;}) +#define CLEAR_FREG(n) asm volatile("vmov.i64 d"#n ", #0x0" : : : "d"#n) +#elif defined(__aarch64__) #define SET_FREG(n, v) asm volatile("fmov d"#n ", "#v : : : "d"#n) +#define GET_FREG(n) ({ double _r; asm volatile("fmov %0, d"#n : "=r"(_r) : :); _r; }) #define CLEAR_FREG(n) asm volatile("fmov d"#n ", xzr" : : : "d"#n) +#endif + +#if defined(__arm__) || defined(__aarch64__) #define SET_FREGS \ SET_FREG(8, 8.0); SET_FREG(9, 9.0); SET_FREG(10, 10.0); SET_FREG(11, 11.0); \ SET_FREG(12, 12.0); SET_FREG(13, 13.0); SET_FREG(14, 14.0); SET_FREG(15, 15.0); #define CLEAR_FREGS \ CLEAR_FREG(8); CLEAR_FREG(9); CLEAR_FREG(10); CLEAR_FREG(11); \ CLEAR_FREG(12); CLEAR_FREG(13); CLEAR_FREG(14); CLEAR_FREG(15); -#define GET_FREG(n) ({ double _r; asm volatile("fmov %0, d"#n : "=r"(_r) : :); _r; }) -#define CHECK_FREGS \ - EXPECT_EQ(8.0, GET_FREG(8)); EXPECT_EQ(9.0, GET_FREG(9)); \ - EXPECT_EQ(10.0, GET_FREG(10)); EXPECT_EQ(11.0, GET_FREG(11)); \ - EXPECT_EQ(12.0, GET_FREG(12)); EXPECT_EQ(13.0, GET_FREG(13)); \ - EXPECT_EQ(14.0, GET_FREG(14)); EXPECT_EQ(15.0, GET_FREG(15)); -#elif defined(__arm__) -#define SET_FREG(n, v) \ - ({ const double _v{v}; asm volatile("fcpyd d"#n ", %P0" : : "w"(_v) : "d"#n); }) -#define SET_FREGS \ - SET_FREG(8, 8); SET_FREG(9, 9); SET_FREG(10, 10); SET_FREG(11, 11); \ - SET_FREG(12, 12); SET_FREG(13, 13); SET_FREG(14, 14); SET_FREG(15, 15); -#define CLEAR_FREGS \ - SET_FREG(8, 0); SET_FREG(9, 0); SET_FREG(10, 0); SET_FREG(11, 0); \ - SET_FREG(12, 0); SET_FREG(13, 0); SET_FREG(14, 0); SET_FREG(15, 0); -#define GET_FREG(n) ({ double _r; asm volatile("fcpyd %P0, d"#n : "=w"(_r) : :); _r;}) #define CHECK_FREGS \ EXPECT_EQ(8.0, GET_FREG(8)); EXPECT_EQ(9.0, GET_FREG(9)); \ EXPECT_EQ(10.0, GET_FREG(10)); EXPECT_EQ(11.0, GET_FREG(11)); \ diff --git a/tests/stack_protector_test.cpp b/tests/stack_protector_test.cpp index c4be78c72..aea791c81 100644 --- a/tests/stack_protector_test.cpp +++ b/tests/stack_protector_test.cpp @@ -136,7 +136,7 @@ TEST_F(stack_protector_DeathTest, modify_stack_protector) { if (stack_mte_enabled()) { GTEST_SKIP() << "Stack MTE is enabled, stack protector is not available"; } else if (hwasan_enabled()) { - ASSERT_EXIT(modify_stack_protector_test(), testing::KilledBySignal(SIGABRT), "tag-mismatch"); + GTEST_SKIP() << "HWASan is enabled, stack protector is not testable"; } else { ASSERT_EXIT(modify_stack_protector_test(), testing::KilledBySignal(SIGABRT), "stack corruption detected"); diff --git a/tests/sys_hwprobe_test.cpp b/tests/sys_hwprobe_test.cpp index 6b74e1875..fd59e1ddc 100644 --- a/tests/sys_hwprobe_test.cpp +++ b/tests/sys_hwprobe_test.cpp @@ -33,6 +33,68 @@ #include <sys/syscall.h> #endif + +#if defined(__riscv) +#include <riscv_vector.h> + +__attribute__((noinline)) +uint64_t scalar_cast(uint8_t const* p) { + return *(uint64_t const*)p; +} + +__attribute__((noinline)) +uint64_t scalar_memcpy(uint8_t const* p) { + uint64_t r; + __builtin_memcpy(&r, p, sizeof(r)); + return r; +} + +__attribute__((noinline)) +uint64_t vector_memcpy(uint8_t* d, uint8_t const* p) { + __builtin_memcpy(d, p, 16); + return *(uint64_t const*)d; +} + +__attribute__((noinline)) +uint64_t vector_ldst(uint8_t* d, uint8_t const* p) { + __riscv_vse8(d, __riscv_vle8_v_u8m1(p, 16), 16); + return *(uint64_t const*)d; +} + +__attribute__((noinline)) +uint64_t vector_ldst64(uint8_t* d, uint8_t const* p) { + __riscv_vse64((unsigned long *)d, __riscv_vle64_v_u64m1((const unsigned long *)p, 16), 16); + return *(uint64_t const*)d; +} + +// For testing scalar and vector unaligned accesses. +uint64_t tmp[3] = {1,1,1}; +uint64_t dst[3] = {1,1,1}; +#endif + +TEST(sys_hwprobe, __riscv_hwprobe_misaligned_scalar) { +#if defined(__riscv) + uint8_t* p = (uint8_t*)tmp + 1; + ASSERT_NE(0U, scalar_cast(p)); + ASSERT_NE(0U, scalar_memcpy(p)); +#else + GTEST_SKIP() << "__riscv_hwprobe requires riscv64"; +#endif +} + +TEST(sys_hwprobe, __riscv_hwprobe_misaligned_vector) { +#if defined(__riscv) + uint8_t* p = (uint8_t*)tmp + 1; + uint8_t* d = (uint8_t*)dst + 1; + + ASSERT_NE(0U, vector_ldst(d, p)); + ASSERT_NE(0U, vector_memcpy(d, p)); + ASSERT_NE(0U, vector_ldst64(d, p)); +#else + GTEST_SKIP() << "__riscv_hwprobe requires riscv64"; +#endif +} + TEST(sys_hwprobe, __riscv_hwprobe) { #if defined(__riscv) && __has_include(<sys/hwprobe.h>) riscv_hwprobe probes[] = {{.key = RISCV_HWPROBE_KEY_IMA_EXT_0}, @@ -82,4 +144,4 @@ TEST(sys_hwprobe, __riscv_hwprobe_fail) { #else GTEST_SKIP() << "__riscv_hwprobe requires riscv64"; #endif -} +}
\ No newline at end of file diff --git a/tests/sys_statvfs_test.cpp b/tests/sys_statvfs_test.cpp index 73b2a9681..5dd7b937a 100644 --- a/tests/sys_statvfs_test.cpp +++ b/tests/sys_statvfs_test.cpp @@ -25,7 +25,7 @@ #include <string> template <typename StatVfsT> void Check(StatVfsT& sb) { - EXPECT_EQ(4096U, sb.f_bsize); + EXPECT_EQ(getpagesize(), static_cast<int>(sb.f_bsize)); EXPECT_EQ(0U, sb.f_bfree); EXPECT_EQ(0U, sb.f_ffree); EXPECT_EQ(255U, sb.f_namemax); diff --git a/tests/sys_vfs_test.cpp b/tests/sys_vfs_test.cpp index 96fd61a85..e783190ad 100644 --- a/tests/sys_vfs_test.cpp +++ b/tests/sys_vfs_test.cpp @@ -27,7 +27,7 @@ #include "utils.h" template <typename StatFsT> void Check(StatFsT& sb) { - EXPECT_EQ(4096, static_cast<int>(sb.f_bsize)); + EXPECT_EQ(getpagesize(), static_cast<int>(sb.f_bsize)); EXPECT_EQ(0U, sb.f_bfree); EXPECT_EQ(0U, sb.f_ffree); EXPECT_EQ(255, static_cast<int>(sb.f_namelen)); diff --git a/tests/time_test.cpp b/tests/time_test.cpp index ca8e2608c..baafbf666 100644 --- a/tests/time_test.cpp +++ b/tests/time_test.cpp @@ -31,6 +31,8 @@ #include <thread> #include "SignalUtils.h" +#include "android-base/file.h" +#include "android-base/strings.h" #include "utils.h" using namespace std::chrono_literals; @@ -797,21 +799,41 @@ TEST(time, timer_create_NULL) { ASSERT_EQ(1, timer_create_NULL_signal_handler_invocation_count); } +static int GetThreadCount() { + std::string status; + if (android::base::ReadFileToString("/proc/self/status", &status)) { + for (const auto& line : android::base::Split(status, "\n")) { + int thread_count; + if (sscanf(line.c_str(), "Threads: %d", &thread_count) == 1) { + return thread_count; + } + } + } + return -1; +} + TEST(time, timer_create_EINVAL) { - clockid_t invalid_clock = 16; + const clockid_t kInvalidClock = 16; - // A SIGEV_SIGNAL timer is easy; the kernel does all that. + // A SIGEV_SIGNAL timer failure is easy; that's the kernel's problem. timer_t timer_id; - ASSERT_EQ(-1, timer_create(invalid_clock, nullptr, &timer_id)); + ASSERT_EQ(-1, timer_create(kInvalidClock, nullptr, &timer_id)); ASSERT_ERRNO(EINVAL); - // A SIGEV_THREAD timer is more interesting because we have stuff to clean up. - sigevent se; - memset(&se, 0, sizeof(se)); + // A SIGEV_THREAD timer failure is more interesting because we have a thread + // to clean up (https://issuetracker.google.com/340125671). + sigevent se = {}; se.sigev_notify = SIGEV_THREAD; se.sigev_notify_function = NoOpNotifyFunction; - ASSERT_EQ(-1, timer_create(invalid_clock, &se, &timer_id)); + ASSERT_EQ(-1, timer_create(kInvalidClock, &se, &timer_id)); ASSERT_ERRNO(EINVAL); + + // timer_create() doesn't guarantee that the thread will be dead _before_ + // it returns because that would require extra synchronization that's + // unnecessary in the normal (successful) case. A timeout here means we + // leaked a thread. + while (GetThreadCount() > 1) { + } } TEST(time, timer_create_multiple) { diff --git a/tests/utils.h b/tests/utils.h index dcb08f572..3c83b734d 100644 --- a/tests/utils.h +++ b/tests/utils.h @@ -38,6 +38,7 @@ #endif #include <atomic> +#include <iomanip> #include <string> #include <regex> @@ -253,7 +254,7 @@ class ExecTestHelper { AssertChildExited(pid, expected_exit_status, &error_msg); if (expected_output_regex != nullptr) { if (!std::regex_search(output_, std::regex(expected_output_regex))) { - FAIL() << "regex " << expected_output_regex << " didn't match " << output_; + FAIL() << "regex " << std::quoted(expected_output_regex) << " didn't match " << std::quoted(output_); } } } |