Merge "Switch to the arm-optimized-routines string routines on aarch64 where possible."
diff --git a/benchmarks/Android.bp b/benchmarks/Android.bp
index b4176de..5f8c113 100644
--- a/benchmarks/Android.bp
+++ b/benchmarks/Android.bp
@@ -34,6 +34,7 @@
"inttypes_benchmark.cpp",
"malloc_benchmark.cpp",
"malloc_sql_benchmark.cpp",
+ "malloc_map_benchmark.cpp",
"math_benchmark.cpp",
"property_benchmark.cpp",
"pthread_benchmark.cpp",
@@ -52,6 +53,15 @@
"libtinyxml2",
],
stl: "libc++_static",
+
+ target: {
+ android: {
+ static_libs: [
+ "libmeminfo",
+ "libprocinfo",
+ ],
+ },
+ },
}
cc_defaults {
diff --git a/benchmarks/malloc_map_benchmark.cpp b/benchmarks/malloc_map_benchmark.cpp
new file mode 100644
index 0000000..ba4d62c
--- /dev/null
+++ b/benchmarks/malloc_map_benchmark.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <err.h>
+#include <malloc.h>
+#include <stdint.h>
+
+#include <map>
+#include <unordered_map>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+#include "util.h"
+
+#include <android-base/strings.h>
+
+#if defined(__BIONIC__)
+
+#include <meminfo/procmeminfo.h>
+#include <procinfo/process_map.h>
+
+static void Gather(uint64_t* rss_bytes) {
+ android::meminfo::ProcMemInfo proc_mem(getpid());
+ const std::vector<android::meminfo::Vma>& maps = proc_mem.MapsWithoutUsageStats();
+ for (auto& vma : maps) {
+ if (vma.name == "[anon:libc_malloc]" || android::base::StartsWith(vma.name, "[anon:scudo:") ||
+ android::base::StartsWith(vma.name, "[anon:GWP-ASan")) {
+ android::meminfo::Vma update_vma(vma);
+ if (!proc_mem.FillInVmaStats(update_vma)) {
+ err(1, "FillInVmaStats failed\n");
+ }
+ *rss_bytes += update_vma.usage.rss;
+ }
+ }
+}
+#endif
+
+template <typename MapType>
+static void MapBenchmark(benchmark::State& state, size_t num_elements) {
+#if defined(__BIONIC__)
+ uint64_t rss_bytes = 0;
+#endif
+
+ for (auto _ : state) {
+#if defined(__BIONIC__)
+ state.PauseTiming();
+ mallopt(M_PURGE, 0);
+ uint64_t rss_bytes_before = 0;
+ Gather(&rss_bytes_before);
+ state.ResumeTiming();
+#endif
+ MapType map;
+ for (size_t i = 0; i < num_elements; i++) {
+ map[i][0] = 0;
+ }
+#if defined(__BIONIC__)
+ state.PauseTiming();
+ mallopt(M_PURGE, 0);
+ Gather(&rss_bytes);
+ // Try and record only the memory used in the map.
+ rss_bytes -= rss_bytes_before;
+ state.ResumeTiming();
+#endif
+ }
+
+#if defined(__BIONIC__)
+ double rss_mb = (rss_bytes / static_cast<double>(state.iterations())) / 1024.0 / 1024.0;
+ state.counters["RSS_MB"] = rss_mb;
+#endif
+}
+
+static void BM_std_map_8(benchmark::State& state) {
+ MapBenchmark<std::map<uint64_t, char[8]>>(state, 1000000);
+}
+BIONIC_BENCHMARK(BM_std_map_8);
+
+static void BM_std_map_16(benchmark::State& state) {
+ MapBenchmark<std::map<uint64_t, char[16]>>(state, 1000000);
+}
+BIONIC_BENCHMARK(BM_std_map_16);
+
+static void BM_std_map_32(benchmark::State& state) {
+ MapBenchmark<std::map<uint64_t, char[32]>>(state, 1000000);
+}
+BIONIC_BENCHMARK(BM_std_map_32);
+
+static void BM_std_map_64(benchmark::State& state) {
+ MapBenchmark<std::map<uint64_t, char[64]>>(state, 1000000);
+}
+BIONIC_BENCHMARK(BM_std_map_64);
+
+static void BM_std_map_96(benchmark::State& state) {
+ MapBenchmark<std::map<uint64_t, char[96]>>(state, 1000000);
+}
+BIONIC_BENCHMARK(BM_std_map_96);
+
+static void BM_std_map_128(benchmark::State& state) {
+ MapBenchmark<std::map<uint64_t, char[128]>>(state, 500000);
+}
+BIONIC_BENCHMARK(BM_std_map_128);
+
+static void BM_std_map_256(benchmark::State& state) {
+ MapBenchmark<std::map<uint64_t, char[256]>>(state, 500000);
+}
+BIONIC_BENCHMARK(BM_std_map_256);
+
+static void BM_std_map_512(benchmark::State& state) {
+ MapBenchmark<std::map<uint64_t, char[512]>>(state, 500000);
+}
+BIONIC_BENCHMARK(BM_std_map_512);
+
+static void BM_std_unordered_map_8(benchmark::State& state) {
+ MapBenchmark<std::unordered_map<uint64_t, char[8]>>(state, 1000000);
+}
+BIONIC_BENCHMARK(BM_std_unordered_map_8);
+
+static void BM_std_unordered_map_16(benchmark::State& state) {
+ MapBenchmark<std::unordered_map<uint64_t, char[16]>>(state, 1000000);
+}
+BIONIC_BENCHMARK(BM_std_unordered_map_16);
+
+static void BM_std_unordered_map_32(benchmark::State& state) {
+ MapBenchmark<std::unordered_map<uint64_t, char[32]>>(state, 1000000);
+}
+BIONIC_BENCHMARK(BM_std_unordered_map_32);
+
+static void BM_std_unordered_map_64(benchmark::State& state) {
+ MapBenchmark<std::unordered_map<uint64_t, char[64]>>(state, 1000000);
+}
+BIONIC_BENCHMARK(BM_std_unordered_map_64);
+
+static void BM_std_unordered_map_96(benchmark::State& state) {
+ MapBenchmark<std::unordered_map<uint64_t, char[96]>>(state, 1000000);
+}
+BIONIC_BENCHMARK(BM_std_unordered_map_96);
+
+static void BM_std_unordered_map_128(benchmark::State& state) {
+ MapBenchmark<std::unordered_map<uint64_t, char[128]>>(state, 500000);
+}
+BIONIC_BENCHMARK(BM_std_unordered_map_128);
+
+static void BM_std_unordered_map_256(benchmark::State& state) {
+ MapBenchmark<std::unordered_map<uint64_t, char[256]>>(state, 500000);
+}
+BIONIC_BENCHMARK(BM_std_unordered_map_256);
+
+static void BM_std_unordered_map_512(benchmark::State& state) {
+ MapBenchmark<std::unordered_map<uint64_t, char[512]>>(state, 500000);
+}
+BIONIC_BENCHMARK(BM_std_unordered_map_512);
diff --git a/docs/status.md b/docs/status.md
index 6f358ea..9d3ad88 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -52,8 +52,8 @@
New libc functions in R (API level 30):
* Full C11 `<threads.h>` (available as inlines for older API levels).
- * `memfd_create` and `mlock2` (GNU extensions).
- * `renameat2` (GNU extension).
+ * `memfd_create` and `mlock2` (Linux-specific GNU extensions).
+ * `renameat2` and `statx` (Linux-specific GNU extensions).
* `pthread_cond_clockwait`/`pthread_mutex_clocklock`/`pthread_rwlock_clockrdlock`/`pthread_rwlock_clockwrlock`/`sem_clockwait`
New libc behavior in R (API level 30):
diff --git a/libc/SECCOMP_WHITELIST_COMMON.TXT b/libc/SECCOMP_WHITELIST_COMMON.TXT
index 72ced4f..56f9d1d 100644
--- a/libc/SECCOMP_WHITELIST_COMMON.TXT
+++ b/libc/SECCOMP_WHITELIST_COMMON.TXT
@@ -54,8 +54,6 @@
# Since Linux 4.6, glibc 2.26.
ssize_t preadv2(int fd, const struct iovec* iov, int iovcnt, off_t offset, int flags) all
ssize_t pwritev2(int fd, const struct iovec* iov, int iovcnt, off_t offset, int flags) all
-# Since Linux 4.11, glibc 2.30.
-int statx(int, const char*, int, unsigned int, statx*) all
# Since Linux 5.1, not in glibc.
int clock_gettime64(clockid_t, timespec64*) lp32
int clock_settime64(clockid_t, const timespec64*) lp32
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 571df22..ab309e6 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -208,6 +208,7 @@
ssize_t llistxattr(const char*, char*, size_t) all
int removexattr(const char*, const char*) all
int lremovexattr(const char*, const char*) all
+int statx(int, const char*, int, unsigned, struct statx*) all
int swapon(const char*, int) all
int swapoff(const char*) all
diff --git a/libc/bionic/android_profiling_dynamic.cpp b/libc/bionic/android_profiling_dynamic.cpp
index 183a614..54f896c 100644
--- a/libc/bionic/android_profiling_dynamic.cpp
+++ b/libc/bionic/android_profiling_dynamic.cpp
@@ -36,6 +36,7 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/ucontext.h>
#include <sys/un.h>
#include <async_safe/log.h>
@@ -64,10 +65,10 @@
sigaction(BIONIC_SIGNAL_PROFILER, &action, nullptr);
}
+static void HandleSigsysSeccompOverride(int, siginfo_t*, void*);
static void HandleTracedPerfSignal();
static void HandleProfilingSignal(int /*signal_number*/, siginfo_t* info, void* /*ucontext*/) {
- // Avoid clobbering errno.
ErrnoRestorer errno_restorer;
if (info->si_code != SI_QUEUE) {
@@ -86,6 +87,21 @@
return;
}
+ // Temporarily override SIGSYS handling, in a best-effort attempt at not
+ // crashing if we happen to be running in a process with a seccomp filter that
+ // disallows some of the syscalls done by this signal handler. This protects
+ // against SECCOMP_RET_TRAP with a crashing SIGSYS handler (typical of android
+ // minijails). Won't help if the filter is using SECCOMP_RET_KILL_*.
+ // Note: the override is process-wide, but short-lived. The syscalls are still
+ // blocked, but the overridden handler recovers from SIGSYS, and fakes the
+ // syscall return value as ENOSYS.
+ struct sigaction sigsys_override = {};
+ sigsys_override.sa_sigaction = &HandleSigsysSeccompOverride;
+ sigsys_override.sa_flags = SA_SIGINFO;
+
+ struct sigaction old_act = {};
+ sigaction(SIGSYS, &sigsys_override, &old_act);
+
if (signal_value == kHeapprofdSignalValue) {
HandleHeapprofdSignal();
} else if (signal_value == kTracedPerfSignalValue) {
@@ -94,6 +110,7 @@
async_safe_format_log(ANDROID_LOG_ERROR, "libc", "unrecognized profiling signal si_value: %d",
signal_value);
}
+ sigaction(SIGSYS, &old_act, nullptr);
}
// Open /proc/self/{maps,mem}, connect to traced_perf, send the fds over the
@@ -150,3 +167,33 @@
async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to sendmsg: %s", strerror(errno));
}
}
+
+static void HandleSigsysSeccompOverride(int /*signal_number*/, siginfo_t* info,
+ void* void_context) {
+ ErrnoRestorer errno_restorer;
+ if (info->si_code != SYS_SECCOMP) {
+ return;
+ }
+
+ async_safe_format_log(
+ ANDROID_LOG_WARN, "libc",
+ "Profiling setup: trapped seccomp SIGSYS for syscall %d. Returning ENOSYS to caller.",
+ info->si_syscall);
+
+ // The handler is responsible for setting the return value as if the system
+ // call happened (which is arch-specific). Use a plausible unsuccessful value.
+ auto ret = -ENOSYS;
+ ucontext_t* ctx = reinterpret_cast<ucontext_t*>(void_context);
+
+#if defined(__arm__)
+ ctx->uc_mcontext.arm_r0 = ret;
+#elif defined(__aarch64__)
+ ctx->uc_mcontext.regs[0] = ret; // x0
+#elif defined(__i386__)
+ ctx->uc_mcontext.gregs[REG_EAX] = ret;
+#elif defined(__x86_64__)
+ ctx->uc_mcontext.gregs[REG_RAX] = ret;
+#else
+#error "unsupported architecture"
+#endif
+}
diff --git a/libc/bionic/android_unsafe_frame_pointer_chase.cpp b/libc/bionic/android_unsafe_frame_pointer_chase.cpp
index 0fb086e..e25867b 100644
--- a/libc/bionic/android_unsafe_frame_pointer_chase.cpp
+++ b/libc/bionic/android_unsafe_frame_pointer_chase.cpp
@@ -57,6 +57,12 @@
auto begin = reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
uintptr_t end = __get_thread()->stack_top;
+
+ stack_t ss;
+ if (sigaltstack(nullptr, &ss) == 0 && (ss.ss_flags & SS_ONSTACK)) {
+ end = reinterpret_cast<uintptr_t>(ss.ss_sp) + ss.ss_size;
+ }
+
size_t num_frames = 0;
while (1) {
auto* frame = reinterpret_cast<frame_record*>(begin);
diff --git a/libc/bionic/heap_tagging.cpp b/libc/bionic/heap_tagging.cpp
index 62b5f5c..e5e8ec3 100644
--- a/libc/bionic/heap_tagging.cpp
+++ b/libc/bionic/heap_tagging.cpp
@@ -46,7 +46,8 @@
// or hardware doesn't support MTE, and we will fall back to just enabling tagged pointers in
// syscall arguments.
if (prctl(PR_SET_TAGGED_ADDR_CTRL,
- PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_ASYNC | (1 << PR_MTE_EXCL_SHIFT), 0, 0, 0) == 0) {
+ PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_ASYNC | (0xfffe << PR_MTE_TAG_SHIFT), 0, 0,
+ 0) == 0) {
heap_tagging_level = M_HEAP_TAGGING_LEVEL_ASYNC;
return;
}
diff --git a/libc/bionic/ifaddrs.cpp b/libc/bionic/ifaddrs.cpp
index e21ec40..e89b0bf 100644
--- a/libc/bionic/ifaddrs.cpp
+++ b/libc/bionic/ifaddrs.cpp
@@ -28,7 +28,6 @@
#include <ifaddrs.h>
-#include <async_safe/log.h>
#include <cutils/misc.h> // FIRST_APPLICATION_UID
#include <errno.h>
#include <linux/if_packet.h>
@@ -248,11 +247,20 @@
}
}
-static void remove_nameless_interfaces(ifaddrs** list) {
+static void resolve_or_remove_nameless_interfaces(ifaddrs** list) {
ifaddrs_storage* addr = reinterpret_cast<ifaddrs_storage*>(*list);
ifaddrs_storage* prev_addr = nullptr;
while (addr != nullptr) {
ifaddrs* next_addr = addr->ifa.ifa_next;
+
+ // Try resolving interfaces without a name first.
+ if (strlen(addr->name) == 0) {
+ if (if_indextoname(addr->interface_index, addr->name) != nullptr) {
+ addr->ifa.ifa_name = addr->name;
+ }
+ }
+
+ // If the interface could not be resolved, remove it.
if (strlen(addr->name) == 0) {
if (prev_addr == nullptr) {
*list = next_addr;
@@ -273,11 +281,9 @@
// Open the netlink socket and ask for all the links and addresses.
NetlinkConnection nc;
- // Simulate kernel behavior on R and above: RTM_GETLINK messages can only be
- // sent by:
+ // SELinux policy only allows RTM_GETLINK messages to be sent by:
// - System apps
// - Apps with a target SDK version lower than R
- // TODO(b/141455849): Remove this check when kernel changes are merged.
bool getlink_success = false;
if (getuid() < FIRST_APPLICATION_UID ||
android_get_application_target_sdk_version() < __ANDROID_API_R__) {
@@ -294,10 +300,9 @@
}
if (!getlink_success) {
- async_safe_format_log(ANDROID_LOG_INFO, "ifaddrs", "Failed to send RTM_GETLINK request");
// If we weren't able to depend on GETLINK messages, it's possible some
- // interfaces never got their name set. Remove those.
- remove_nameless_interfaces(out);
+ // interfaces never got their name set. Resolve them using if_indextoname or remove them.
+ resolve_or_remove_nameless_interfaces(out);
}
return 0;
diff --git a/libc/bionic/malloc_heapprofd.cpp b/libc/bionic/malloc_heapprofd.cpp
index 198d2f0..b2a9e3e 100644
--- a/libc/bionic/malloc_heapprofd.cpp
+++ b/libc/bionic/malloc_heapprofd.cpp
@@ -173,26 +173,46 @@
// not ever have a conflict modifying the globals.
if (!atomic_exchange(&gGlobalsMutating, true)) {
if (!atomic_exchange(&gHeapprofdInitInProgress, true)) {
- // If the backing dispatch is GWP-ASan, we should use GWP-ASan as the
- // intermediate dispatch table during initialisation. It may be possible
- // at this point in time that heapprofd is *already* the default dispatch,
- // and as such we don't want to use heapprofd as the backing store
- // (otherwise infinite recursion occurs).
- gPreviousDefaultDispatchTable = nullptr;
const MallocDispatch* default_dispatch = GetDefaultDispatchTable();
- if (DispatchIsGwpAsan(default_dispatch)) {
+
+ // Below, we initialize heapprofd lazily by redirecting libc's malloc() to
+ // call MallocInitHeapprofdHook, which spawns off a thread and initializes
+ // heapprofd. During the short period between now and when heapprofd is
+ // initialized, allocations may need to be serviced. There are three
+ // possible configurations:
+
+ if (default_dispatch == nullptr) {
+ // 1. No malloc hooking has been done (heapprofd, GWP-ASan, etc.). In
+ // this case, everything but malloc() should come from the system
+ // allocator.
+ gPreviousDefaultDispatchTable = nullptr;
+ gEphemeralDispatch = *NativeAllocatorDispatch();
+ } else if (DispatchIsGwpAsan(default_dispatch)) {
+ // 2. GWP-ASan was installed. We should use GWP-ASan for everything but
+ // malloc() in the interim period before heapprofd is properly
+ // installed. After heapprofd is finished installing, we will use
+ // GWP-ASan as heapprofd's backing allocator to allow heapprofd and
+ // GWP-ASan to coexist.
gPreviousDefaultDispatchTable = default_dispatch;
+ gEphemeralDispatch = *default_dispatch;
+ } else {
+ // 3. It may be possible at this point in time that heapprofd is
+ // *already* the default dispatch, and as such we don't want to use
+ // heapprofd as the backing store for itself (otherwise infinite
+ // recursion occurs). We will use the system allocator functions. Note:
+ // We've checked that no other malloc interceptors are being used by
+ // validating `gHeapprofdIncompatibleHooks` above, so we don't need to
+ // worry about that case here.
+ gPreviousDefaultDispatchTable = nullptr;
+ gEphemeralDispatch = *NativeAllocatorDispatch();
}
- __libc_globals.mutate([](libc_globals* globals) {
- // Wholesale copy the malloc dispatch table here. If the current/default
- // dispatch table is pointing to the malloc_dispatch_table, we can't
- // modify it as it may be racy. This dispatch table copy is ephemeral,
- // and the dispatch tables will be resolved back to the global
- // malloc_dispatch_table after initialization finishes.
- gEphemeralDispatch = globals->malloc_dispatch_table;
- gEphemeralDispatch.malloc = MallocInitHeapprofdHook;
+ // Now, replace the malloc function so that the next call to malloc() will
+ // initialize heapprofd.
+ gEphemeralDispatch.malloc = MallocInitHeapprofdHook;
+ // And finally, install these new malloc-family interceptors.
+ __libc_globals.mutate([](libc_globals* globals) {
atomic_store(&globals->default_dispatch_table, &gEphemeralDispatch);
if (!MallocLimitInstalled()) {
atomic_store(&globals->current_dispatch_table, &gEphemeralDispatch);
diff --git a/libc/include/bits/auxvec.h b/libc/include/bits/auxvec.h
index 4d39477..2d6522a 100644
--- a/libc/include/bits/auxvec.h
+++ b/libc/include/bits/auxvec.h
@@ -37,6 +37,14 @@
#include <linux/auxvec.h>
+// AT_HWCAP isn't useful without these constants.
+#if __has_include(<asm/hwcap.h>)
+#include <asm/hwcap.h>
+#endif
+#if __has_include(<asm/hwcap2.h>)
+#include <asm/hwcap2.h>
+#endif
+
/** Historical SuperH cruft. Irrelevant on Android. */
#define AT_FPUCW 18
/** Historical PowerPC cruft. Irrelevant on Android. */
diff --git a/libc/include/bits/fortify/stat.h b/libc/include/bits/fortify/stat.h
index e92e6ac..2d42a51 100644
--- a/libc/include/bits/fortify/stat.h
+++ b/libc/include/bits/fortify/stat.h
@@ -26,9 +26,7 @@
* SUCH DAMAGE.
*/
-#ifndef _SYS_STAT_H_
-#error "Never include this file directly; instead, include <sys/stat.h>"
-#endif
+#pragma once
mode_t __umask_chk(mode_t) __INTRODUCED_IN(18);
mode_t __umask_real(mode_t mode) __RENAME(umask);
diff --git a/libc/include/sys/auxv.h b/libc/include/sys/auxv.h
index c651940..bf70dda 100644
--- a/libc/include/sys/auxv.h
+++ b/libc/include/sys/auxv.h
@@ -40,7 +40,7 @@
__BEGIN_DECLS
/**
- * [getauxval(3)](http://man7.org/linux/man-pages/man2/personality.2.html) returns values from
+ * [getauxval(3)](http://man7.org/linux/man-pages/man3/getauxval.3.html) returns values from
* the ELF auxiliary vector passed by the kernel.
*
* Returns the corresponding value on success,
diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h
index a6c73b7..4184f6c 100644
--- a/libc/include/sys/stat.h
+++ b/libc/include/sys/stat.h
@@ -26,8 +26,12 @@
* SUCH DAMAGE.
*/
-#ifndef _SYS_STAT_H_
-#define _SYS_STAT_H_
+#pragma once
+
+/**
+ * @file sys/stat.h
+ * @brief File status.
+ */
#include <bits/timespec.h>
#include <linux/stat.h>
@@ -169,8 +173,16 @@
int utimensat(int __dir_fd, const char* __path, const struct timespec __times[2], int __flags);
int futimens(int __dir_fd, const struct timespec __times[2]) __INTRODUCED_IN(19);
+#if defined(__USE_GNU)
+/**
+ * [statx(2)](http://man7.org/linux/man-pages/man2/statx.2.html) returns
+ * extended file status information.
+ *
+ * Returns 0 on success and returns -1 and sets `errno` on failure.
+ */
+int statx(int __dir_fd, const char* __path, int __flags, unsigned __mask, struct statx* __buf) __INTRODUCED_IN(30);
+#endif
+
__END_DECLS
#include <android/legacy_sys_stat_inlines.h>
-
-#endif
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 37807be..4bfb8a2 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1505,6 +1505,7 @@
pthread_rwlock_clockwrlock;
renameat2;
sem_clockwait;
+ statx;
thrd_create;
thrd_current;
thrd_detach;
diff --git a/libc/platform/bionic/mte_kernel.h b/libc/platform/bionic/mte_kernel.h
index 2c777c9..984d17d 100644
--- a/libc/platform/bionic/mte_kernel.h
+++ b/libc/platform/bionic/mte_kernel.h
@@ -37,7 +37,7 @@
#ifdef ANDROID_EXPERIMENTAL_MTE
-#define HWCAP2_MTE (1 << 10)
+#define HWCAP2_MTE (1 << 18)
#define PROT_MTE 0x20
#define PR_MTE_TCF_SHIFT 1
@@ -45,10 +45,10 @@
#define PR_MTE_TCF_SYNC (1UL << PR_MTE_TCF_SHIFT)
#define PR_MTE_TCF_ASYNC (2UL << PR_MTE_TCF_SHIFT)
#define PR_MTE_TCF_MASK (3UL << PR_MTE_TCF_SHIFT)
-#define PR_MTE_EXCL_SHIFT 3
-#define PR_MTE_EXCL_MASK (0xffffUL << PR_MTE_EXCL_SHIFT)
+#define PR_MTE_TAG_SHIFT 3
+#define PR_MTE_TAG_MASK (0xffffUL << PR_MTE_TAG_SHIFT)
-#define SEGV_MTEAERR 6
-#define SEGV_MTESERR 7
+#define SEGV_MTEAERR 8
+#define SEGV_MTESERR 9
#endif
diff --git a/tests/Android.bp b/tests/Android.bp
index 4bd96ad..b840f36 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -39,10 +39,14 @@
"-D__STDC_LIMIT_MACROS",
],
header_libs: ["bionic_libc_platform_headers"],
- // Make the bionic tests implicitly test bionic's shadow call stack support.
+ // Ensure that the tests exercise shadow call stack support and
+ // the hint space PAC/BTI instructions.
arch: {
arm64: {
- cflags: ["-fsanitize=shadow-call-stack"],
+ cflags: [
+ "-fsanitize=shadow-call-stack",
+ "-mbranch-protection=standard",
+ ],
},
},
stl: "libc++",
@@ -166,6 +170,7 @@
"strings_nofortify_test.cpp",
"strings_test.cpp",
"sstream_test.cpp",
+ "sys_auxv_test.cpp",
"sys_epoll_test.cpp",
"sys_mman_test.cpp",
"sys_msg_test.cpp",
diff --git a/tests/android_unsafe_frame_pointer_chase_test.cpp b/tests/android_unsafe_frame_pointer_chase_test.cpp
index dd04c33..7fa50e1 100644
--- a/tests/android_unsafe_frame_pointer_chase_test.cpp
+++ b/tests/android_unsafe_frame_pointer_chase_test.cpp
@@ -18,6 +18,8 @@
#if defined(__BIONIC__)
+#include <sys/mman.h>
+
#include "platform/bionic/android_unsafe_frame_pointer_chase.h"
// Prevent tail calls inside recurse.
@@ -72,21 +74,25 @@
EXPECT_TRUE(CheckFrames(frames, size));
}
-static void *BacktraceThread(void *) {
+static const char* tester_func() {
size_t size = recurse(kNumFrames, 0, 0);
uintptr_t frames[kNumFrames + 2];
size_t size2 = recurse(kNumFrames, frames, kNumFrames + 2);
if (size2 != size) {
- return (void*)"size2 != size";
+ return "size2 != size";
}
if (!CheckFrames(frames, size)) {
- return (void*)"CheckFrames failed";
+ return "CheckFrames failed";
}
return nullptr;
}
+static void* BacktraceThread(void*) {
+ return (void*)tester_func();
+}
+
TEST(android_unsafe_frame_pointer_chase, pthread) {
pthread_t t;
ASSERT_EQ(0, pthread_create(&t, nullptr, BacktraceThread, nullptr));
@@ -95,4 +101,58 @@
EXPECT_EQ(nullptr, reinterpret_cast<char*>(retval));
}
+static bool g_handler_called;
+static const char* g_handler_tester_result;
+
+static void BacktraceHandler(int) {
+ g_handler_called = true;
+ g_handler_tester_result = tester_func();
+}
+
+static constexpr size_t kStackSize = 16384;
+
+static void* SignalBacktraceThread(void* sp) {
+ stack_t ss;
+ ss.ss_sp = sp;
+ ss.ss_flags = 0;
+ ss.ss_size = kStackSize;
+ sigaltstack(&ss, nullptr);
+
+ struct sigaction s = {};
+ s.sa_handler = BacktraceHandler;
+ s.sa_flags = SA_ONSTACK;
+ sigaction(SIGRTMIN, &s, nullptr);
+
+ raise(SIGRTMIN);
+ return nullptr;
+}
+
+TEST(android_unsafe_frame_pointer_chase, sigaltstack) {
+ // Create threads where the alternate stack appears both after and before the regular stack, and
+ // call android_unsafe_frame_pointer_chase from a signal handler. Without handling for the
+ // alternate signal stack, this would cause false negatives or potential false positives in the
+ // android_unsafe_frame_pointer_chase function.
+ void* stacks =
+ mmap(nullptr, kStackSize * 2, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
+
+ for (unsigned i = 0; i != 2; ++i) {
+ pthread_t t;
+ pthread_attr_t attr;
+ ASSERT_EQ(0, pthread_attr_init(&attr));
+ ASSERT_EQ(0, pthread_attr_setstack(&attr, reinterpret_cast<char*>(stacks) + kStackSize * i,
+ kStackSize));
+
+ ASSERT_EQ(0, pthread_create(&t, &attr, SignalBacktraceThread,
+ reinterpret_cast<char*>(stacks) + kStackSize * (1 - i)));
+ void* retval;
+ ASSERT_EQ(0, pthread_join(t, &retval));
+
+ EXPECT_TRUE(g_handler_called);
+ EXPECT_EQ(nullptr, g_handler_tester_result);
+ g_handler_called = false;
+ }
+
+ munmap(stacks, kStackSize * 2);
+}
+
#endif // __BIONIC__
diff --git a/tests/sys_auxv_test.cpp b/tests/sys_auxv_test.cpp
new file mode 100644
index 0000000..afd62ea
--- /dev/null
+++ b/tests/sys_auxv_test.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <gtest/gtest.h>
+
+#include <sys/auxv.h>
+
+TEST(sys_auxv, getauxval_HWCAP) {
+ __attribute__((__unused__)) unsigned long hwcap = getauxval(AT_HWCAP);
+
+ // Check that the constants for *using* AT_HWCAP are also available.
+#if defined(__arm__)
+ ASSERT_NE(0, HWCAP_THUMB);
+#elif defined(__aarch64__)
+ ASSERT_NE(0, HWCAP_FP);
+#endif
+}
+
+TEST(sys_auxv, getauxval_HWCAP2) {
+#if defined(AT_HWCAP2)
+ __attribute__((__unused__)) unsigned long hwcap = getauxval(AT_HWCAP2);
+
+ // Check that the constants for *using* AT_HWCAP2 are also available.
+#if defined(__arm__)
+ ASSERT_NE(0, HWCAP2_AES);
+#elif defined(__aarch64__)
+ ASSERT_NE(0, HWCAP2_SVE2);
+#endif
+#else
+ GTEST_SKIP() << "No AT_HWCAP2 for this architecture.";
+#endif
+}
diff --git a/tests/sys_stat_test.cpp b/tests/sys_stat_test.cpp
index 97bf580..71591c0 100644
--- a/tests/sys_stat_test.cpp
+++ b/tests/sys_stat_test.cpp
@@ -22,6 +22,14 @@
#include <android-base/file.h>
#include <gtest/gtest.h>
+#if defined(__BIONIC__)
+#define HAVE_STATX
+#elif defined(__GLIBC_PREREQ)
+#if __GLIBC_PREREQ(2, 28)
+#define HAVE_STATX
+#endif
+#endif
+
TEST(sys_stat, futimens) {
FILE* fp = tmpfile();
ASSERT_TRUE(fp != nullptr);
@@ -95,6 +103,24 @@
close(fd);
}
+TEST(sys_stat, statx) {
+#if defined(HAVE_STATX)
+ struct statx sx;
+ int rc = statx(AT_FDCWD, "/proc/version", AT_STATX_SYNC_AS_STAT, STATX_ALL, &sx);
+ if (rc == -1 && errno == ENOSYS) {
+ GTEST_SKIP() << "statx returned ENOSYS";
+ return;
+ }
+ ASSERT_EQ(0, rc);
+ struct stat64 sb;
+ ASSERT_EQ(0, stat64("/proc/version", &sb));
+ EXPECT_EQ(sb.st_ino, sx.stx_ino);
+ EXPECT_EQ(sb.st_mode, sx.stx_mode);
+#else
+ GTEST_SKIP() << "statx not available";
+#endif
+}
+
TEST(sys_stat, fchmodat_EFAULT_file) {
ASSERT_EQ(-1, fchmodat(AT_FDCWD, (char *) 0x1, 0751, 0));
ASSERT_EQ(EFAULT, errno);