diff options
57 files changed, 956 insertions, 392 deletions
diff --git a/apex/Android.bp b/apex/Android.bp index c97eb15d3..8aec64a49 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -60,6 +60,8 @@ sdk { ], native_static_libs: [ "libasync_safe", + "note_memtag_heap_async", + "note_memtag_heap_sync", ], native_objects: [ "crtbegin_dynamic", diff --git a/libc/Android.bp b/libc/Android.bp index 6bb197446..5340c6f8a 100644 --- a/libc/Android.bp +++ b/libc/Android.bp @@ -93,9 +93,6 @@ cc_defaults { ldflags: ["-Wl,-z,muldefs"], product_variables: { - experimental_mte: { - cflags: ["-DANDROID_EXPERIMENTAL_MTE"], - }, malloc_zero_contents: { cflags: ["-DSCUDO_ZERO_CONTENTS"], }, @@ -269,6 +266,7 @@ cc_library_static { "-Wno-unused-parameter", "-include netbsd-compat.h", "-Wframe-larger-than=66000", + "-include private/bsd_sys_param.h", ], local_include_dirs: [ @@ -579,6 +577,7 @@ cc_library_static { ], local_include_dirs: [ + "private", "upstream-openbsd/android/include/", "upstream-openbsd/lib/libc/include/", "upstream-openbsd/lib/libc/gdtoa/", @@ -1653,6 +1652,7 @@ cc_library { "gwp_asan", "libc_init_dynamic", "libc_common_shared", + "libunwind-exported", ], }, @@ -1694,8 +1694,6 @@ cc_library { srcs: [":libc_sources_shared_arm"], // special for arm cflags: ["-DCRT_LEGACY_WORKAROUND"], - - whole_static_libs: [ "libunwind_llvm" ], }, // Arm 32 bit does not produce complete exidx unwind information @@ -1714,10 +1712,6 @@ cc_library { strip: { keep_symbols: true, }, - - shared: { - whole_static_libs: [ "libgcc_stripped" ], - }, }, x86: { // TODO: This is to work around b/24465209. Remove after root cause is fixed. @@ -1731,10 +1725,6 @@ cc_library { strip: { keep_symbols: true, }, - - shared: { - whole_static_libs: [ "libgcc_stripped" ], - }, }, x86_64: { version_script: ":libc.x86_64.map", @@ -1744,10 +1734,6 @@ cc_library { strip: { keep_symbols: true, }, - - shared: { - whole_static_libs: [ "libgcc_stripped" ], - }, }, }, @@ -2122,6 +2108,8 @@ cc_object { local_include_dirs: ["include"], srcs: ["arch-common/bionic/crtbegin.c"], defaults: ["crt_defaults"], + // When using libc.a, we're using the latest library regardless of target API level. + min_sdk_version: "current", } cc_object { @@ -2132,6 +2120,8 @@ cc_object { "crtbrand", ], defaults: ["crt_defaults"], + // When using libc.a, we're using the latest library regardless of target API level. + min_sdk_version: "current", } cc_object { @@ -2169,6 +2159,28 @@ cc_object { defaults: ["crt_defaults"], } +cc_library_static { + name: "note_memtag_heap_async", + arch: { + arm64: { + srcs: ["arch-arm64/bionic/note_memtag_heap_async.S"], + } + }, + + defaults: ["crt_defaults"], +} + +cc_library_static { + name: "note_memtag_heap_sync", + arch: { + arm64: { + srcs: ["arch-arm64/bionic/note_memtag_heap_sync.S"], + } + }, + + defaults: ["crt_defaults"], +} + // ======================================================== // NDK headers. // ======================================================== @@ -2249,7 +2261,6 @@ ndk_headers { ndk_library { name: "libc", - native_bridge_supported: true, symbol_file: "libc.map.txt", first_version: "9", } diff --git a/libc/NOTICE b/libc/NOTICE index f7d73d8f8..7041e5c3c 100644 --- a/libc/NOTICE +++ b/libc/NOTICE @@ -1083,6 +1083,34 @@ SUCH DAMAGE. ------------------------------------------------------------------- +Copyright (C) 2021 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. + +------------------------------------------------------------------- + Copyright (c) 1980, 1983, 1988, 1993 The Regents of the University of California. All rights reserved. diff --git a/libc/arch-arm/bionic/kuser_helper_on.S b/libc/arch-arm/bionic/kuser_helper_on.S index cff2073b7..2a1d86dde 100644 --- a/libc/arch-arm/bionic/kuser_helper_on.S +++ b/libc/arch-arm/bionic/kuser_helper_on.S @@ -26,13 +26,15 @@ * SUCH DAMAGE. */ +#include <private/bionic_asm_note.h> + .section .note.android.kuser_helper_on,"a",%note .balign 4 .type kuser_helper_on, %object kuser_helper_on: .long 2f-1f // int32_t namesz .long 3f-2f // int32_t descsz - .long 3 // int32_t type + .long NT_TYPE_KUSER // int32_t type 1:.ascii "Android\0" // char name[] 2:.long 1 // int32_t on 3: diff --git a/libc/arch-arm64/bionic/note_memtag_heap_async.S b/libc/arch-arm64/bionic/note_memtag_heap_async.S new file mode 100644 index 000000000..208115c13 --- /dev/null +++ b/libc/arch-arm64/bionic/note_memtag_heap_async.S @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 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 <private/bionic_asm.h> +#include <private/bionic_asm_note.h> + +__bionic_asm_custom_note_gnu_section() + + .section ".note.android.memtag", "a", %note + .p2align 2 + .long 1f - 0f // int32_t namesz + .long 3f - 2f // int32_t descsz + .long NT_TYPE_MEMTAG // int32_t type +0: + .asciz "Android" // char name[] +1: + .p2align 2 +2: + .long (NT_MEMTAG_LEVEL_ASYNC | NT_MEMTAG_HEAP) // value +3: + .p2align 2 diff --git a/libc/arch-arm64/bionic/note_memtag_heap_sync.S b/libc/arch-arm64/bionic/note_memtag_heap_sync.S new file mode 100644 index 000000000..d71ad020e --- /dev/null +++ b/libc/arch-arm64/bionic/note_memtag_heap_sync.S @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 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 <private/bionic_asm.h> +#include <private/bionic_asm_note.h> + +__bionic_asm_custom_note_gnu_section() + + .section ".note.android.memtag", "a", %note + .p2align 2 + .long 1f - 0f // int32_t namesz + .long 3f - 2f // int32_t descsz + .long NT_TYPE_MEMTAG // int32_t type +0: + .asciz "Android" // char name[] +1: + .p2align 2 +2: + .long (NT_MEMTAG_LEVEL_SYNC | NT_MEMTAG_HEAP) // value +3: + .p2align 2 diff --git a/libc/arch-arm64/dynamic_function_dispatch.cpp b/libc/arch-arm64/dynamic_function_dispatch.cpp index 0fd331f79..83e5ca4da 100644 --- a/libc/arch-arm64/dynamic_function_dispatch.cpp +++ b/libc/arch-arm64/dynamic_function_dispatch.cpp @@ -26,25 +26,15 @@ * SUCH DAMAGE. */ -#include <platform/bionic/mte_kernel.h> #include <private/bionic_ifuncs.h> #include <stddef.h> #include <sys/auxv.h> extern "C" { -static bool supports_mte(unsigned long hwcap2) { -#ifdef ANDROID_EXPERIMENTAL_MTE - return hwcap2 & HWCAP2_MTE; -#else - (void)hwcap2; - return false; -#endif -} - typedef void* memchr_func(const void*, int, size_t); DEFINE_IFUNC_FOR(memchr) { - if (supports_mte(arg->_hwcap2)) { + if (arg->_hwcap2 & HWCAP2_MTE) { RETURN_FUNC(memchr_func, __memchr_aarch64_mte); } else { RETURN_FUNC(memchr_func, __memchr_aarch64); @@ -53,7 +43,7 @@ DEFINE_IFUNC_FOR(memchr) { typedef int stpcpy_func(char*, const char*); DEFINE_IFUNC_FOR(stpcpy) { - if (supports_mte(arg->_hwcap2)) { + if (arg->_hwcap2 & HWCAP2_MTE) { RETURN_FUNC(stpcpy_func, __stpcpy_aarch64_mte); } else { RETURN_FUNC(stpcpy_func, __stpcpy_aarch64); @@ -62,7 +52,7 @@ DEFINE_IFUNC_FOR(stpcpy) { typedef char* strchr_func(const char*, int); DEFINE_IFUNC_FOR(strchr) { - if (supports_mte(arg->_hwcap2)) { + if (arg->_hwcap2 & HWCAP2_MTE) { RETURN_FUNC(strchr_func, __strchr_aarch64_mte); } else { RETURN_FUNC(strchr_func, __strchr_aarch64); @@ -71,7 +61,7 @@ DEFINE_IFUNC_FOR(strchr) { typedef char* strchrnul_func(const char*, int); DEFINE_IFUNC_FOR(strchrnul) { - if (supports_mte(arg->_hwcap2)) { + if (arg->_hwcap2 & HWCAP2_MTE) { RETURN_FUNC(strchrnul_func, __strchrnul_aarch64_mte); } else { RETURN_FUNC(strchrnul_func, __strchrnul_aarch64); @@ -80,7 +70,7 @@ DEFINE_IFUNC_FOR(strchrnul) { typedef int strcmp_func(const char*, const char*); DEFINE_IFUNC_FOR(strcmp) { - if (supports_mte(arg->_hwcap2)) { + if (arg->_hwcap2 & HWCAP2_MTE) { RETURN_FUNC(strcmp_func, __strcmp_aarch64_mte); } else { RETURN_FUNC(strcmp_func, __strcmp_aarch64); @@ -89,7 +79,7 @@ DEFINE_IFUNC_FOR(strcmp) { typedef int strcpy_func(char*, const char*); DEFINE_IFUNC_FOR(strcpy) { - if (supports_mte(arg->_hwcap2)) { + if (arg->_hwcap2 & HWCAP2_MTE) { RETURN_FUNC(strcpy_func, __strcpy_aarch64_mte); } else { RETURN_FUNC(strcpy_func, __strcpy_aarch64); @@ -98,7 +88,7 @@ DEFINE_IFUNC_FOR(strcpy) { typedef size_t strlen_func(const char*); DEFINE_IFUNC_FOR(strlen) { - if (supports_mte(arg->_hwcap2)) { + if (arg->_hwcap2 & HWCAP2_MTE) { RETURN_FUNC(strlen_func, __strlen_aarch64_mte); } else { RETURN_FUNC(strlen_func, __strlen_aarch64); @@ -107,7 +97,7 @@ DEFINE_IFUNC_FOR(strlen) { typedef int strncmp_func(const char*, const char*, int); DEFINE_IFUNC_FOR(strncmp) { - if (supports_mte(arg->_hwcap2)) { + if (arg->_hwcap2 & HWCAP2_MTE) { RETURN_FUNC(strncmp_func, __strncmp_aarch64_mte); } else { RETURN_FUNC(strncmp_func, __strncmp_aarch64); @@ -116,7 +106,7 @@ DEFINE_IFUNC_FOR(strncmp) { typedef char* strrchr_func(const char*, int); DEFINE_IFUNC_FOR(strrchr) { - if (supports_mte(arg->_hwcap2)) { + if (arg->_hwcap2 & HWCAP2_MTE) { RETURN_FUNC(strrchr_func, __strrchr_aarch64_mte); } else { RETURN_FUNC(strrchr_func, __strrchr_aarch64); diff --git a/libc/arch-common/bionic/crtbrand.S b/libc/arch-common/bionic/crtbrand.S index 3d80d7353..307ef2e34 100644 --- a/libc/arch-common/bionic/crtbrand.S +++ b/libc/arch-common/bionic/crtbrand.S @@ -32,13 +32,15 @@ __bionic_asm_custom_note_gnu_section() #endif +#include <private/bionic_asm_note.h> + .section .note.android.ident,"a",%note .balign 4 .type abitag, %object abitag: .long 2f-1f // int32_t namesz .long 3f-2f // int32_t descsz - .long 1 // int32_t type + .long NT_TYPE_IDENT // int32_t type #ifdef __ANDROID__ 1:.ascii "Android\0" // char name[] 2:.long PLATFORM_SDK_VERSION // int32_t android_api diff --git a/libc/bionic/bionic_appcompat.cpp b/libc/bionic/bionic_appcompat.cpp index 5b31c299d..dcca0dad5 100644 --- a/libc/bionic/bionic_appcompat.cpp +++ b/libc/bionic/bionic_appcompat.cpp @@ -88,4 +88,4 @@ int get_package_name(char* buffer, const int bufferlen) { close(file); return 0; -}
\ No newline at end of file +} diff --git a/libc/bionic/bionic_appcompat.h b/libc/bionic/bionic_appcompat.h index 1976e0b70..fd3703588 100644 --- a/libc/bionic/bionic_appcompat.h +++ b/libc/bionic/bionic_appcompat.h @@ -41,4 +41,4 @@ static inline const char* const soft_mac_getlink_allowlist[] = { int get_package_name(char* buffer, const int bufferlen); bool should_apply_soft_mac_bind_restrictions(); -bool should_apply_soft_mac_getlink_restrictions();
\ No newline at end of file +bool should_apply_soft_mac_getlink_restrictions(); diff --git a/libc/bionic/fts.c b/libc/bionic/fts.c index 8888ab18a..77b411762 100644 --- a/libc/bionic/fts.c +++ b/libc/bionic/fts.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fts.c,v 1.48 2014/11/20 04:14:15 guenther Exp $ */ +/* $OpenBSD: fts.c,v 1.60 2021/01/08 16:06:30 tb Exp $ */ /*- * Copyright (c) 1990, 1993, 1994 @@ -29,10 +29,9 @@ * SUCH DAMAGE. */ -#include <sys/param.h> +#include <sys/param.h> /* ALIGN */ #include <sys/stat.h> -#include <assert.h> #include <dirent.h> #include <errno.h> #include <fcntl.h> @@ -42,7 +41,9 @@ #include <string.h> #include <unistd.h> -static FTSENT *fts_alloc(FTS *, char *, size_t); +#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b)) + +static FTSENT *fts_alloc(FTS *, const char *, size_t); static FTSENT *fts_build(FTS *, int); static void fts_lfree(FTSENT *); static void fts_load(FTS *, FTSENT *); @@ -51,11 +52,12 @@ static void fts_padjust(FTS *, FTSENT *); static int fts_palloc(FTS *, size_t); static FTSENT *fts_sort(FTS *, FTSENT *, int); static u_short fts_stat(FTS *, FTSENT *, int, int); -static int fts_safe_changedir(FTS *, FTSENT *, int, char *); +static int fts_safe_changedir(FTS *, FTSENT *, int, const char *); -#define ALIGNBYTES (sizeof(uintptr_t) - 1) -#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES) -void* reallocarray(void*, size_t, size_t); +/* Android: OpenBSD source compatibility workarounds. */ +#include "private/bsd_sys_param.h" +#define DEF_WEAK(s) /* nothing */ +void* recallocarray(void*, size_t, size_t, size_t); #define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) @@ -70,12 +72,22 @@ void* reallocarray(void*, size_t, size_t); #define BNAMES 2 /* fts_children, names only */ #define BREAD 3 /* fts_read */ -FTS* __fts_open(char* const* argv, int options, int (*compar)(const FTSENT**, const FTSENT**)) { +FTS * +__fts_open(char * const *argv, int options, + int (*compar)(const FTSENT **, const FTSENT **)) +{ FTS *sp; FTSENT *p, *root; int nitems; - FTSENT *parent, *tmp; - size_t len; + FTSENT *parent, *prev; + + /* Android: options check moved to __fts_open() for ftw(). */ + + /* At least one path must be specified. */ + if (*argv == NULL) { + errno = EINVAL; + return (NULL); + } /* Allocate/initialize the stream */ if ((sp = calloc(1, sizeof(FTS))) == NULL) @@ -91,7 +103,7 @@ FTS* __fts_open(char* const* argv, int options, int (*compar)(const FTSENT**, co * Start out with 1K of path space, and enough, in any case, * to hold the user's paths. */ - if (fts_palloc(sp, MAX(fts_maxarglen(argv), PATH_MAX))) + if (fts_palloc(sp, MAXIMUM(fts_maxarglen(argv), PATH_MAX))) goto mem1; /* Allocate/initialize root's parent. */ @@ -100,21 +112,15 @@ FTS* __fts_open(char* const* argv, int options, int (*compar)(const FTSENT**, co parent->fts_level = FTS_ROOTPARENTLEVEL; /* Allocate/initialize root(s). */ - for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) { - /* Don't allow zero-length paths. */ - if ((len = strlen(*argv)) == 0) { - errno = ENOENT; - goto mem3; - } - - if ((p = fts_alloc(sp, *argv, len)) == NULL) + for (root = prev = NULL, nitems = 0; *argv; ++argv, ++nitems) { + if ((p = fts_alloc(sp, *argv, strlen(*argv))) == NULL) goto mem3; p->fts_level = FTS_ROOTLEVEL; p->fts_parent = parent; p->fts_accpath = p->fts_name; p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW), -1); - // For ftw/nftw we need to fail early: http://b/31152735 + // Android: for ftw/nftw we need to fail early: http://b/31152735 if ((options & FTS_FOR_FTW) != 0 && p->fts_info == FTS_NS) goto mem3; /* Command-line "." and ".." are real directories. */ @@ -131,11 +137,10 @@ FTS* __fts_open(char* const* argv, int options, int (*compar)(const FTSENT**, co } else { p->fts_link = NULL; if (root == NULL) - tmp = root = p; - else { - tmp->fts_link = p; - tmp = p; - } + root = p; + else + prev->fts_link = p; + prev = p; } } if (compar && nitems > 1) @@ -158,7 +163,8 @@ FTS* __fts_open(char* const* argv, int options, int (*compar)(const FTSENT**, co * and ".." are all fairly nasty problems. Note, if we can't get the * descriptor we run anyway, just more slowly. */ - if (!ISSET(FTS_NOCHDIR) && (sp->fts_rfd = open(".", O_RDONLY|O_CLOEXEC, 0)) < 0) + if (!ISSET(FTS_NOCHDIR) && + (sp->fts_rfd = open(".", O_RDONLY | O_CLOEXEC)) == -1) SET(FTS_NOCHDIR); if (nitems == 0) @@ -172,6 +178,7 @@ mem2: free(sp->fts_path); mem1: free(sp); return (NULL); } +DEF_WEAK(fts_open); static void fts_load(FTS *sp, FTSENT *p) @@ -221,7 +228,8 @@ fts_close(FTS *sp) rfd = ISSET(FTS_NOCHDIR) ? -1 : sp->fts_rfd; /* Free up child linked list, sort array, path buffer, stream ptr.*/ - fts_lfree(sp->fts_child); + if (sp->fts_child) + fts_lfree(sp->fts_child); free(sp->fts_array); free(sp->fts_path); free(sp); @@ -237,6 +245,7 @@ fts_close(FTS *sp) return (error); } +DEF_WEAK(fts_close); /* * Special case of "/" at the end of the path so that slashes aren't @@ -281,7 +290,8 @@ fts_read(FTS *sp) (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { p->fts_info = fts_stat(sp, p, 1, -1); if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { - if ((p->fts_symfd = open(".", O_RDONLY|O_CLOEXEC, 0)) < 0) { + if ((p->fts_symfd = + open(".", O_RDONLY | O_CLOEXEC)) == -1) { p->fts_errno = errno; p->fts_info = FTS_ERR; } else @@ -370,7 +380,8 @@ next: tmp = p; if (p->fts_instr == FTS_FOLLOW) { p->fts_info = fts_stat(sp, p, 1, -1); if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { - if ((p->fts_symfd = open(".", O_RDONLY|O_CLOEXEC, 0)) < 0) { + if ((p->fts_symfd = + open(".", O_RDONLY | O_CLOEXEC)) == -1) { p->fts_errno = errno; p->fts_info = FTS_ERR; } else @@ -432,6 +443,7 @@ name: t = sp->fts_path + NAPPEND(p->fts_parent); p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; return (sp->fts_cur = p); } +DEF_WEAK(fts_read); /* * Fts_set takes the stream as an argument although it's not used in this @@ -439,7 +451,6 @@ name: t = sp->fts_path + NAPPEND(p->fts_parent); * semantics to fts using fts_set. An error return is allowed for similar * reasons. */ -/* ARGSUSED */ int fts_set(FTS *sp __unused, FTSENT *p, int instr) { @@ -451,6 +462,7 @@ fts_set(FTS *sp __unused, FTSENT *p, int instr) p->fts_instr = instr; return (0); } +DEF_WEAK(fts_set); FTSENT * fts_children(FTS *sp, int instr) @@ -489,7 +501,8 @@ fts_children(FTS *sp, int instr) return (NULL); /* Free up any previous child list. */ - fts_lfree(sp->fts_child); + if (sp->fts_child) + fts_lfree(sp->fts_child); if (instr == FTS_NAMEONLY) { SET(FTS_NAMEONLY); @@ -508,7 +521,7 @@ fts_children(FTS *sp, int instr) ISSET(FTS_NOCHDIR)) return (sp->fts_child = fts_build(sp, instr)); - if ((fd = open(".", O_RDONLY|O_CLOEXEC, 0)) < 0) + if ((fd = open(".", O_RDONLY | O_CLOEXEC)) == -1) return (NULL); sp->fts_child = fts_build(sp, instr); if (fchdir(fd)) { @@ -518,6 +531,7 @@ fts_children(FTS *sp, int instr) (void)close(fd); return (sp->fts_child); } +DEF_WEAK(fts_children); /* * This is the tricky part -- do not casually change *anything* in here. The @@ -542,9 +556,9 @@ fts_build(FTS *sp, int type) DIR *dirp; void *oldaddr; size_t len, maxlen; - int nitems, cderrno, descend, level, nlinks, nostat = 0, doadjust; + int nitems, cderrno, descend, level, nlinks, nostat, doadjust; int saved_errno; - char *cp = NULL; + char *cp; /* Set current node pointer. */ cur = sp->fts_cur; @@ -709,8 +723,7 @@ mem1: saved_errno = errno; /* Build a file name for fts_stat to stat. */ if (ISSET(FTS_NOCHDIR)) { p->fts_accpath = p->fts_path; - assert(cp && "cp should be non-null if FTS_NOCHDIR is set"); - memmove(cp, p->fts_name, p->fts_namelen + 1); // NOLINT + memmove(cp, p->fts_name, p->fts_namelen + 1); p->fts_info = fts_stat(sp, p, 0, dirfd(dirp)); } else { p->fts_accpath = p->fts_name; @@ -806,9 +819,9 @@ fts_stat(FTS *sp, FTSENT *p, int follow, int dfd) * fail, set the errno from the stat call. */ if (ISSET(FTS_LOGICAL) || follow) { - if (fstatat(dfd, path, sbp, 0) == -1) { + if (fstatat(dfd, path, sbp, 0)) { saved_errno = errno; - if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW) == 0) { + if (!fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) { errno = 0; return (FTS_SLNONE); } @@ -872,19 +885,19 @@ fts_sort(FTS *sp, FTSENT *head, int nitems) if (nitems > sp->fts_nitems) { struct _ftsent **a; - sp->fts_nitems = nitems + 40; if ((a = reallocarray(sp->fts_array, - sp->fts_nitems, sizeof(FTSENT *))) == NULL) { + nitems + 40, sizeof(FTSENT *))) == NULL) { free(sp->fts_array); sp->fts_array = NULL; sp->fts_nitems = 0; return (head); } + sp->fts_nitems = nitems + 40; sp->fts_array = a; } for (ap = sp->fts_array, p = head; p; p = p->fts_link) *ap++ = p; - qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar); + qsort(sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar); for (head = *(ap = sp->fts_array); --nitems; ++ap) ap[0]->fts_link = ap[1]; ap[0]->fts_link = NULL; @@ -892,7 +905,7 @@ fts_sort(FTS *sp, FTSENT *head, int nitems) } static FTSENT * -fts_alloc(FTS *sp, char *name, size_t namelen) +fts_alloc(FTS *sp, const char *name, size_t namelen) { FTSENT *p; size_t len; @@ -954,13 +967,14 @@ fts_palloc(FTS *sp, size_t more) errno = ENAMETOOLONG; return (1); } - sp->fts_pathlen += more; - p = realloc(sp->fts_path, sp->fts_pathlen); + p = recallocarray(sp->fts_path, sp->fts_pathlen, + sp->fts_pathlen + more, 1); if (p == NULL) { free(sp->fts_path); sp->fts_path = NULL; return (1); } + sp->fts_pathlen += more; sp->fts_path = p; return (0); } @@ -1010,7 +1024,7 @@ fts_maxarglen(char * const *argv) * Assumes p->fts_dev and p->fts_ino are filled in. */ static int -fts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path) +fts_safe_changedir(FTS *sp, FTSENT *p, int fd, const char *path) { int ret, oerrno, newfd; struct stat sb; @@ -1018,9 +1032,9 @@ fts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path) newfd = fd; if (ISSET(FTS_NOCHDIR)) return (0); - if (fd < 0 && (newfd = open(path, O_RDONLY|O_DIRECTORY|O_CLOEXEC, 0)) < 0) + if (fd == -1 && (newfd = open(path, O_RDONLY|O_DIRECTORY|O_CLOEXEC)) == -1) return (-1); - if (fstat(newfd, &sb)) { + if (fstat(newfd, &sb) == -1) { ret = -1; goto bail; } @@ -1032,17 +1046,21 @@ fts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path) ret = fchdir(newfd); bail: oerrno = errno; - if (fd < 0) + if (fd == -1) (void)close(newfd); errno = oerrno; return (ret); } -FTS* fts_open(char* const* argv, int options, int (*compar)(const FTSENT**, const FTSENT**)) { - // Options check. - if ((options & ~FTS_OPTIONMASK) != 0) { - errno = EINVAL; - return NULL; - } - return __fts_open(argv, options, compar); +FTS * +fts_open(char * const *argv, int options, + int (*compar)(const FTSENT **, const FTSENT **)) +{ + // Android needs to an __fts_open() that doesn't make this check + // so that FTS_FOR_FTW works. + if (options & ~FTS_OPTIONMASK) { + errno = EINVAL; + return (NULL); + } + return __fts_open(argv, options, compar); } diff --git a/libc/bionic/heap_tagging.cpp b/libc/bionic/heap_tagging.cpp index 2c5d4d8cb..ffbabb9a0 100644 --- a/libc/bionic/heap_tagging.cpp +++ b/libc/bionic/heap_tagging.cpp @@ -32,7 +32,6 @@ #include <bionic/pthread_internal.h> #include <platform/bionic/malloc.h> -#include <platform/bionic/mte_kernel.h> extern "C" void scudo_malloc_disable_memory_tagging(); extern "C" void scudo_malloc_set_track_allocation_stacks(int); @@ -42,35 +41,36 @@ static HeapTaggingLevel heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE; void SetDefaultHeapTaggingLevel() { #if defined(__aarch64__) -#ifdef ANDROID_EXPERIMENTAL_MTE - // First, try enabling MTE in asynchronous mode, with tag 0 excluded. This will fail if the kernel - // 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 | (0xfffe << PR_MTE_TAG_SHIFT), 0, 0, - 0) == 0) { - heap_tagging_level = M_HEAP_TAGGING_LEVEL_ASYNC; - return; - } -#endif // ANDROID_EXPERIMENTAL_MTE - - // Allow the kernel to accept tagged pointers in syscall arguments. This is a no-op (kernel - // returns -EINVAL) if the kernel doesn't understand the prctl. - if (prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0) == 0) { #if !__has_feature(hwaddress_sanitizer) - heap_tagging_level = M_HEAP_TAGGING_LEVEL_TBI; - __libc_globals.mutate([](libc_globals* globals) { - // Arrange for us to set pointer tags to POINTER_TAG, check tags on - // deallocation and untag when passing pointers to the allocator. - globals->heap_pointer_tag = (reinterpret_cast<uintptr_t>(POINTER_TAG) << TAG_SHIFT) | - (0xffull << CHECK_SHIFT) | (0xffull << UNTAG_SHIFT); - }); -#endif // hwaddress_sanitizer + heap_tagging_level = __libc_shared_globals()->initial_heap_tagging_level; +#endif + switch (heap_tagging_level) { + case M_HEAP_TAGGING_LEVEL_TBI: + __libc_globals.mutate([](libc_globals* globals) { + // Arrange for us to set pointer tags to POINTER_TAG, check tags on + // deallocation and untag when passing pointers to the allocator. + globals->heap_pointer_tag = (reinterpret_cast<uintptr_t>(POINTER_TAG) << TAG_SHIFT) | + (0xffull << CHECK_SHIFT) | (0xffull << UNTAG_SHIFT); + }); +#if defined(USE_SCUDO) + scudo_malloc_disable_memory_tagging(); +#endif // USE_SCUDO + break; +#if defined(USE_SCUDO) + case M_HEAP_TAGGING_LEVEL_SYNC: + scudo_malloc_set_track_allocation_stacks(1); + break; + + case M_HEAP_TAGGING_LEVEL_NONE: + scudo_malloc_disable_memory_tagging(); + break; +#endif // USE_SCUDO + default: + break; } #endif // aarch64 } -#ifdef ANDROID_EXPERIMENTAL_MTE static bool set_tcf_on_all_threads(int tcf) { static int g_tcf; g_tcf = tcf; @@ -90,7 +90,6 @@ static bool set_tcf_on_all_threads(int tcf) { }, nullptr); } -#endif pthread_mutex_t g_heap_tagging_lock = PTHREAD_MUTEX_INITIALIZER; @@ -100,12 +99,7 @@ HeapTaggingLevel GetHeapTaggingLevel() { } // Requires `g_heap_tagging_lock` to be held. -bool SetHeapTaggingLevel(void* arg, size_t arg_size) { - if (arg_size != sizeof(HeapTaggingLevel)) { - return false; - } - - auto tag_level = *reinterpret_cast<HeapTaggingLevel*>(arg); +bool SetHeapTaggingLevel(HeapTaggingLevel tag_level) { if (tag_level == heap_tagging_level) { return true; } @@ -119,13 +113,9 @@ bool SetHeapTaggingLevel(void* arg, size_t arg_size) { // tagged and checks no longer happen. globals->heap_pointer_tag = static_cast<uintptr_t>(0xffull << UNTAG_SHIFT); }); - } else { -#if defined(ANDROID_EXPERIMENTAL_MTE) - if (!set_tcf_on_all_threads(PR_MTE_TCF_NONE)) { - error_log("SetHeapTaggingLevel: set_tcf_on_all_threads failed"); - return false; - } -#endif + } else if (!set_tcf_on_all_threads(PR_MTE_TCF_NONE)) { + error_log("SetHeapTaggingLevel: set_tcf_on_all_threads failed"); + return false; } #if defined(USE_SCUDO) scudo_malloc_disable_memory_tagging(); @@ -135,8 +125,12 @@ bool SetHeapTaggingLevel(void* arg, size_t arg_size) { case M_HEAP_TAGGING_LEVEL_ASYNC: case M_HEAP_TAGGING_LEVEL_SYNC: if (heap_tagging_level == M_HEAP_TAGGING_LEVEL_NONE) { +#if !__has_feature(hwaddress_sanitizer) + // Suppress the error message in HWASan builds. Apps can try to enable TBI (or even MTE + // modes) being unaware of HWASan, fail them silently. error_log( "SetHeapTaggingLevel: re-enabling tagging after it was disabled is not supported"); +#endif return false; } else if (tag_level == M_HEAP_TAGGING_LEVEL_TBI || heap_tagging_level == M_HEAP_TAGGING_LEVEL_TBI) { @@ -145,16 +139,12 @@ bool SetHeapTaggingLevel(void* arg, size_t arg_size) { } if (tag_level == M_HEAP_TAGGING_LEVEL_ASYNC) { -#if defined(ANDROID_EXPERIMENTAL_MTE) set_tcf_on_all_threads(PR_MTE_TCF_ASYNC); -#endif #if defined(USE_SCUDO) scudo_malloc_set_track_allocation_stacks(0); #endif } else if (tag_level == M_HEAP_TAGGING_LEVEL_SYNC) { -#if defined(ANDROID_EXPERIMENTAL_MTE) set_tcf_on_all_threads(PR_MTE_TCF_SYNC); -#endif #if defined(USE_SCUDO) scudo_malloc_set_track_allocation_stacks(1); #endif diff --git a/libc/bionic/heap_tagging.h b/libc/bionic/heap_tagging.h index db45fc100..110b6ed7a 100644 --- a/libc/bionic/heap_tagging.h +++ b/libc/bionic/heap_tagging.h @@ -42,5 +42,5 @@ extern pthread_mutex_t g_heap_tagging_lock; // These functions can be called in a multithreaded context, and thus should // only be called when holding the `g_heap_tagging_lock`. -bool SetHeapTaggingLevel(void* arg, size_t arg_size); +bool SetHeapTaggingLevel(HeapTaggingLevel level); HeapTaggingLevel GetHeapTaggingLevel(); diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp index 80adbbe8e..f2c3f1c68 100644 --- a/libc/bionic/libc_init_common.cpp +++ b/libc/bionic/libc_init_common.cpp @@ -86,7 +86,7 @@ static void arc4random_fork_handler() { _thread_arc4_lock(); } -static void __libc_init_malloc_fill_contents() { +void __libc_init_scudo() { // TODO(b/158870657) make this unconditional when all devices support SCUDO. #if defined(USE_SCUDO) #if defined(SCUDO_PATTERN_FILL_CONTENTS) @@ -95,6 +95,7 @@ static void __libc_init_malloc_fill_contents() { scudo_malloc_set_zero_contents(1); #endif #endif + SetDefaultHeapTaggingLevel(); } __BIONIC_WEAK_FOR_NATIVE_BRIDGE @@ -119,9 +120,6 @@ void __libc_init_common() { __system_properties_init(); // Requires 'environ'. __libc_init_fdsan(); // Requires system properties (for debug.fdsan). __libc_init_fdtrack(); - - __libc_init_malloc_fill_contents(); - SetDefaultHeapTaggingLevel(); } void __libc_init_fork_handler() { diff --git a/libc/bionic/libc_init_common.h b/libc/bionic/libc_init_common.h index be7526f5f..a89908916 100644 --- a/libc/bionic/libc_init_common.h +++ b/libc/bionic/libc_init_common.h @@ -28,6 +28,7 @@ #pragma once +#include <stdint.h> #include <sys/cdefs.h> typedef void init_func_t(int, char*[], char*[]); @@ -57,6 +58,8 @@ __LIBC_HIDDEN__ void __libc_init_globals(); __LIBC_HIDDEN__ void __libc_init_common(); +__LIBC_HIDDEN__ void __libc_init_scudo(); + __LIBC_HIDDEN__ void __libc_init_AT_SECURE(char** envp); // The fork handler must be initialised after __libc_init_malloc, as diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp index c9da02eab..175fa3ee9 100644 --- a/libc/bionic/libc_init_dynamic.cpp +++ b/libc/bionic/libc_init_dynamic.cpp @@ -90,6 +90,7 @@ static void __libc_preinit_impl() { __libc_init_globals(); __libc_init_common(); + __libc_init_scudo(); // Hooks for various libraries to let them know that we're starting up. __libc_globals.mutate(__libc_init_malloc); diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp index 4a73918f2..2e4ee11a9 100644 --- a/libc/bionic/libc_init_static.cpp +++ b/libc/bionic/libc_init_static.cpp @@ -39,13 +39,17 @@ #include "libc_init_common.h" #include "pthread_internal.h" +#include "platform/bionic/macros.h" +#include "platform/bionic/mte.h" #include "platform/bionic/page.h" +#include "private/KernelArgumentBlock.h" +#include "private/bionic_asm.h" +#include "private/bionic_asm_note.h" #include "private/bionic_call_ifunc_resolver.h" #include "private/bionic_elf_tls.h" #include "private/bionic_globals.h" -#include "platform/bionic/macros.h" #include "private/bionic_tls.h" -#include "private/KernelArgumentBlock.h" +#include "sys/system_properties.h" #if __has_feature(hwaddress_sanitizer) #include <sanitizer/hwasan_interface.h> @@ -59,6 +63,7 @@ __LIBC_HIDDEN__ void* __libc_sysinfo; #endif extern "C" int __cxa_atexit(void (*)(void *), void *, void *); +extern "C" const char* __gnu_basename(const char* path); static void call_array(init_func_t** list, int argc, char* argv[], char* envp[]) { // First element is -1, list is null-terminated @@ -158,6 +163,170 @@ static void layout_static_tls(KernelArgumentBlock& args) { layout.finish_layout(); } +// Get the presiding config string, in the following order of priority: +// 1. Environment variables. +// 2. System properties, in the order they're specified in sys_prop_names. +// If neither of these options are specified, this function returns false. +// Otherwise, it returns true, and the presiding options string is written to +// the `options` buffer of size `size`. If this function returns true, `options` +// is guaranteed to be null-terminated. `options_size` should be at least +// PROP_VALUE_MAX. +bool get_config_from_env_or_sysprops(const char* env_var_name, const char* const* sys_prop_names, + size_t sys_prop_names_size, char* options, + size_t options_size) { + const char* env = getenv(env_var_name); + if (env && *env != '\0') { + strncpy(options, env, options_size); + options[options_size - 1] = '\0'; // Ensure null-termination. + return true; + } + + for (size_t i = 0; i < sys_prop_names_size; ++i) { + if (__system_property_get(sys_prop_names[i], options) && *options != '\0') return true; + } + return false; +} + +#ifdef __aarch64__ +static bool __read_memtag_note(const ElfW(Nhdr)* note, const char* name, const char* desc, + unsigned* result) { + if (note->n_namesz != 8 || strncmp(name, "Android", 8) != 0) { + return false; + } + if (note->n_type != NT_TYPE_MEMTAG) { + return false; + } + if (note->n_descsz != 4) { + async_safe_fatal("unrecognized android.memtag note: n_descsz = %d, expected 4", note->n_descsz); + } + *result = *reinterpret_cast<const ElfW(Word)*>(desc); + return true; +} + +static unsigned __get_memtag_note(const ElfW(Phdr)* phdr_start, size_t phdr_ct, + const ElfW(Addr) load_bias) { + for (size_t i = 0; i < phdr_ct; ++i) { + const ElfW(Phdr)* phdr = &phdr_start[i]; + if (phdr->p_type != PT_NOTE) { + continue; + } + ElfW(Addr) p = load_bias + phdr->p_vaddr; + ElfW(Addr) note_end = load_bias + phdr->p_vaddr + phdr->p_memsz; + while (p + sizeof(ElfW(Nhdr)) <= note_end) { + const ElfW(Nhdr)* note = reinterpret_cast<const ElfW(Nhdr)*>(p); + p += sizeof(ElfW(Nhdr)); + const char* name = reinterpret_cast<const char*>(p); + p += align_up(note->n_namesz, 4); + const char* desc = reinterpret_cast<const char*>(p); + p += align_up(note->n_descsz, 4); + if (p > note_end) { + break; + } + unsigned ret; + if (__read_memtag_note(note, name, desc, &ret)) { + return ret; + } + } + } + return 0; +} + +// Returns true if there's an environment setting (either sysprop or env var) +// that should overwrite the ELF note, and places the equivalent heap tagging +// level into *level. +static bool get_environment_memtag_setting(HeapTaggingLevel* level) { + static const char kMemtagPrognameSyspropPrefix[] = "arm64.memtag.process."; + + const char* progname = __libc_shared_globals()->init_progname; + if (progname == nullptr) return false; + + const char* basename = __gnu_basename(progname); + + static constexpr size_t kOptionsSize = PROP_VALUE_MAX; + char options_str[kOptionsSize]; + size_t sysprop_size = strlen(basename) + strlen(kMemtagPrognameSyspropPrefix) + 1; + char* sysprop_name = static_cast<char*>(alloca(sysprop_size)); + + async_safe_format_buffer(sysprop_name, sysprop_size, "%s%s", kMemtagPrognameSyspropPrefix, + basename); + + if (!get_config_from_env_or_sysprops("MEMTAG_OPTIONS", &sysprop_name, + /* sys_prop_names_size */ 1, options_str, kOptionsSize)) { + return false; + } + + if (strcmp("sync", options_str) == 0) { + *level = M_HEAP_TAGGING_LEVEL_SYNC; + } else if (strcmp("async", options_str) == 0) { + *level = M_HEAP_TAGGING_LEVEL_ASYNC; + } else if (strcmp("off", options_str) == 0) { + *level = M_HEAP_TAGGING_LEVEL_TBI; + } else { + async_safe_format_log( + ANDROID_LOG_ERROR, "libc", + "unrecognized memtag level: \"%s\" (options are \"sync\", \"async\", or \"off\").", + options_str); + return false; + } + + return true; +} + +// Returns the initial heap tagging level. Note: This function will never return +// M_HEAP_TAGGING_LEVEL_NONE, if MTE isn't enabled for this process we enable +// M_HEAP_TAGGING_LEVEL_TBI. +static HeapTaggingLevel __get_heap_tagging_level(const void* phdr_start, size_t phdr_ct, + uintptr_t load_bias) { + HeapTaggingLevel level; + if (get_environment_memtag_setting(&level)) return level; + + unsigned note_val = + __get_memtag_note(reinterpret_cast<const ElfW(Phdr)*>(phdr_start), phdr_ct, load_bias); + if (note_val & ~(NT_MEMTAG_LEVEL_MASK | NT_MEMTAG_HEAP)) { + async_safe_fatal("unrecognized android.memtag note: desc = %d", note_val); + } + + if (!(note_val & NT_MEMTAG_HEAP)) return M_HEAP_TAGGING_LEVEL_TBI; + + unsigned memtag_level = note_val & NT_MEMTAG_LEVEL_MASK; + switch (memtag_level) { + case NT_MEMTAG_LEVEL_ASYNC: + return M_HEAP_TAGGING_LEVEL_ASYNC; + case NT_MEMTAG_LEVEL_DEFAULT: + case NT_MEMTAG_LEVEL_SYNC: + return M_HEAP_TAGGING_LEVEL_SYNC; + default: + async_safe_fatal("unrecognized android.memtag note: level = %d", memtag_level); + } +} + +// 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(const void* phdr_start, + size_t phdr_ct, + uintptr_t load_bias) { + HeapTaggingLevel level = __get_heap_tagging_level(phdr_start, phdr_ct, load_bias); + + if (level == M_HEAP_TAGGING_LEVEL_SYNC || level == M_HEAP_TAGGING_LEVEL_ASYNC) { + unsigned long prctl_arg = PR_TAGGED_ADDR_ENABLE | PR_MTE_TAG_SET_NONZERO; + prctl_arg |= (level == M_HEAP_TAGGING_LEVEL_SYNC) ? PR_MTE_TCF_SYNC : PR_MTE_TCF_ASYNC; + + if (prctl(PR_SET_TAGGED_ADDR_CTRL, prctl_arg, 0, 0, 0) == 0) { + __libc_shared_globals()->initial_heap_tagging_level = level; + return; + } + } + + // MTE was either not enabled, or wasn't supported on this device. Try and use + // TBI. + if (prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0) == 0) { + __libc_shared_globals()->initial_heap_tagging_level = M_HEAP_TAGGING_LEVEL_TBI; + } +} +#else // __aarch64__ +void __libc_init_mte(const void*, size_t, uintptr_t) {} +#endif // __aarch64__ + __noreturn static void __real_libc_init(void *raw_args, void (*onexit)(void) __unused, int (*slingshot)(int, char**, char**), @@ -175,6 +344,9 @@ __noreturn static void __real_libc_init(void *raw_args, layout_static_tls(args); __libc_init_main_thread_final(); __libc_init_common(); + __libc_init_mte(reinterpret_cast<ElfW(Phdr)*>(getauxval(AT_PHDR)), getauxval(AT_PHNUM), + /*load_bias = */ 0); + __libc_init_scudo(); __libc_init_fork_handler(); call_ifunc_resolvers(); diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp index 0ee12a7fd..863103deb 100644 --- a/libc/bionic/malloc_common.cpp +++ b/libc/bionic/malloc_common.cpp @@ -102,6 +102,15 @@ extern "C" int malloc_info(int options, FILE* fp) { } extern "C" int mallopt(int param, int value) { + // Some are handled by libc directly rather than by the allocator. + if (param == M_BIONIC_SET_HEAP_TAGGING_LEVEL) { + ScopedPthreadMutexLocker locker(&g_heap_tagging_lock); + return SetHeapTaggingLevel(static_cast<HeapTaggingLevel>(value)); + } + if (param == M_BIONIC_DISABLE_MEMORY_MITIGATIONS) { + return DisableMemoryMitigations(value); + } + // The rest we pass on... auto dispatch_table = GetDispatchTable(); if (__predict_false(dispatch_table != nullptr)) { return dispatch_table->mallopt(param, value); @@ -316,10 +325,6 @@ extern "C" bool android_mallopt(int opcode, void* arg, size_t arg_size) { if (opcode == M_SET_ALLOCATION_LIMIT_BYTES) { return LimitEnable(arg, arg_size); } - if (opcode == M_SET_HEAP_TAGGING_LEVEL) { - ScopedPthreadMutexLocker locker(&g_heap_tagging_lock); - return SetHeapTaggingLevel(arg, arg_size); - } if (opcode == M_INITIALIZE_GWP_ASAN) { if (arg == nullptr || arg_size != sizeof(bool)) { errno = EINVAL; @@ -329,9 +334,6 @@ extern "C" bool android_mallopt(int opcode, void* arg, size_t arg_size) { return MaybeInitGwpAsan(globals, *reinterpret_cast<bool*>(arg)); }); } - if (opcode == M_DISABLE_MEMORY_MITIGATIONS) { - return DisableMemoryMitigations(arg, arg_size); - } errno = ENOTSUP; return false; } diff --git a/libc/bionic/malloc_common_dynamic.cpp b/libc/bionic/malloc_common_dynamic.cpp index 2d6a1bbcb..7a221d891 100644 --- a/libc/bionic/malloc_common_dynamic.cpp +++ b/libc/bionic/malloc_common_dynamic.cpp @@ -523,10 +523,6 @@ extern "C" bool android_mallopt(int opcode, void* arg, size_t arg_size) { } return FreeMallocLeakInfo(reinterpret_cast<android_mallopt_leak_info_t*>(arg)); } - if (opcode == M_SET_HEAP_TAGGING_LEVEL) { - ScopedPthreadMutexLocker locker(&g_heap_tagging_lock); - return SetHeapTaggingLevel(arg, arg_size); - } if (opcode == M_INITIALIZE_GWP_ASAN) { if (arg == nullptr || arg_size != sizeof(bool)) { errno = EINVAL; @@ -536,9 +532,6 @@ extern "C" bool android_mallopt(int opcode, void* arg, size_t arg_size) { return MaybeInitGwpAsan(globals, *reinterpret_cast<bool*>(arg)); }); } - if (opcode == M_DISABLE_MEMORY_MITIGATIONS) { - return DisableMemoryMitigations(arg, arg_size); - } // Try heapprofd's mallopt, as it handles options not covered here. return HeapprofdMallopt(opcode, arg, arg_size); } diff --git a/libc/bionic/malloc_tagged_pointers.h b/libc/bionic/malloc_tagged_pointers.h index de3cc2ed9..484a0802e 100644 --- a/libc/bionic/malloc_tagged_pointers.h +++ b/libc/bionic/malloc_tagged_pointers.h @@ -99,9 +99,10 @@ static inline void* MaybeUntagAndCheckPointer(const volatile void* ptr) { // check below allows us to turn *off* pointer tagging (by setting PointerCheckMask() and // FixedPointerTag() to zero) and still allow tagged heap allocations to be freed. if ((ptr_int & PointerCheckMask()) != FixedPointerTag()) { - // TODO(b/145604058) - Upstream tagged pointers documentation and provide - // a link to it in the abort message here. - async_safe_fatal("Pointer tag for %p was truncated.", ptr); + async_safe_fatal( + "Pointer tag for %p was truncated, see " + "'https://source.android.com/devices/tech/debug/tagged-pointers'.", + ptr); } return reinterpret_cast<void*>(ptr_int & PointerUntagMask()); } diff --git a/libc/bionic/memory_mitigation_state.cpp b/libc/bionic/memory_mitigation_state.cpp index 4761d8862..b262f8616 100644 --- a/libc/bionic/memory_mitigation_state.cpp +++ b/libc/bionic/memory_mitigation_state.cpp @@ -47,8 +47,8 @@ extern "C" void scudo_malloc_set_zero_contents(int zero_contents); -bool DisableMemoryMitigations(void* arg, size_t arg_size) { - if (arg || arg_size) { +bool DisableMemoryMitigations(int arg) { + if (arg != 0) { return false; } @@ -61,7 +61,7 @@ bool DisableMemoryMitigations(void* arg, size_t arg_size) { HeapTaggingLevel current_level = GetHeapTaggingLevel(); if (current_level != M_HEAP_TAGGING_LEVEL_NONE && current_level != M_HEAP_TAGGING_LEVEL_TBI) { HeapTaggingLevel level = M_HEAP_TAGGING_LEVEL_NONE; - SetHeapTaggingLevel(reinterpret_cast<void*>(&level), sizeof(level)); + SetHeapTaggingLevel(level); } return true; diff --git a/libc/bionic/memory_mitigation_state.h b/libc/bionic/memory_mitigation_state.h index ffa19121d..047b6ad3a 100644 --- a/libc/bionic/memory_mitigation_state.h +++ b/libc/bionic/memory_mitigation_state.h @@ -30,4 +30,4 @@ #include <stddef.h> -bool DisableMemoryMitigations(void* arg, size_t arg_size); +bool DisableMemoryMitigations(int arg); diff --git a/libc/bionic/recvmsg.cpp b/libc/bionic/recvmsg.cpp index 003f43d8a..4d3f98939 100644 --- a/libc/bionic/recvmsg.cpp +++ b/libc/bionic/recvmsg.cpp @@ -39,7 +39,7 @@ extern "C" int __recvmmsg(int __fd, struct mmsghdr* __msgs, unsigned int __msg_c static inline __attribute__((artificial)) __attribute__((always_inline)) void track_fds( struct msghdr* msg, const char* function_name) { - if (!__android_fdtrack_hook) { + if (!atomic_load(&__android_fdtrack_hook)) { return; } diff --git a/libc/dns/net/gethnamaddr.c b/libc/dns/net/gethnamaddr.c index 84942f876..f8212a295 100644 --- a/libc/dns/net/gethnamaddr.c +++ b/libc/dns/net/gethnamaddr.c @@ -75,9 +75,6 @@ #include <syslog.h> #include <unistd.h> -#define ALIGNBYTES (sizeof(uintptr_t) - 1) -#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES) - #ifndef LOG_AUTH # define LOG_AUTH 0 #endif diff --git a/libc/dns/net/sethostent.c b/libc/dns/net/sethostent.c index a743a543e..b2b0132c5 100644 --- a/libc/dns/net/sethostent.c +++ b/libc/dns/net/sethostent.c @@ -55,9 +55,6 @@ __RCSID("$NetBSD: sethostent.c,v 1.20 2014/03/17 13:24:23 christos Exp $"); #include "hostent.h" #include "resolv_private.h" -#define ALIGNBYTES (sizeof(uintptr_t) - 1) -#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES) - #ifndef _REENTRANT void res_close(void); #endif diff --git a/libc/include/android/api-level.h b/libc/include/android/api-level.h index bcddddd59..40846fb8b 100644 --- a/libc/include/android/api-level.h +++ b/libc/include/android/api-level.h @@ -151,6 +151,9 @@ __BEGIN_DECLS /** Names the "S" API level (31), for comparison against `__ANDROID_API__`. */ #define __ANDROID_API_S__ 31 +/* This file is included in <features.h>, and might be used from .S files. */ +#if !defined(__ASSEMBLY__) + /** * Returns the `targetSdkVersion` of the caller, or `__ANDROID_API_FUTURE__` if * there is no known target SDK version (for code not running in the context of @@ -167,7 +170,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. +/* android_get_device_api_level is a static inline before API level 29. */ #define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline #include <bits/get_device_api_level_inlines.h> #undef __BIONIC_GET_DEVICE_API_LEVEL_INLINE @@ -185,6 +188,8 @@ int android_get_device_api_level() __INTRODUCED_IN(29); #endif +#endif /* defined(__ASSEMBLY__) */ + __END_DECLS /** @} */ diff --git a/libc/include/android/legacy_signal_inlines.h b/libc/include/android/legacy_signal_inlines.h index 90eda7dc1..a6734464c 100644 --- a/libc/include/android/legacy_signal_inlines.h +++ b/libc/include/android/legacy_signal_inlines.h @@ -45,12 +45,16 @@ int __libc_current_sigrtmax() __attribute__((__weak__)) __VERSIONER_NO_GUARD; int __libc_current_sigrtmin() __attribute__((__weak__)) __VERSIONER_NO_GUARD; static __inline int __ndk_legacy___libc_current_sigrtmax() { - if (__libc_current_sigrtmax) return __libc_current_sigrtmax(); + if (__builtin_available(android 21, *)) { + return __libc_current_sigrtmax(); + } return __SIGRTMAX; /* Should match __libc_current_sigrtmax. */ } static __inline int __ndk_legacy___libc_current_sigrtmin() { - if (__libc_current_sigrtmin) return __libc_current_sigrtmin(); + if (__builtin_available(android 21, *)) { + return __libc_current_sigrtmin(); + } return __SIGRTMIN + 7; /* Should match __libc_current_sigrtmin. */ } diff --git a/libc/include/android/versioning.h b/libc/include/android/versioning.h index 3ea414a45..2b9a0272b 100644 --- a/libc/include/android/versioning.h +++ b/libc/include/android/versioning.h @@ -33,13 +33,62 @@ #else -#define __INTRODUCED_IN(api_level) -#define __DEPRECATED_IN(api_level) -#define __REMOVED_IN(api_level) -#define __INTRODUCED_IN_32(api_level) +// When headers are not processed by the versioner (i.e. compiled into object files), +// the availability attributed is emitted instead. The clang compiler will make the symbol weak +// when targeting old api_level and enforce the reference to the symbol to be guarded with +// __builtin_available(android api_level, *). + +// The 'strict' flag is required for NDK clients where the use of "-Wunguarded-availability" cannot +// be enforced. In the case, the absence of 'strict' makes it possible to call an unavailable API +// without the __builtin_available check, which will cause a link error at runtime. +// Android platform build system defines this macro along with -Wunguarded-availability +#if defined(__ANDROID_UNGUARDED_AVAILABILITY__) +#define __MAYBE_STRICT +#else +#define __MAYBE_STRICT ,strict +#endif + +#define __INTRODUCED_IN(api_level) \ + __attribute__((availability(android __MAYBE_STRICT,introduced=api_level))) +#define __DEPRECATED_IN(api_level) \ + __attribute__((availability(android __MAYBE_STRICT,deprecated=api_level))) +#define __REMOVED_IN(api_level) \ + __attribute__((availability(android __MAYBE_STRICT,obsoleted=api_level))) + +// 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 +// cause inconsistent availability values which is an error with -Wavailability: +// +// void foo() __INTRODUCED_IN_32(30) __INTRODUCED_IN_64(31); +// +// This also takes the advantage of the fact that we never use bitness-specific macro with +// arch-specific macro. In other words, +// +// void foo() __INTRODUCED_IN_ARM(30) __INTRODUCED_IN_64(31); +// +// hasn't been supported and won't be. +#if !defined(__LP64__) +#define __INTRODUCED_IN_32(api_level) \ + __attribute__((availability(android __MAYBE_STRICT,introduced=api_level))) #define __INTRODUCED_IN_64(api_level) +#else +#define __INTRODUCED_IN_32(api_level) +#define __INTRODUCED_IN_64(api_level) \ + __attribute__((availability(android __MAYBE_STRICT,introduced=api_level))) +#endif + +#if defined(__arm__) || defined(__aarch64__) +#define __INTRODUCED_IN_ARM(api_level) \ + __attribute__((availability(android __MAYBE_STRICT,introduced=api_level))) +#define __INTRODUCED_IN_X86(api_level) +#elif defined(__i386__) || defined(__x86_64__) +#define __INTRODUCED_IN_ARM(api_level) +#define __INTRODUCED_IN_X86(api_level) \ + __attribute__((availability(android __MAYBE_STRICT,introduced=api_level))) +#else #define __INTRODUCED_IN_ARM(api_level) #define __INTRODUCED_IN_X86(api_level) +#endif #define __VERSIONER_NO_GUARD #define __VERSIONER_FORTIFY_INLINE diff --git a/libc/include/malloc.h b/libc/include/malloc.h index a237254b7..598a50bc5 100644 --- a/libc/include/malloc.h +++ b/libc/include/malloc.h @@ -204,6 +204,60 @@ int malloc_info(int __must_be_zero, FILE* __fp) __INTRODUCED_IN(23); #define M_TSDS_COUNT_MAX (-202) /** + * mallopt() option to disable heap initialization across the whole process. + * If the hardware supports memory tagging, this also disables memory tagging. + * May be called at any time, including when multiple threads are running. The + * value is unused but must be set to 0. + * + * Note that these memory mitigations are only implemented in scudo and + * therefore this will have no effect when using another allocator (such as + * jemalloc on Android Go devices). + * + * Available since API level 31. + */ +#define M_BIONIC_DISABLE_MEMORY_MITIGATIONS (-203) + +/** + * mallopt() option to change the heap tagging state. May be called at any + * time, including when multiple threads are running. + * The value must be one of the M_HEAP_TAGGING_LEVEL_ constants. + * + * Available since API level 31. + */ +#define M_BIONIC_SET_HEAP_TAGGING_LEVEL (-204) + +/** + * Constants for use with the M_BIONIC_SET_HEAP_TAGGING_LEVEL mallopt() option. + */ +enum HeapTaggingLevel { + /** + * Disable heap tagging and memory tag checks (if supported). + * Heap tagging may not be re-enabled after being disabled. + */ + M_HEAP_TAGGING_LEVEL_NONE = 0, +#define M_HEAP_TAGGING_LEVEL_NONE M_HEAP_TAGGING_LEVEL_NONE + /** + * Address-only tagging. Heap pointers have a non-zero tag in the + * most significant ("top") byte which is checked in free(). Memory + * accesses ignore the tag using arm64's Top Byte Ignore (TBI) feature. + */ + M_HEAP_TAGGING_LEVEL_TBI = 1, +#define M_HEAP_TAGGING_LEVEL_TBI M_HEAP_TAGGING_LEVEL_TBI + /** + * Enable heap tagging and asynchronous memory tag checks (if supported). + * Disable stack trace collection. + */ + M_HEAP_TAGGING_LEVEL_ASYNC = 2, +#define M_HEAP_TAGGING_LEVEL_ASYNC M_HEAP_TAGGING_LEVEL_ASYNC + /** + * Enable heap tagging and synchronous memory tag checks (if supported). + * Enable stack trace collection. + */ + M_HEAP_TAGGING_LEVEL_SYNC = 3, +#define M_HEAP_TAGGING_LEVEL_SYNC M_HEAP_TAGGING_LEVEL_SYNC +}; + +/** * [mallopt(3)](http://man7.org/linux/man-pages/man3/mallopt.3.html) modifies * heap behavior. Values of `__option` are the `M_` constants from this header. * diff --git a/libc/platform/bionic/malloc.h b/libc/platform/bionic/malloc.h index 56badf0fd..b56ca746a 100644 --- a/libc/platform/bionic/malloc.h +++ b/libc/platform/bionic/malloc.h @@ -28,6 +28,7 @@ #pragma once +#include <malloc.h> #include <stdbool.h> #include <stdint.h> @@ -85,12 +86,6 @@ enum { // arg_size = sizeof(android_mallopt_leak_info_t) M_FREE_MALLOC_LEAK_INFO = 7, #define M_FREE_MALLOC_LEAK_INFO M_FREE_MALLOC_LEAK_INFO - // Change the heap tagging state. May be called at any time including when - // multiple threads are running. - // arg = HeapTaggingLevel* - // arg_size = sizeof(HeapTaggingLevel) - M_SET_HEAP_TAGGING_LEVEL = 8, -#define M_SET_HEAP_TAGGING_LEVEL M_SET_HEAP_TAGGING_LEVEL // Query whether the current process is considered to be profileable by the // Android platform. Result is assigned to the arg pointer's destination. // arg = bool* @@ -105,28 +100,6 @@ enum { // arg_size = sizeof(bool) M_INITIALIZE_GWP_ASAN = 10, #define M_INITIALIZE_GWP_ASAN M_INITIALIZE_GWP_ASAN - // Disable heap initialization across the whole process. If the hardware supports memory - // tagging, it also disables memory tagging. May be called at any time including - // when multiple threads are running. arg and arg_size are unused and must be set to 0. - // Note that the memory mitigations are only implemented in scudo and therefore this API call will - // have no effect when using another allocator. - M_DISABLE_MEMORY_MITIGATIONS = 11, -#define M_DISABLE_MEMORY_MITIGATIONS M_DISABLE_MEMORY_MITIGATIONS -}; - -enum HeapTaggingLevel { - // Disable heap tagging and memory tag checks if supported. Heap tagging may not be re-enabled - // after being disabled. - M_HEAP_TAGGING_LEVEL_NONE = 0, - // Address-only tagging. Heap pointers have a non-zero tag in the most significant byte which is - // checked in free(). Memory accesses ignore the tag. - M_HEAP_TAGGING_LEVEL_TBI = 1, - // Enable heap tagging and asynchronous memory tag checks if supported. Disable stack trace - // collection. - M_HEAP_TAGGING_LEVEL_ASYNC = 2, - // Enable heap tagging and synchronous memory tag checks if supported. Enable stack trace - // collection. - M_HEAP_TAGGING_LEVEL_SYNC = 3, }; // Manipulates bionic-specific handling of memory allocation APIs such as diff --git a/libc/platform/bionic/mte.h b/libc/platform/bionic/mte.h index 1e393eb0c..73cd821b6 100644 --- a/libc/platform/bionic/mte.h +++ b/libc/platform/bionic/mte.h @@ -29,10 +29,16 @@ #pragma once #include <sys/auxv.h> -#include <bionic/mte_kernel.h> +#include <sys/prctl.h> + +// Note: Most PR_MTE_* constants come from the upstream kernel. This tag mask +// allows for the hardware to provision any nonzero tag. Zero tags are reserved +// for scudo to use for the chunk headers in order to prevent linear heap +// overflow/underflow. +#define PR_MTE_TAG_SET_NONZERO (0xfffeUL << PR_MTE_TAG_SHIFT) inline bool mte_supported() { -#if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE) +#if defined(__aarch64__) static bool supported = getauxval(AT_HWCAP2) & HWCAP2_MTE; #else static bool supported = false; diff --git a/libc/private/bionic_asm.h b/libc/private/bionic_asm.h index 6d4f7d52c..d68a2d604 100644 --- a/libc/private/bionic_asm.h +++ b/libc/private/bionic_asm.h @@ -26,8 +26,10 @@ * SUCH DAMAGE. */ -#ifndef _PRIVATE_BIONIC_ASM_H_ -#define _PRIVATE_BIONIC_ASM_H_ +#pragma once + +/* https://github.com/android/ndk/issues/1422 */ +#include <features.h> #include <asm/unistd.h> /* For system call numbers. */ #define MAX_ERRNO 4095 /* For recognizing system call error returns. */ @@ -86,5 +88,3 @@ #define NOTE_GNU_PROPERTY() \ __bionic_asm_custom_note_gnu_section() - -#endif diff --git a/libc/private/bionic_asm_arm64.h b/libc/private/bionic_asm_arm64.h index c11732ae8..e73f25d36 100644 --- a/libc/private/bionic_asm_arm64.h +++ b/libc/private/bionic_asm_arm64.h @@ -69,4 +69,10 @@ .long (__bionic_asm_aarch64_feature_pac | \ __bionic_asm_aarch64_feature_bti); \ .long 0; \ - .popsection; \ + .popsection; + +#define NT_MEMTAG_LEVEL_MASK 3 +#define NT_MEMTAG_LEVEL_DEFAULT 0 +#define NT_MEMTAG_LEVEL_ASYNC 1 +#define NT_MEMTAG_LEVEL_SYNC 2 +#define NT_MEMTAG_HEAP 4 diff --git a/libc/platform/bionic/mte_kernel.h b/libc/private/bionic_asm_note.h index d81480aa7..80b8f011c 100644 --- a/libc/platform/bionic/mte_kernel.h +++ b/libc/private/bionic_asm_note.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2021 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,32 +28,6 @@ #pragma once -// Defines constants used as part of the interface in an experimental MTE branch -// of the Linux kernel, which may be found at: -// -// https://github.com/pcc/linux/tree/android-experimental-mte -// -// This interface should not be considered to be stable. - -#ifdef ANDROID_EXPERIMENTAL_MTE - -#define HWCAP2_MTE (1 << 18) -#define PROT_MTE 0x20 - -#define PR_MTE_TCF_SHIFT 1 -#define PR_MTE_TCF_NONE (0UL << PR_MTE_TCF_SHIFT) -#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_TAG_SHIFT 3 -#define PR_MTE_TAG_MASK (0xffffUL << PR_MTE_TAG_SHIFT) - -#define SEGV_MTEAERR 8 -#define SEGV_MTESERR 9 - -#define PTRACE_PEEKMTETAGS 33 -#define PTRACE_POKEMTETAGS 34 - -#define NT_ARM_TAGGED_ADDR_CTRL 0x409 - -#endif +#define NT_TYPE_IDENT 1 +#define NT_TYPE_KUSER 3 +#define NT_TYPE_MEMTAG 4 diff --git a/libc/private/bionic_fdtrack.h b/libc/private/bionic_fdtrack.h index 752dd8dc5..259897c22 100644 --- a/libc/private/bionic_fdtrack.h +++ b/libc/private/bionic_fdtrack.h @@ -58,7 +58,7 @@ extern "C" _Atomic(android_fdtrack_hook_t) __android_fdtrack_hook; event.fd = __fd; \ event.type = ANDROID_FDTRACK_EVENT_TYPE_CREATE; \ event.data.create.function_name = name; \ - __android_fdtrack_hook(&event); \ + atomic_load(&__android_fdtrack_hook)(&event); \ tls.fdtrack_disabled = false; \ } \ } \ @@ -86,7 +86,7 @@ extern "C" _Atomic(android_fdtrack_hook_t) __android_fdtrack_hook; android_fdtrack_event event; \ event.fd = __fd; \ event.type = ANDROID_FDTRACK_EVENT_TYPE_CLOSE; \ - __android_fdtrack_hook(&event); \ + atomic_load(&__android_fdtrack_hook)(&event); \ tls.fdtrack_disabled = false; \ errno = saved_errno; \ } \ diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h index 5c9b726d2..813226172 100644 --- a/libc/private/bionic_globals.h +++ b/libc/private/bionic_globals.h @@ -41,6 +41,8 @@ #include "private/bionic_vdso.h" #include "private/WriteProtected.h" +#include <platform/bionic/malloc.h> + struct libc_globals { vdso_entry vdso[VDSO_END]; long setjmp_cookie; @@ -106,6 +108,8 @@ struct libc_shared_globals { const char* scudo_stack_depot = nullptr; const char* scudo_region_info = nullptr; + + HeapTaggingLevel initial_heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE; }; __LIBC_HIDDEN__ libc_shared_globals* __libc_shared_globals(); diff --git a/libc/private/bsd_sys_param.h b/libc/private/bsd_sys_param.h new file mode 100644 index 000000000..8c936c459 --- /dev/null +++ b/libc/private/bsd_sys_param.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +/* OpenBSD has these in <sys/param.h>, but "ALIGN" isn't something we want to reserve. */ +#define ALIGNBYTES (sizeof(uintptr_t) - 1) +#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) & ~ALIGNBYTES) diff --git a/libc/stdio/stdio.cpp b/libc/stdio/stdio.cpp index b8aced83b..c7b1ba459 100644 --- a/libc/stdio/stdio.cpp +++ b/libc/stdio/stdio.cpp @@ -57,8 +57,7 @@ #include "private/ErrnoRestorer.h" #include "private/thread_private.h" -#define ALIGNBYTES (sizeof(uintptr_t) - 1) -#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES) +#include "private/bsd_sys_param.h" // For ALIGN/ALIGNBYTES. #define NDYNAMIC 10 /* add ten more whenever necessary */ diff --git a/libc/system_properties/context_lookup_benchmark_data.h b/libc/system_properties/context_lookup_benchmark_data.h index 3cc325724..b928875dd 100644 --- a/libc/system_properties/context_lookup_benchmark_data.h +++ b/libc/system_properties/context_lookup_benchmark_data.h @@ -885,7 +885,6 @@ ro.hwui.use_vulkan u:object_r:exported_default_prop:s0 exact bool ro.kernel.qemu u:object_r:exported_default_prop:s0 exact bool ro.kernel.qemu. u:object_r:exported_default_prop:s0 ro.kernel.android.bootanim u:object_r:exported_default_prop:s0 exact int -ro.kernel.ebpf.supported u:object_r:exported_default_prop:s0 exact bool ro.oem.key1 u:object_r:exported_default_prop:s0 exact string diff --git a/libc/upstream-openbsd/android/include/openbsd-compat.h b/libc/upstream-openbsd/android/include/openbsd-compat.h index 2fc5046ad..6c21c5b49 100644 --- a/libc/upstream-openbsd/android/include/openbsd-compat.h +++ b/libc/upstream-openbsd/android/include/openbsd-compat.h @@ -25,6 +25,8 @@ #include <sys/random.h> // For getentropy. +#include "private/bsd_sys_param.h" + #define __BEGIN_HIDDEN_DECLS _Pragma("GCC visibility push(hidden)") #define __END_HIDDEN_DECLS _Pragma("GCC visibility pop") @@ -57,10 +59,6 @@ extern const char* __progname; #define explicit_bzero(p, s) memset(p, 0, s) -/* OpenBSD has these in <sys/param.h>, but "ALIGN" isn't something we want to reserve. */ -#define ALIGNBYTES (sizeof(uintptr_t) - 1) -#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES) - /* OpenBSD has this in paths.h. But this directory doesn't normally exist. * Even when it does exist, only the 'shell' user has permissions. */ diff --git a/libdl/Android.bp b/libdl/Android.bp index 9a31d360c..91f85f916 100644 --- a/libdl/Android.bp +++ b/libdl/Android.bp @@ -216,7 +216,6 @@ cc_library { ndk_library { name: "libdl", - native_bridge_supported: true, symbol_file: "libdl.map.txt", first_version: "9", } diff --git a/libm/Android.bp b/libm/Android.bp index 6c8ad2254..21be51ba0 100644 --- a/libm/Android.bp +++ b/libm/Android.bp @@ -516,7 +516,6 @@ cc_library { ndk_library { name: "libm", - native_bridge_supported: true, symbol_file: "libm.map.txt", first_version: "9", } diff --git a/linker/Android.bp b/linker/Android.bp index 3ebae59d9..efda312e7 100644 --- a/linker/Android.bp +++ b/linker/Android.bp @@ -232,19 +232,15 @@ cc_defaults { arch: { arm: { srcs: [":linker_sources_arm"], - static_libs: ["libunwind_llvm"], }, arm64: { srcs: [":linker_sources_arm64"], - static_libs: ["libgcc_stripped"], }, x86: { srcs: [":linker_sources_x86"], - static_libs: ["libgcc_stripped"], }, x86_64: { srcs: [":linker_sources_x86_64"], - static_libs: ["libgcc_stripped"], }, }, @@ -292,6 +288,7 @@ cc_defaults { "libc_nomalloc", "libc_dynamic_dispatch", "libm", + "libunwind", ], // Ensure that if the linker needs __gnu_Unwind_Find_exidx, then the linker will have a diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp index ec6850a40..af050274d 100644 --- a/linker/dlfcn.cpp +++ b/linker/dlfcn.cpp @@ -332,7 +332,8 @@ soinfo* get_libdl_info(const soinfo& linker_si) { __libdl_info->target_sdk_version_ = __ANDROID_API__; __libdl_info->generate_handle(); #if defined(__work_around_b_24465209__) - strlcpy(__libdl_info->old_name_, __libdl_info->soname_, sizeof(__libdl_info->old_name_)); + strlcpy(__libdl_info->old_name_, __libdl_info->soname_.c_str(), + sizeof(__libdl_info->old_name_)); #endif } diff --git a/linker/linker.cpp b/linker/linker.cpp index 2481be4e4..c240c5639 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -1339,8 +1339,7 @@ static bool find_loaded_library_by_soname(android_namespace_t* ns, const char* name, soinfo** candidate) { return !ns->soinfo_list().visit([&](soinfo* si) { - const char* soname = si->get_soname(); - if (soname != nullptr && (strcmp(name, soname) == 0)) { + if (strcmp(name, si->get_soname()) == 0) { *candidate = si; return false; } @@ -2571,9 +2570,8 @@ bool VersionTracker::init_verneed(const soinfo* si_from) { const char* target_soname = si_from->get_string(verneed->vn_file); // find it in dependencies - soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) { - return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0; - }); + soinfo* target_si = si_from->get_children().find_if( + [&](const soinfo* si) { return strcmp(si->get_soname(), target_soname) == 0; }); if (target_si == nullptr) { DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"", @@ -3195,34 +3193,32 @@ bool soinfo::prelink_image() { return false; } - // second pass - parse entries relying on strtab - for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) { - switch (d->d_tag) { - case DT_SONAME: - set_soname(get_string(d->d_un.d_val)); - break; - case DT_RUNPATH: - set_dt_runpath(get_string(d->d_un.d_val)); - break; + // Second pass - parse entries relying on strtab. Skip this while relocating the linker so as to + // avoid doing heap allocations until later in the linker's initialization. + if (!relocating_linker) { + for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) { + switch (d->d_tag) { + case DT_SONAME: + set_soname(get_string(d->d_un.d_val)); + break; + case DT_RUNPATH: + set_dt_runpath(get_string(d->d_un.d_val)); + break; + } } } - // Before M release linker was using basename in place of soname. - // In the case when dt_soname is absent some apps stop working - // because they can't find dt_needed library by soname. - // This workaround should keep them working. (Applies only - // for apps targeting sdk version < M.) Make an exception for - // the main executable and linker; they do not need to have dt_soname. - // TODO: >= O the linker doesn't need this workaround. - if (soname_ == nullptr && - this != solist_get_somain() && - (flags_ & FLAG_LINKER) == 0 && + // Before M release, linker was using basename in place of soname. In the case when DT_SONAME is + // absent some apps stop working because they can't find DT_NEEDED library by soname. This + // workaround should keep them working. (Applies only for apps targeting sdk version < M.) Make + // an exception for the main executable, which does not need to have DT_SONAME. The linker has an + // DT_SONAME but the soname_ field is initialized later on. + if (soname_.empty() && this != solist_get_somain() && !relocating_linker && get_application_target_sdk_version() < 23) { soname_ = basename(realpath_.c_str()); - DL_WARN_documented_change(23, - "missing-soname-enforced-for-api-level-23", - "\"%s\" has no DT_SONAME (will use %s instead)", - get_realpath(), soname_); + DL_WARN_documented_change(23, "missing-soname-enforced-for-api-level-23", + "\"%s\" has no DT_SONAME (will use %s instead)", get_realpath(), + soname_.c_str()); // Don't call add_dlwarning because a missing DT_SONAME isn't important enough to show in the UI } diff --git a/linker/linker_cfi.cpp b/linker/linker_cfi.cpp index 87b5d3485..6bc261545 100644 --- a/linker/linker_cfi.cpp +++ b/linker/linker_cfi.cpp @@ -133,8 +133,7 @@ void CFIShadowWriter::Add(uintptr_t begin, uintptr_t end, uintptr_t cfi_check) { static soinfo* find_libdl(soinfo* solist) { for (soinfo* si = solist; si != nullptr; si = si->next) { - const char* soname = si->get_soname(); - if (soname && strcmp(soname, "libdl.so") == 0) { + if (strcmp(si->get_soname(), "libdl.so") == 0) { return si; } } diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp index aad8f6f6f..0b501a7b1 100644 --- a/linker/linker_main.cpp +++ b/linker/linker_main.cpp @@ -66,6 +66,8 @@ static void get_elf_base_from_phdr(const ElfW(Phdr)* phdr_table, size_t phdr_cou static void set_bss_vma_name(soinfo* si); +void __libc_init_mte(const void* phdr_start, size_t phdr_count, uintptr_t load_bias); + // These should be preserved static to avoid emitting // RELATIVE relocations for the part of the code running // before linker links itself. @@ -403,6 +405,8 @@ static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load strerror(errno)); } } + + __libc_init_mte(somain->phdr, somain->phnum, somain->load_bias); #endif // Register the main executable and the linker upfront to have @@ -721,6 +725,13 @@ __linker_init_post_relocation(KernelArgumentBlock& args, soinfo& tmp_linker_so) // Initialize the linker's own global variables tmp_linker_so.call_constructors(); + // Setting the linker soinfo's soname can allocate heap memory, so delay it until here. + for (const ElfW(Dyn)* d = tmp_linker_so.dynamic; d->d_tag != DT_NULL; ++d) { + if (d->d_tag == DT_SONAME) { + tmp_linker_so.set_soname(tmp_linker_so.get_string(d->d_un.d_val)); + } + } + // When the linker is run directly rather than acting as PT_INTERP, parse // arguments and determine the executable to load. When it's instead acting // as PT_INTERP, AT_ENTRY will refer to the loaded executable rather than the diff --git a/linker/linker_namespaces.h b/linker/linker_namespaces.h index 77b662294..6817901a3 100644 --- a/linker/linker_namespaces.h +++ b/linker/linker_namespaces.h @@ -56,9 +56,6 @@ struct android_namespace_link_t { } bool is_accessible(const char* soname) const { - if (soname == nullptr) { - return false; - } return allow_all_shared_libs_ || shared_lib_sonames_.find(soname) != shared_lib_sonames_.end(); } diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp index 60fd242cc..287e757a9 100644 --- a/linker/linker_soinfo.cpp +++ b/linker/linker_soinfo.cpp @@ -485,11 +485,8 @@ static void call_function(const char* function_name __unused, } template <typename F> -static void call_array(const char* array_name __unused, - F* functions, - size_t count, - bool reverse, - const char* realpath) { +static inline void call_array(const char* array_name __unused, F* functions, size_t count, + bool reverse, const char* realpath) { if (functions == nullptr) { return; } @@ -695,7 +692,7 @@ void soinfo::set_soname(const char* soname) { if (has_min_version(2)) { soname_ = soname; } - strlcpy(old_name_, soname_, sizeof(old_name_)); + strlcpy(old_name_, soname_.c_str(), sizeof(old_name_)); #else soname_ = soname; #endif @@ -704,12 +701,12 @@ void soinfo::set_soname(const char* soname) { const char* soinfo::get_soname() const { #if defined(__work_around_b_24465209__) if (has_min_version(2)) { - return soname_; + return soname_.c_str(); } else { return old_name_; } #else - return soname_; + return soname_.c_str(); #endif } diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h index 7372a51e8..9c589d608 100644 --- a/linker/linker_soinfo.h +++ b/linker/linker_soinfo.h @@ -401,7 +401,7 @@ struct soinfo { uint8_t* android_relocs_; size_t android_relocs_size_; - const char* soname_; + std::string soname_; std::string realpath_; const ElfW(Versym)* versym_; diff --git a/tests/Android.bp b/tests/Android.bp index 477c8fc7d..678eae8c1 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -67,12 +67,6 @@ cc_defaults { // Use the bootstrap version of bionic because some tests call private APIs // that aren't exposed by the APEX bionic stubs. bootstrap: true, - - product_variables: { - experimental_mte: { - cflags: ["-DANDROID_EXPERIMENTAL_MTE"], - }, - }, } // ----------------------------------------------------------------------------- @@ -851,66 +845,95 @@ cc_defaults { "elftls_dlopen_ie_error_helper", "exec_linker_helper", "exec_linker_helper_lib", - "libtest_dt_runpath_a", - "libtest_dt_runpath_b", - "libtest_dt_runpath_c", - "libtest_dt_runpath_x", - "libtest_dt_runpath_y", + "heap_tagging_async_helper", + "heap_tagging_disabled_helper", + "heap_tagging_static_async_helper", + "heap_tagging_static_disabled_helper", + "heap_tagging_static_sync_helper", + "heap_tagging_sync_helper", + "ld_config_test_helper", + "ld_config_test_helper_lib1", + "ld_config_test_helper_lib2", + "ld_config_test_helper_lib3", + "ld_preload_test_helper", + "ld_preload_test_helper_lib1", + "ld_preload_test_helper_lib2", "libatest_simple_zip", "libcfi-test", "libcfi-test-bad", + "libdl_preempt_test_1", + "libdl_preempt_test_2", + "libdl_test_df_1_global", + "libdlext_test", "libdlext_test_different_soname", "libdlext_test_fd", "libdlext_test_norelro", "libdlext_test_recursive", "libdlext_test_runpath_zip_zipaligned", - "libdlext_test", "libdlext_test_zip", "libdlext_test_zip_zipaligned", - "libdl_preempt_test_1", - "libdl_preempt_test_2", - "libdl_test_df_1_global", "libgnu-hash-table-library", - "librelocations-ANDROID_RELR", + "libns_hidden_child_app", + "libns_hidden_child_global", + "libns_hidden_child_internal", + "libns_hidden_child_public", + "libnstest_dlopened", + "libnstest_ns_a_public1", + "libnstest_ns_a_public1_internal", + "libnstest_ns_b_public2", + "libnstest_ns_b_public3", + "libnstest_private", + "libnstest_private_external", + "libnstest_public", + "libnstest_public_internal", + "libnstest_root", + "libnstest_root_not_isolated", "librelocations-ANDROID_REL", + "librelocations-ANDROID_RELR", "librelocations-RELR", "librelocations-fat", + "libsegment_gap_inner", + "libsegment_gap_outer", "libsysv-hash-table-library", - "libtestshared", "libtest_atexit", + "libtest_check_order_dlsym", "libtest_check_order_dlsym_1_left", "libtest_check_order_dlsym_2_right", "libtest_check_order_dlsym_3_c", "libtest_check_order_dlsym_a", "libtest_check_order_dlsym_b", "libtest_check_order_dlsym_d", - "libtest_check_order_dlsym", + "libtest_check_order_reloc_root", "libtest_check_order_reloc_root_1", "libtest_check_order_reloc_root_2", - "libtest_check_order_reloc_root", + "libtest_check_order_reloc_siblings", "libtest_check_order_reloc_siblings_1", "libtest_check_order_reloc_siblings_2", "libtest_check_order_reloc_siblings_3", "libtest_check_order_reloc_siblings_a", "libtest_check_order_reloc_siblings_b", + "libtest_check_order_reloc_siblings_c", "libtest_check_order_reloc_siblings_c_1", "libtest_check_order_reloc_siblings_c_2", - "libtest_check_order_reloc_siblings_c", "libtest_check_order_reloc_siblings_d", "libtest_check_order_reloc_siblings_e", "libtest_check_order_reloc_siblings_f", - "libtest_check_order_reloc_siblings", "libtest_check_rtld_next_from_library", "libtest_dlopen_df_1_global", - "libtest_dlopen_from_ctor_main", "libtest_dlopen_from_ctor", + "libtest_dlopen_from_ctor_main", "libtest_dlopen_weak_undefined_func", "libtest_dlsym_df_1_global", + "libtest_dlsym_from_this", "libtest_dlsym_from_this_child", "libtest_dlsym_from_this_grandchild", - "libtest_dlsym_from_this", "libtest_dlsym_weak_func", + "libtest_dt_runpath_a", + "libtest_dt_runpath_b", + "libtest_dt_runpath_c", "libtest_dt_runpath_d", + "libtest_dt_runpath_x", + "libtest_dt_runpath_y", "libtest_elftls_dynamic", "libtest_elftls_dynamic_filler_1", "libtest_elftls_dynamic_filler_2", @@ -919,83 +942,60 @@ cc_defaults { "libtest_elftls_shared_var_ie", "libtest_elftls_tprel", "libtest_empty", - "libtest_ifunc_variable_impl", - "libtest_ifunc_variable", "libtest_ifunc", + "libtest_ifunc_variable", + "libtest_ifunc_variable_impl", + "libtest_indirect_thread_local_dtor", "libtest_init_fini_order_child", "libtest_init_fini_order_grand_child", - "libtest_init_fini_order_root2", "libtest_init_fini_order_root", - "libtest_missing_symbol_child_public", + "libtest_init_fini_order_root2", + "libtest_invalid-empty_shdr_table", + "libtest_invalid-rw_load_segment", + "libtest_invalid-textrels", + "libtest_invalid-textrels2", + "libtest_invalid-unaligned_shdr_offset", + "libtest_invalid-zero_shdr_table_content", + "libtest_invalid-zero_shdr_table_offset", + "libtest_invalid-zero_shentsize", + "libtest_invalid-zero_shstrndx", + "libtest_missing_symbol", "libtest_missing_symbol_child_private", + "libtest_missing_symbol_child_public", "libtest_missing_symbol_root", - "libtest_missing_symbol", "libtest_nodelete_1", "libtest_nodelete_2", "libtest_nodelete_dt_flags_1", "libtest_pthread_atfork", + "libtest_relo_check_dt_needed_order", "libtest_relo_check_dt_needed_order_1", "libtest_relo_check_dt_needed_order_2", - "libtest_relo_check_dt_needed_order", "libtest_simple", + "libtest_thread_local_dtor", + "libtest_thread_local_dtor2", "libtest_two_parents_child", "libtest_two_parents_parent1", "libtest_two_parents_parent2", "libtest_versioned_lib", "libtest_versioned_libv1", "libtest_versioned_libv2", - "libtest_versioned_otherlib_empty", "libtest_versioned_otherlib", + "libtest_versioned_otherlib_empty", "libtest_versioned_uselibv1", - "libtest_versioned_uselibv2_other", "libtest_versioned_uselibv2", + "libtest_versioned_uselibv2_other", "libtest_versioned_uselibv3_other", + "libtest_with_dependency", + "libtest_with_dependency_loop", "libtest_with_dependency_loop_a", "libtest_with_dependency_loop_b", "libtest_with_dependency_loop_c", - "libtest_with_dependency_loop", - "libtest_with_dependency", - "libtest_indirect_thread_local_dtor", - "libtest_invalid-empty_shdr_table", - "libtest_invalid-rw_load_segment", - "libtest_invalid-unaligned_shdr_offset", - "libtest_invalid-zero_shdr_table_content", - "libtest_invalid-zero_shdr_table_offset", - "libtest_invalid-zero_shentsize", - "libtest_invalid-zero_shstrndx", - "libtest_invalid-textrels", - "libtest_invalid-textrels2", - "libtest_thread_local_dtor", - "libtest_thread_local_dtor2", + "libtestshared", + "ns_hidden_child_helper", "preinit_getauxval_test_helper", "preinit_syscall_test_helper", - "libnstest_private_external", - "libnstest_dlopened", - "libnstest_private", - "libnstest_root_not_isolated", - "libnstest_root", - "libnstest_public", - "libnstest_public_internal", - "libnstest_ns_a_public1", - "libnstest_ns_a_public1_internal", - "libnstest_ns_b_public2", - "libnstest_ns_b_public3", - "ns_hidden_child_helper", - "libns_hidden_child_global", - "libns_hidden_child_internal", - "libns_hidden_child_public", - "libns_hidden_child_app", - "libsegment_gap_inner", - "libsegment_gap_outer", - "ld_preload_test_helper", - "ld_preload_test_helper_lib1", - "ld_preload_test_helper_lib2", - "ld_config_test_helper", - "ld_config_test_helper_lib1", - "ld_config_test_helper_lib2", - "ld_config_test_helper_lib3", - "tls_properties_helper", "thread_exit_cb_helper", + "tls_properties_helper", ], } diff --git a/tests/heap_tagging_level_test.cpp b/tests/heap_tagging_level_test.cpp index 1dbf45531..b3c8f22a9 100644 --- a/tests/heap_tagging_level_test.cpp +++ b/tests/heap_tagging_level_test.cpp @@ -15,10 +15,12 @@ */ #include <gtest/gtest.h> + +#include <malloc.h> #include <sys/prctl.h> #if defined(__BIONIC__) -#include "platform/bionic/malloc.h" +#include "gtest_globals.h" #include "platform/bionic/mte.h" #include "utils.h" @@ -36,7 +38,7 @@ static bool KernelSupportsTaggedPointers() { } static bool SetHeapTaggingLevel(HeapTaggingLevel level) { - return android_mallopt(M_SET_HEAP_TAGGING_LEVEL, &level, sizeof(level)); + return mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, level); } #endif @@ -76,21 +78,22 @@ TEST(heap_tagging_level, tagged_pointer_dies) { #endif // defined(__BIONIC__) } -#if defined(__BIONIC__) && defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE) +#if defined(__BIONIC__) && defined(__aarch64__) void ExitWithSiCode(int, siginfo_t* info, void*) { _exit(info->si_code); } #endif TEST(heap_tagging_level, sync_async_bad_accesses_die) { -#if defined(__BIONIC__) && defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE) +#if defined(__BIONIC__) && defined(__aarch64__) if (!(getauxval(AT_HWCAP2) & HWCAP2_MTE)) { GTEST_SKIP() << "requires MTE support"; } std::unique_ptr<int[]> p = std::make_unique<int[]>(4); - // First, check that memory tagging is enabled and the default tag checking level is async. + // First, check that memory tagging is enabled and the default tag checking level is sync. + // cc_test targets get sync MTE by default. // We assume that scudo is used on all MTE enabled hardware; scudo inserts a header with a // mismatching tag before each allocation. EXPECT_EXIT( @@ -98,18 +101,20 @@ TEST(heap_tagging_level, sync_async_bad_accesses_die) { ScopedSignalHandler ssh(SIGSEGV, ExitWithSiCode, SA_SIGINFO); p[-1] = 42; }, - testing::ExitedWithCode(SEGV_MTEAERR), ""); + testing::ExitedWithCode(SEGV_MTESERR), ""); - EXPECT_TRUE(SetHeapTaggingLevel(M_HEAP_TAGGING_LEVEL_SYNC)); + EXPECT_TRUE(SetHeapTaggingLevel(M_HEAP_TAGGING_LEVEL_ASYNC)); EXPECT_EXIT( { ScopedSignalHandler ssh(SIGSEGV, ExitWithSiCode, SA_SIGINFO); p[-1] = 42; }, - testing::ExitedWithCode(SEGV_MTESERR), ""); + testing::ExitedWithCode(SEGV_MTEAERR), ""); EXPECT_TRUE(SetHeapTaggingLevel(M_HEAP_TAGGING_LEVEL_NONE)); volatile int oob ATTRIBUTE_UNUSED = p[-1]; +#else + GTEST_SKIP() << "bionic/arm64 only"; #endif } @@ -175,3 +180,34 @@ TEST(heap_tagging_level, tagging_level_transition_sync_none) { GTEST_SKIP() << "bionic/arm64 only"; #endif } + +enum class MemtagNote { NONE, ASYNC, SYNC }; +class MemtagNoteTest : public testing::TestWithParam<std::tuple<MemtagNote, bool>> {}; + +TEST_P(MemtagNoteTest, SEGV) { +#if defined(__BIONIC__) && defined(__aarch64__) + if (!(getauxval(AT_HWCAP2) & HWCAP2_MTE)) { + GTEST_SKIP() << "requires MTE support"; + } + + const char* kNoteSuffix[] = {"disabled", "async", "sync"}; + const char* kExpectedOutput[] = {"normal exit\n", "SEGV_MTEAERR\n", "SEGV_MTESERR\n"}; + + MemtagNote note = std::get<0>(GetParam()); + bool isStatic = std::get<1>(GetParam()); + std::string helper_base = std::string("heap_tagging_") + (isStatic ? "static_" : "") + + kNoteSuffix[static_cast<int>(note)] + "_helper"; + fprintf(stderr, "=== %s\n", helper_base.c_str()); + std::string helper = GetTestlibRoot() + "/" + helper_base + "/" + helper_base; + chmod(helper.c_str(), 0755); + ExecTestHelper eth; + eth.SetArgs({helper.c_str(), nullptr}); + eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, + kExpectedOutput[static_cast<int>(note)]); +#endif +} + +INSTANTIATE_TEST_SUITE_P(, MemtagNoteTest, + testing::Combine(testing::Values(MemtagNote::NONE, MemtagNote::ASYNC, + MemtagNote::SYNC), + testing::Bool())); diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp index 4b86faf7a..385d1209e 100644 --- a/tests/libs/Android.bp +++ b/tests/libs/Android.bp @@ -1579,3 +1579,85 @@ cc_test_library { defaults: ["bionic_testlib_defaults"], srcs: ["relocations.cpp"], } + +cc_defaults { + name: "bionic_targets_only", + enabled: false, + target: { + android: { + enabled: true, + }, + linux_bionic: { + enabled: true, + }, + }, +} + +cc_test { + name: "heap_tagging_sync_helper", + defaults: ["bionic_testlib_defaults", "bionic_targets_only"], + srcs: ["heap_tagging_helper.cpp"], + sanitize: { + memtag_heap: true, + diag: { + memtag_heap: true, + }, + }, +} + +cc_test { + name: "heap_tagging_async_helper", + defaults: ["bionic_testlib_defaults", "bionic_targets_only"], + srcs: ["heap_tagging_helper.cpp"], + sanitize: { + memtag_heap: true, + diag: { + memtag_heap: false, + }, + }, +} + +cc_test { + name: "heap_tagging_disabled_helper", + defaults: ["bionic_testlib_defaults", "bionic_targets_only"], + srcs: ["heap_tagging_helper.cpp"], + sanitize: { + memtag_heap: false, + }, +} + +cc_test { + name: "heap_tagging_static_sync_helper", + defaults: ["bionic_testlib_defaults", "bionic_targets_only"], + srcs: ["heap_tagging_helper.cpp"], + static_executable: true, + sanitize: { + memtag_heap: true, + diag: { + memtag_heap: true, + }, + }, +} + +cc_test { + name: "heap_tagging_static_async_helper", + defaults: ["bionic_testlib_defaults", "bionic_targets_only"], + srcs: ["heap_tagging_helper.cpp"], + static_executable: true, + sanitize: { + memtag_heap: true, + diag: { + memtag_heap: false, + }, + }, +} + +cc_test { + name: "heap_tagging_static_disabled_helper", + defaults: ["bionic_testlib_defaults", "bionic_targets_only"], + srcs: ["heap_tagging_helper.cpp"], + static_executable: true, + sanitize: { + memtag_heap: false, + }, +} diff --git a/tests/libs/heap_tagging_helper.cpp b/tests/libs/heap_tagging_helper.cpp new file mode 100644 index 000000000..1a970f258 --- /dev/null +++ b/tests/libs/heap_tagging_helper.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <signal.h> +#include <stdio.h> +#include <sys/cdefs.h> +#include <unistd.h> +#include <memory> + +void action(int signo, siginfo_t* info __unused, void*) { +#ifdef __ANDROID__ + if (signo == 11 && info->si_code == SEGV_MTEAERR) { + fprintf(stderr, "SEGV_MTEAERR\n"); + _exit(0); + } + + if (signo == 11 && info->si_code == SEGV_MTESERR) { + fprintf(stderr, "SEGV_MTESERR\n"); + _exit(0); + } +#endif + + fprintf(stderr, "signo %d\n", signo); + _exit(0); +} + +__attribute__((optnone)) int main() { + struct sigaction sa = {}; + sa.sa_sigaction = action; + sa.sa_flags = SA_SIGINFO; + sigaction(SIGSEGV, &sa, nullptr); + + std::unique_ptr<int[]> p = std::make_unique<int[]>(4); + volatile int oob = p[-1]; + (void)oob; + + fprintf(stderr, "normal exit\n"); + return 0; +} diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp index ddd3416be..b35bba983 100644 --- a/tests/malloc_test.cpp +++ b/tests/malloc_test.cpp @@ -47,7 +47,6 @@ #include "platform/bionic/malloc.h" #include "platform/bionic/mte.h" -#include "platform/bionic/mte_kernel.h" #include "platform/bionic/reserved_signals.h" #include "private/bionic_config.h" @@ -1257,13 +1256,12 @@ TEST(android_mallopt, set_allocation_limit_multiple_threads) { #endif } -TEST(android_mallopt, disable_memory_mitigations) { +TEST(malloc, disable_memory_mitigations) { #if defined(__BIONIC__) if (!mte_supported()) { GTEST_SKIP() << "This function can only be tested with MTE"; } -#ifdef ANDROID_EXPERIMENTAL_MTE sem_t sem; ASSERT_EQ(0, sem_init(&sem, 0, 0)); @@ -1277,7 +1275,7 @@ TEST(android_mallopt, disable_memory_mitigations) { }, &sem)); - ASSERT_TRUE(android_mallopt(M_DISABLE_MEMORY_MITIGATIONS, nullptr, 0)); + ASSERT_EQ(1, mallopt(M_BIONIC_DISABLE_MEMORY_MITIGATIONS, 0)); ASSERT_EQ(0, sem_post(&sem)); int my_tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0); @@ -1287,7 +1285,6 @@ TEST(android_mallopt, disable_memory_mitigations) { ASSERT_EQ(0, pthread_join(thread, &retval)); int thread_tagged_addr_ctrl = reinterpret_cast<uintptr_t>(retval); ASSERT_EQ(my_tagged_addr_ctrl, thread_tagged_addr_ctrl); -#endif #else GTEST_SKIP() << "bionic extension"; #endif diff --git a/tests/stack_unwinding_test.cpp b/tests/stack_unwinding_test.cpp index 0ff6f30a6..7fb22471c 100644 --- a/tests/stack_unwinding_test.cpp +++ b/tests/stack_unwinding_test.cpp @@ -82,7 +82,7 @@ struct UnwindData { static UnwindData g_unwind_data; -static void noinline UnwindSignalHandler(int) { +__attribute__((unused)) static void noinline UnwindSignalHandler(int) { _Unwind_Backtrace(FrameCounter, &g_unwind_data.handler_frame_count); g_unwind_data.handler_one_deeper_frame_count = unwind_one_frame_deeper(); @@ -98,7 +98,7 @@ static void verify_unwind_data(const UnwindData& unwind_data) { EXPECT_EQ(unwind_data.handler_frame_count + 1, unwind_data.handler_one_deeper_frame_count); } -static void noinline UnwindTest() { +__attribute__((unused)) static void noinline UnwindTest() { g_unwind_data = {}; _Unwind_Backtrace(FrameCounter, &g_unwind_data.expected_frame_count); @@ -112,14 +112,24 @@ static void noinline UnwindTest() { } TEST(stack_unwinding, unwind_through_signal_frame) { +#if defined(__aarch64__) + // A newer libunwind.a update should restore signal frame unwinding on arm64. + GTEST_SKIP() << "signal frame unwinding temporarily broken on arm64 -- b/153025717"; +#else ScopedSignalHandler ssh(SIGUSR1, UnwindSignalHandler); UnwindTest(); +#endif } // On LP32, the SA_SIGINFO flag gets you __restore_rt instead of __restore. TEST(stack_unwinding, unwind_through_signal_frame_SA_SIGINFO) { +#if defined(__aarch64__) + // A newer libunwind.a update should restore signal frame unwinding on arm64. + GTEST_SKIP() << "signal frame unwinding temporarily broken on arm64 -- b/153025717"; +#else ScopedSignalHandler ssh(SIGUSR1, UnwindSignalHandler, SA_SIGINFO); UnwindTest(); +#endif } diff --git a/tools/versioner/src/Driver.cpp b/tools/versioner/src/Driver.cpp index adf93c393..24dc5ecd8 100644 --- a/tools/versioner/src/Driver.cpp +++ b/tools/versioner/src/Driver.cpp @@ -149,7 +149,7 @@ static void generateTargetCC1Flags(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSyste cmd.push_back("-"); auto diags = constructDiags(); - driver::Driver driver("versioner", llvm::sys::getDefaultTargetTriple(), *diags, vfs); + driver::Driver driver("versioner", llvm::sys::getDefaultTargetTriple(), *diags, "versioner", vfs); driver.setCheckInputsExist(false); llvm::SmallVector<const char*, 32> driver_args; |