Merge "Improve comment about glibc behavior difference." into main
diff --git a/libc/NOTICE b/libc/NOTICE
index ef64e0c..d464e1d 100644
--- a/libc/NOTICE
+++ b/libc/NOTICE
@@ -942,6 +942,35 @@
-------------------------------------------------------------------
+Copyright (c) 1982, 1986, 1988, 1993
+ The Regents of the University of California. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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) 1982, 1986, 1993
The Regents of the University of California. All rights reserved.
diff --git a/libc/bionic/fcntl.cpp b/libc/bionic/fcntl.cpp
index 754277b..7730a15 100644
--- a/libc/bionic/fcntl.cpp
+++ b/libc/bionic/fcntl.cpp
@@ -44,7 +44,7 @@
va_end(args);
if (cmd == F_SETFD && (reinterpret_cast<uintptr_t>(arg) & ~FD_CLOEXEC) != 0) {
- __fortify_fatal("fcntl(F_SETFD) passed non-FD_CLOEXEC flag: %p", arg);
+ __fortify_fatal("fcntl(F_SETFD) only supports FD_CLOEXEC but was passed %p", arg);
}
#if defined(__LP64__)
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index 1591785..8068fc2 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -179,26 +179,10 @@
}
#ifdef __aarch64__
-static bool __read_memtag_note(const ElfW(Nhdr)* note, const char* name, const char* desc,
- unsigned* result) {
- if (note->n_type != NT_ANDROID_TYPE_MEMTAG) {
- return false;
- }
- if (note->n_namesz != 8 || strncmp(name, "Android", 8) != 0) {
- return false;
- }
- // Previously (in Android 12), if the note was != 4 bytes, we check-failed
- // here. Let's be more permissive to allow future expansion.
- 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) {
+static bool __get_elf_note(const ElfW(Phdr) * phdr_start, size_t phdr_ct,
+ const ElfW(Addr) load_bias, unsigned desired_type,
+ const char* desired_name, const ElfW(Nhdr) * *note_out,
+ const char** desc_out) {
for (size_t i = 0; i < phdr_ct; ++i) {
const ElfW(Phdr)* phdr = &phdr_start[i];
if (phdr->p_type != PT_NOTE) {
@@ -216,13 +200,68 @@
if (p > note_end) {
break;
}
- unsigned ret;
- if (__read_memtag_note(note, name, desc, &ret)) {
- return ret;
+ if (note->n_type != desired_type) {
+ continue;
}
+ size_t desired_name_len = strlen(desired_name);
+ if (note->n_namesz != desired_name_len + 1 ||
+ strncmp(desired_name, name, desired_name_len) != 0) {
+ break;
+ }
+ *note_out = note;
+ *desc_out = desc;
+ return true;
}
}
- return 0;
+ return false;
+}
+
+static HeapTaggingLevel __get_memtag_level_from_note(const ElfW(Phdr) * phdr_start, size_t phdr_ct,
+ const ElfW(Addr) load_bias, bool* stack) {
+ const ElfW(Nhdr) * note;
+ const char* desc;
+ if (!__get_elf_note(phdr_start, phdr_ct, load_bias, NT_ANDROID_TYPE_MEMTAG, "Android", ¬e,
+ &desc)) {
+ return M_HEAP_TAGGING_LEVEL_TBI;
+ }
+
+ // Previously (in Android 12), if the note was != 4 bytes, we check-failed
+ // here. Let's be more permissive to allow future expansion.
+ if (note->n_descsz < 4) {
+ async_safe_fatal("unrecognized android.memtag note: n_descsz = %d, expected >= 4",
+ note->n_descsz);
+ }
+
+ // `desc` is always aligned due to ELF requirements, enforced in __get_elf_note().
+ ElfW(Word) note_val = *reinterpret_cast<const ElfW(Word)*>(desc);
+ *stack = (note_val & NT_MEMTAG_STACK) != 0;
+
+ // Warning: In Android 12, any value outside of bits [0..3] resulted in a check-fail.
+ if (!(note_val & (NT_MEMTAG_HEAP | NT_MEMTAG_STACK))) {
+ async_safe_format_log(ANDROID_LOG_INFO, "libc",
+ "unrecognised memtag note_val did not specificy heap or stack: %u",
+ note_val);
+ return M_HEAP_TAGGING_LEVEL_TBI;
+ }
+
+ unsigned mode = note_val & NT_MEMTAG_LEVEL_MASK;
+ switch (mode) {
+ case NT_MEMTAG_LEVEL_NONE:
+ // Note, previously (in Android 12), NT_MEMTAG_LEVEL_NONE was
+ // NT_MEMTAG_LEVEL_DEFAULT, which implied SYNC mode. This was never used
+ // by anyone, but we note it (heh) here for posterity, in case the zero
+ // level becomes meaningful, and binaries with this note can be executed
+ // on Android 12 devices.
+ return M_HEAP_TAGGING_LEVEL_TBI;
+ case NT_MEMTAG_LEVEL_ASYNC:
+ return M_HEAP_TAGGING_LEVEL_ASYNC;
+ case NT_MEMTAG_LEVEL_SYNC:
+ default:
+ // We allow future extensions to specify mode 3 (currently unused), with
+ // the idea that it might be used for ASYMM mode or something else. On
+ // this version of Android, it falls back to SYNC mode.
+ return M_HEAP_TAGGING_LEVEL_SYNC;
+ }
}
// Returns true if there's an environment setting (either sysprop or env var)
@@ -273,48 +312,57 @@
// 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, bool* stack) {
- unsigned note_val =
- __get_memtag_note(reinterpret_cast<const ElfW(Phdr)*>(phdr_start), phdr_ct, load_bias);
- *stack = note_val & NT_MEMTAG_STACK;
+static HeapTaggingLevel __get_tagging_level(const memtag_dynamic_entries_t* memtag_dynamic_entries,
+ const void* phdr_start, size_t phdr_ct,
+ uintptr_t load_bias, bool* stack) {
+ HeapTaggingLevel level = M_HEAP_TAGGING_LEVEL_TBI;
- HeapTaggingLevel level;
- if (get_environment_memtag_setting(&level)) return level;
-
- // Note, previously (in Android 12), any value outside of bits [0..3] resulted
- // in a check-fail. In order to be permissive of further extensions, we
- // relaxed this restriction.
- if (!(note_val & (NT_MEMTAG_HEAP | NT_MEMTAG_STACK))) return M_HEAP_TAGGING_LEVEL_TBI;
-
- unsigned mode = note_val & NT_MEMTAG_LEVEL_MASK;
- switch (mode) {
- case NT_MEMTAG_LEVEL_NONE:
- // Note, previously (in Android 12), NT_MEMTAG_LEVEL_NONE was
- // NT_MEMTAG_LEVEL_DEFAULT, which implied SYNC mode. This was never used
- // by anyone, but we note it (heh) here for posterity, in case the zero
- // level becomes meaningful, and binaries with this note can be executed
- // on Android 12 devices.
- return M_HEAP_TAGGING_LEVEL_TBI;
- case NT_MEMTAG_LEVEL_ASYNC:
- return M_HEAP_TAGGING_LEVEL_ASYNC;
- case NT_MEMTAG_LEVEL_SYNC:
- default:
- // We allow future extensions to specify mode 3 (currently unused), with
- // the idea that it might be used for ASYMM mode or something else. On
- // this version of Android, it falls back to SYNC mode.
- return M_HEAP_TAGGING_LEVEL_SYNC;
+ // If the dynamic entries exist, use those. Otherwise, fall back to the old
+ // Android note, which is still used for fully static executables. When
+ // -fsanitize=memtag* is used in newer toolchains, currently both the dynamic
+ // entries and the old note are created, but we'd expect to move to just the
+ // dynamic entries for dynamically linked executables in the future. In
+ // addition, there's still some cleanup of the build system (that uses a
+ // manually-constructed note) needed. For more information about the dynamic
+ // entries, see:
+ // https://github.com/ARM-software/abi-aa/blob/main/memtagabielf64/memtagabielf64.rst#dynamic-section
+ if (memtag_dynamic_entries && memtag_dynamic_entries->has_memtag_mode) {
+ switch (memtag_dynamic_entries->memtag_mode) {
+ case 0:
+ level = M_HEAP_TAGGING_LEVEL_SYNC;
+ break;
+ case 1:
+ level = M_HEAP_TAGGING_LEVEL_ASYNC;
+ break;
+ default:
+ async_safe_format_log(ANDROID_LOG_INFO, "libc",
+ "unrecognised DT_AARCH64_MEMTAG_MODE value: %u",
+ memtag_dynamic_entries->memtag_mode);
+ }
+ *stack = memtag_dynamic_entries->memtag_stack;
+ } else {
+ level = __get_memtag_level_from_note(reinterpret_cast<const ElfW(Phdr)*>(phdr_start), phdr_ct,
+ load_bias, stack);
}
+
+ // We can't short-circuit the environment override, as `stack` is still inherited from the
+ // binary's settings.
+ if (get_environment_memtag_setting(&level)) {
+ if (level == M_HEAP_TAGGING_LEVEL_NONE || level == M_HEAP_TAGGING_LEVEL_TBI) {
+ *stack = false;
+ }
+ }
+ return 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,
- void* stack_top) {
- bool memtag_stack;
- HeapTaggingLevel level = __get_heap_tagging_level(phdr_start, phdr_ct, load_bias, &memtag_stack);
+__attribute__((no_sanitize("hwaddress", "memtag"))) void __libc_init_mte(
+ const memtag_dynamic_entries_t* memtag_dynamic_entries, const void* phdr_start, size_t phdr_ct,
+ uintptr_t load_bias, void* stack_top) {
+ bool memtag_stack = false;
+ HeapTaggingLevel level =
+ __get_tagging_level(memtag_dynamic_entries, phdr_start, phdr_ct, load_bias, &memtag_stack);
char* env = getenv("BIONIC_MEMTAG_UPGRADE_SECS");
static const char kAppProcessName[] = "app_process64";
const char* progname = __libc_shared_globals()->init_progname;
@@ -385,7 +433,7 @@
__libc_shared_globals()->heap_tagging_upgrade_timer_sec = 0;
}
#else // __aarch64__
-void __libc_init_mte(const void*, size_t, uintptr_t, void*) {}
+void __libc_init_mte(const memtag_dynamic_entries_t*, const void*, size_t, uintptr_t, void*) {}
#endif // __aarch64__
void __libc_init_profiling_handlers() {
@@ -412,7 +460,8 @@
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),
+ __libc_init_mte(/*memtag_dynamic_entries=*/nullptr,
+ reinterpret_cast<ElfW(Phdr)*>(getauxval(AT_PHDR)), getauxval(AT_PHNUM),
/*load_bias = */ 0, /*stack_top = */ raw_args);
__libc_init_scudo();
__libc_init_profiling_handlers();
diff --git a/libc/include/elf.h b/libc/include/elf.h
index 1dfc008..04a73f7 100644
--- a/libc/include/elf.h
+++ b/libc/include/elf.h
@@ -266,4 +266,6 @@
/* TODO: upstream these to FreeBSD? */
#define R_ARM_TLS_DESC 13
#define R_ARM_IRELATIVE 160
-#define R_X86_64_JUMP_SLOT 7
+
+/* BSD spells this slightly differently to Linux. */
+#define R_X86_64_JUMP_SLOT R_X86_64_JMP_SLOT
diff --git a/libc/include/syslog.h b/libc/include/syslog.h
index 90ea76e..1e2fcc4 100644
--- a/libc/include/syslog.h
+++ b/libc/include/syslog.h
@@ -25,6 +25,34 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+/*
+ * Copyright (c) 1982, 1986, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
#pragma once
@@ -129,6 +157,60 @@
*/
#define LOG_PERROR 0x20
+#if defined(SYSLOG_NAMES)
+/** A mapping from name to value, used by `facilitynames` and `prioritynames`. */
+typedef struct _code {
+ char* c_name;
+ int c_val;
+} CODE;
+/* A bogus facility value for "mark". */
+#define INTERNAL_MARK LOG_MAKEPRI((LOG_NFACILITIES<<3), 0)
+/** A table mapping facility names to values. */
+static const CODE facilitynames[] = {
+ { "auth", LOG_AUTH, },
+ { "authpriv", LOG_AUTHPRIV, },
+ { "cron", LOG_CRON, },
+ { "daemon", LOG_DAEMON, },
+ { "ftp", LOG_FTP, },
+ { "kern", LOG_KERN, },
+ { "lpr", LOG_LPR, },
+ { "mail", LOG_MAIL, },
+ { "mark", INTERNAL_MARK, },
+ { "news", LOG_NEWS, },
+ { "security", LOG_AUTH, },
+ { "syslog", LOG_SYSLOG, },
+ { "user", LOG_USER, },
+ { "uucp", LOG_UUCP, },
+ { "local0", LOG_LOCAL0, },
+ { "local1", LOG_LOCAL1, },
+ { "local2", LOG_LOCAL2, },
+ { "local3", LOG_LOCAL3, },
+ { "local4", LOG_LOCAL4, },
+ { "local5", LOG_LOCAL5, },
+ { "local6", LOG_LOCAL6, },
+ { "local7", LOG_LOCAL7, },
+ { NULL, -1, },
+};
+/* A bogus priority value for "none". */
+#define INTERNAL_NOPRI 8
+/** A table mapping priority names to values. */
+static const CODE prioritynames[] = {
+ { "alert", LOG_ALERT, },
+ { "crit", LOG_CRIT, },
+ { "debug", LOG_DEBUG, },
+ { "emerg", LOG_EMERG, },
+ { "err", LOG_ERR, },
+ { "error", LOG_ERR, },
+ { "info", LOG_INFO, },
+ { "none", INTERNAL_NOPRI, },
+ { "notice", LOG_NOTICE, },
+ { "panic", LOG_EMERG, },
+ { "warn", LOG_WARNING, },
+ { "warning", LOG_WARNING, },
+ { NULL, -1, },
+};
+#endif
+
/**
* [closelog(3)](http://man7.org/linux/man-pages/man3/closelog.3.html) does
* nothing on Android.
diff --git a/libc/kernel/tools/cpp.py b/libc/kernel/tools/cpp.py
index 40e1f26..c0b379b 100755
--- a/libc/kernel/tools/cpp.py
+++ b/libc/kernel/tools/cpp.py
@@ -1471,9 +1471,18 @@
made_change = True
i += 1
- if b.isDefine() and b.define_id in replacements:
- b.define_id = replacements[b.define_id]
- made_change = True
+ if b.isDefine():
+ tokens = CppStringTokenizer(b.define_id).tokens
+ id_change = False
+ for tok in tokens:
+ if tok.kind == TokenKind.IDENTIFIER:
+ if tok.id in replacements:
+ tok.id = replacements[tok.id]
+ id_change = True
+ if id_change:
+ b.define_id = ''.join([tok.id for tok in tokens])
+ made_change = True
+
if made_change and b.isIf():
# Keep 'expr' in sync with 'tokens'.
@@ -2578,10 +2587,12 @@
text = """\
#define SIGRTMIN 32
#define SIGRTMAX _NSIG
+#define SIGRTMAX(a,class) some_func(a, class)
"""
expected = """\
#define __SIGRTMIN 32
#define __SIGRTMAX _KERNEL__NSIG
+#define __SIGRTMAX(a,__linux_class) some_func(a, __linux_class)
"""
self.assertEqual(self.parse(text), expected)
diff --git a/libc/kernel/tools/defaults.py b/libc/kernel/tools/defaults.py
index 91d26ce..65e0117 100644
--- a/libc/kernel/tools/defaults.py
+++ b/libc/kernel/tools/defaults.py
@@ -63,6 +63,7 @@
# The kernel usage of __unused for unused struct fields conflicts with the macro defined in <sys/cdefs.h>.
"__unused": "__linux_unused",
# The kernel usage of C++ keywords causes problems for C++ code so rename.
+ "class": "__linux_class",
"private": "__linux_private",
"virtual": "__linux_virtual",
# The non-64 stuff is legacy; msqid64_ds/ipc64_perm is what userspace wants.
@@ -125,6 +126,8 @@
# These are required to support the above functions.
"__fswahw32",
"__fswahb32",
+ # This is used by various macros in <linux/ioprio.h>.
+ "ioprio_value",
]
)
diff --git a/libc/kernel/uapi/linux/ioprio.h b/libc/kernel/uapi/linux/ioprio.h
index c6dc42a..9ae9dae 100644
--- a/libc/kernel/uapi/linux/ioprio.h
+++ b/libc/kernel/uapi/linux/ioprio.h
@@ -61,6 +61,10 @@
IOPRIO_HINT_DEV_DURATION_LIMIT_7 = 7,
};
#define IOPRIO_BAD_VALUE(val,max) ((val) < 0 || (val) >= (max))
-#define IOPRIO_PRIO_VALUE(class,level) ioprio_value(class, level, IOPRIO_HINT_NONE)
-#define IOPRIO_PRIO_VALUE_HINT(class,level,hint) ioprio_value(class, level, hint)
+static __always_inline __u16 ioprio_value(int __linux_class, int level, int hint) {
+ if(IOPRIO_BAD_VALUE(__linux_class, IOPRIO_NR_CLASSES) || IOPRIO_BAD_VALUE(level, IOPRIO_NR_LEVELS) || IOPRIO_BAD_VALUE(hint, IOPRIO_NR_HINTS)) return IOPRIO_CLASS_INVALID << IOPRIO_CLASS_SHIFT;
+ return(__linux_class << IOPRIO_CLASS_SHIFT) | (hint << IOPRIO_HINT_SHIFT) | level;
+}
+#define IOPRIO_PRIO_VALUE(__linux_class,level) ioprio_value(__linux_class, level, IOPRIO_HINT_NONE)
+#define IOPRIO_PRIO_VALUE_HINT(__linux_class,level,hint) ioprio_value(__linux_class, level, hint)
#endif
diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h
index 510d556..d9c4234 100644
--- a/libc/private/bionic_globals.h
+++ b/libc/private/bionic_globals.h
@@ -66,6 +66,15 @@
MallocDispatch malloc_dispatch_table;
};
+struct memtag_dynamic_entries_t {
+ void* memtag_globals;
+ size_t memtag_globalssz;
+ bool has_memtag_mode;
+ unsigned memtag_mode;
+ bool memtag_heap;
+ bool memtag_stack;
+};
+
#ifdef __aarch64__
static_assert(OFFSETOF_libc_globals_memtag_stack == offsetof(libc_globals, memtag_stack));
#endif
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 1553ba9..135eaa3 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -71,11 +71,12 @@
#include "linker_translate_path.h"
#include "linker_utils.h"
+#include "android-base/macros.h"
+#include "android-base/stringprintf.h"
+#include "android-base/strings.h"
+#include "private/bionic_asm_note.h"
#include "private/bionic_call_ifunc_resolver.h"
#include "private/bionic_globals.h"
-#include "android-base/macros.h"
-#include "android-base/strings.h"
-#include "android-base/stringprintf.h"
#include "ziparchive/zip_archive.h"
static std::unordered_map<void*, size_t> g_dso_handle_counters;
@@ -3194,13 +3195,32 @@
case DT_AARCH64_VARIANT_PCS:
// Ignored: AArch64 processor-specific dynamic array tags.
break;
- // TODO(mitchp): Add support to libc_init_mte to use these dynamic array entries instead of
- // the Android-specific ELF note.
case DT_AARCH64_MEMTAG_MODE:
+ memtag_dynamic_entries_.has_memtag_mode = true;
+ memtag_dynamic_entries_.memtag_mode = d->d_un.d_val;
+ break;
case DT_AARCH64_MEMTAG_HEAP:
+ memtag_dynamic_entries_.memtag_heap = d->d_un.d_val;
+ break;
+ // The AArch64 MemtagABI originally erroneously defined
+ // DT_AARCH64_MEMTAG_STACK as `d_ptr`, which is why the dynamic tag value
+ // is odd (`0x7000000c`). `d_val` is clearly the correct semantics, and so
+ // this was fixed in the ABI, but the value (0x7000000c) didn't change
+ // because we already had Android binaries floating around with dynamic
+ // entries, and didn't want to create a whole new dynamic entry and
+ // reserve a value just to fix that tiny mistake. P.S. lld was always
+ // outputting DT_AARCH64_MEMTAG_STACK as `d_val` anyway.
case DT_AARCH64_MEMTAG_STACK:
+ memtag_dynamic_entries_.memtag_stack = d->d_un.d_val;
+ break;
+ // Same as above, except DT_AARCH64_MEMTAG_GLOBALS was incorrectly defined
+ // as `d_val` (hence an even value of `0x7000000d`), when it should have
+ // been `d_ptr` all along. lld has always outputted this as `d_ptr`.
case DT_AARCH64_MEMTAG_GLOBALS:
+ memtag_dynamic_entries_.memtag_globals = reinterpret_cast<void*>(load_bias + d->d_un.d_ptr);
+ break;
case DT_AARCH64_MEMTAG_GLOBALSSZ:
+ memtag_dynamic_entries_.memtag_globalssz = d->d_un.d_val;
break;
#endif
diff --git a/linker/linker_auxv.cpp b/linker/linker_auxv.cpp
index d8e4a3e..95413a0 100644
--- a/linker/linker_auxv.cpp
+++ b/linker/linker_auxv.cpp
@@ -87,6 +87,12 @@
#if defined(AT_L2_CACHEGEOMETRY)
case AT_L2_CACHEGEOMETRY: return "AT_L2_CACHEGEOMETRY";
#endif
+#if defined(AT_L3_CACHESIZE)
+ case AT_L3_CACHESIZE: return "AT_L3_CACHESIZE";
+#endif
+#if defined(AT_L3_CACHEGEOMETRY)
+ case AT_L3_CACHEGEOMETRY: return "AT_L3_CACHEGEOMETRY";
+#endif
}
static char name[32];
snprintf(name, sizeof(name), "AT_??? (%d)", at);
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index 5a33a63..5f5eba4 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -68,8 +68,8 @@
static void set_bss_vma_name(soinfo* si);
-void __libc_init_mte(const void* phdr_start, size_t phdr_count, uintptr_t load_bias,
- void* stack_top);
+void __libc_init_mte(const memtag_dynamic_entries_t* memtag_dynamic_entries, const void* phdr_start,
+ size_t phdr_count, uintptr_t load_bias, void* stack_top);
// These should be preserved static to avoid emitting
// RELATIVE relocations for the part of the code running
@@ -405,7 +405,8 @@
}
}
- __libc_init_mte(somain->phdr, somain->phnum, somain->load_bias, args.argv);
+ __libc_init_mte(somain->memtag_dynamic_entries(), somain->phdr, somain->phnum, somain->load_bias,
+ args.argv);
#endif
// Register the main executable and the linker upfront to have
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 97ae709..0ad0fd5 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -849,7 +849,7 @@
* load_bias -> load bias
* prop -> GnuPropertySection or nullptr
* Return:
- * 0 on error, -1 on failure (error code in errno).
+ * 0 on success, -1 on failure (error code in errno).
*/
int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count,
ElfW(Addr) load_bias, const GnuPropertySection* prop __unused) {
@@ -876,7 +876,7 @@
* phdr_count -> number of entries in tables
* load_bias -> load bias
* Return:
- * 0 on error, -1 on failure (error code in errno).
+ * 0 on success, -1 on failure (error code in errno).
*/
int phdr_table_unprotect_segments(const ElfW(Phdr)* phdr_table,
size_t phdr_count, ElfW(Addr) load_bias) {
@@ -939,7 +939,7 @@
* phdr_count -> number of entries in tables
* load_bias -> load bias
* Return:
- * 0 on error, -1 on failure (error code in errno).
+ * 0 on success, -1 on failure (error code in errno).
*/
int phdr_table_protect_gnu_relro(const ElfW(Phdr)* phdr_table,
size_t phdr_count, ElfW(Addr) load_bias) {
@@ -957,7 +957,7 @@
* fd -> writable file descriptor to use
* file_offset -> pointer to offset into file descriptor to use/update
* Return:
- * 0 on error, -1 on failure (error code in errno).
+ * 0 on success, -1 on failure (error code in errno).
*/
int phdr_table_serialize_gnu_relro(const ElfW(Phdr)* phdr_table,
size_t phdr_count,
@@ -1005,7 +1005,7 @@
* fd -> readable file descriptor to use
* file_offset -> pointer to offset into file descriptor to use/update
* Return:
- * 0 on error, -1 on failure (error code in errno).
+ * 0 on success, -1 on failure (error code in errno).
*/
int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table,
size_t phdr_count,
@@ -1102,7 +1102,7 @@
* arm_exidx -> address of table in memory (null on failure).
* arm_exidx_count -> number of items in table (0 on failure).
* Return:
- * 0 on error, -1 on failure (_no_ error code in errno)
+ * 0 on success, -1 on failure (_no_ error code in errno)
*/
int phdr_table_get_arm_exidx(const ElfW(Phdr)* phdr_table, size_t phdr_count,
ElfW(Addr) load_bias,
diff --git a/linker/linker_relocs.h b/linker/linker_relocs.h
index 37a7880..54aad18 100644
--- a/linker/linker_relocs.h
+++ b/linker/linker_relocs.h
@@ -84,8 +84,7 @@
#define R_GENERIC_TLS_DTPMOD R_RISCV_TLS_DTPMOD64
#define R_GENERIC_TLS_DTPREL R_RISCV_TLS_DTPREL64
#define R_GENERIC_TLS_TPREL R_RISCV_TLS_TPREL64
-// TODO: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/issues/94
-// #define R_GENERIC_TLSDESC R_RISCV_TLS_DESC
+#define R_GENERIC_TLSDESC R_RISCV_TLSDESC
#elif defined (__x86_64__)
diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h
index 9c589d6..622719d 100644
--- a/linker/linker_soinfo.h
+++ b/linker/linker_soinfo.h
@@ -34,9 +34,11 @@
#include <string>
#include <vector>
-#include "private/bionic_elf_tls.h"
+#include "async_safe/CHECK.h"
#include "linker_namespaces.h"
#include "linker_tls.h"
+#include "private/bionic_elf_tls.h"
+#include "private/bionic_globals.h"
#define FLAG_LINKED 0x00000001
#define FLAG_EXE 0x00000004 // The main executable
@@ -351,6 +353,17 @@
void set_gap_size(size_t gap_size);
size_t get_gap_size() const;
+ const memtag_dynamic_entries_t* memtag_dynamic_entries() const {
+ CHECK(has_min_version(7));
+ return &memtag_dynamic_entries_;
+ }
+ void* memtag_globals() const { return memtag_dynamic_entries()->memtag_globals; }
+ size_t memtag_globalssz() const { return memtag_dynamic_entries()->memtag_globalssz; }
+ bool has_memtag_mode() const { return memtag_dynamic_entries()->has_memtag_mode; }
+ unsigned memtag_mode() const { return memtag_dynamic_entries()->memtag_mode; }
+ bool memtag_heap() const { return memtag_dynamic_entries()->memtag_heap; }
+ bool memtag_stack() const { return memtag_dynamic_entries()->memtag_stack; }
+
private:
bool is_image_linked() const;
void set_image_linked();
@@ -433,6 +446,9 @@
// version >= 6
ElfW(Addr) gap_start_;
size_t gap_size_;
+
+ // version >= 7
+ memtag_dynamic_entries_t memtag_dynamic_entries_;
};
// This function is used by dlvsym() to calculate hash of sym_ver
diff --git a/tests/bionic_allocator_test.cpp b/tests/bionic_allocator_test.cpp
index fdcf868..d543d26 100644
--- a/tests/bionic_allocator_test.cpp
+++ b/tests/bionic_allocator_test.cpp
@@ -238,23 +238,27 @@
TEST(bionic_allocator, test_memalign_large) {
BionicAllocator allocator;
void* ptr;
+ size_t alignment;
- // a large object with alignment < PAGE_SIZE
- ptr = allocator.memalign(0x100, 0x2000);
+ // a large object with alignment < kPageSize
+ alignment = kPageSize >> 1;
+ ptr = allocator.memalign(alignment, 0x2000);
ASSERT_TRUE(ptr != nullptr);
- ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr) % 0x100);
+ ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr) % alignment);
allocator.free(ptr);
- // a large object with alignment == PAGE_SIZE
- ptr = allocator.memalign(0x1000, 0x2000);
+ // a large object with alignment == kPageSize
+ alignment = kPageSize;
+ ptr = allocator.memalign(alignment, 0x2000);
ASSERT_TRUE(ptr != nullptr);
- ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr) % 0x1000);
+ ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr) % alignment);
allocator.free(ptr);
- // A large object with alignment > PAGE_SIZE is only guaranteed to have page
+ // A large object with alignment > kPageSize is only guaranteed to have page
// alignment.
- ptr = allocator.memalign(0x2000, 0x4000);
+ alignment = kPageSize << 1;
+ ptr = allocator.memalign(alignment, 0x4000);
ASSERT_TRUE(ptr != nullptr);
- ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr) % 0x1000);
+ ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(ptr) % kPageSize);
allocator.free(ptr);
}
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index 3c2dcf2..d078e50 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -85,6 +85,7 @@
}
void* handle_;
+ const size_t kPageSize = getpagesize();
};
TEST_F(DlExtTest, ExtInfoNull) {
@@ -159,12 +160,12 @@
ASSERT_STREQ("dlopen failed: file offset for the library \"libname_placeholder\" is not page-aligned: 17", dlerror());
// Test an address above 2^44, for http://b/18178121 .
- extinfo.library_fd_offset = (5LL<<48) + PAGE_SIZE;
+ extinfo.library_fd_offset = (5LL << 48) + kPageSize;
handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo);
ASSERT_TRUE(handle_ == nullptr);
ASSERT_SUBSTR("dlopen failed: file offset for the library \"libname_placeholder\" >= file size", dlerror());
- extinfo.library_fd_offset = 0LL - PAGE_SIZE;
+ extinfo.library_fd_offset = 0LL - kPageSize;
handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo);
ASSERT_TRUE(handle_ == nullptr);
ASSERT_SUBSTR("dlopen failed: file offset for the library \"libname_placeholder\" is negative", dlerror());
@@ -340,17 +341,17 @@
dlclose(handle_);
handle_ = nullptr;
- void* new_start = mmap(start, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ void* new_start = mmap(start, kPageSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
ASSERT_NE(start, new_start) << "dlclose unmapped reserved space";
}
TEST_F(DlExtTest, ReservedTooSmall) {
- void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ void* start = mmap(nullptr, kPageSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
ASSERT_TRUE(start != MAP_FAILED);
android_dlextinfo extinfo;
extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
extinfo.reserved_addr = start;
- extinfo.reserved_size = PAGE_SIZE;
+ extinfo.reserved_size = kPageSize;
handle_ = android_dlopen_ext(kLibName, RTLD_NOW, &extinfo);
EXPECT_EQ(nullptr, handle_);
}
@@ -389,12 +390,12 @@
}
TEST_F(DlExtTest, ReservedRecursiveTooSmall) {
- void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ void* start = mmap(nullptr, kPageSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
ASSERT_TRUE(start != MAP_FAILED);
android_dlextinfo extinfo;
extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_RECURSIVE;
extinfo.reserved_addr = start;
- extinfo.reserved_size = PAGE_SIZE;
+ extinfo.reserved_size = kPageSize;
handle_ = android_dlopen_ext(kLibNameRecursive, RTLD_NOW, &extinfo);
EXPECT_EQ(nullptr, handle_);
}
@@ -417,19 +418,18 @@
}
TEST_F(DlExtTest, ReservedHintTooSmall) {
- void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ void* start = mmap(nullptr, kPageSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
ASSERT_TRUE(start != MAP_FAILED);
android_dlextinfo extinfo;
extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT;
extinfo.reserved_addr = start;
- extinfo.reserved_size = PAGE_SIZE;
+ extinfo.reserved_size = kPageSize;
handle_ = android_dlopen_ext(kLibName, RTLD_NOW, &extinfo);
ASSERT_DL_NOTNULL(handle_);
fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
ASSERT_DL_NOTNULL(f);
EXPECT_TRUE(reinterpret_cast<void*>(f) < start ||
- (reinterpret_cast<void*>(f) >=
- reinterpret_cast<char*>(start) + PAGE_SIZE));
+ (reinterpret_cast<void*>(f) >= reinterpret_cast<char*>(start) + kPageSize));
EXPECT_EQ(4, f());
}
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 67f1973..5b3eaf8 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -824,6 +824,8 @@
}
TEST(dlfcn, dlclose_unload) {
+ const size_t kPageSize = getpagesize();
+
void* handle = dlopen("libtest_simple.so", RTLD_NOW);
ASSERT_TRUE(handle != nullptr) << dlerror();
uint32_t* taxicab_number = static_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
@@ -833,8 +835,8 @@
// Making sure that the library has been unmapped as part of library unload
// process. Note that mprotect somewhat counter-intuitively returns ENOMEM in
// this case.
- uintptr_t page_start = reinterpret_cast<uintptr_t>(taxicab_number) & ~(PAGE_SIZE - 1);
- ASSERT_TRUE(mprotect(reinterpret_cast<void*>(page_start), PAGE_SIZE, PROT_NONE) != 0);
+ uintptr_t page_start = reinterpret_cast<uintptr_t>(taxicab_number) & ~(kPageSize - 1);
+ ASSERT_TRUE(mprotect(reinterpret_cast<void*>(page_start), kPageSize, PROT_NONE) != 0);
ASSERT_ERRNO(ENOMEM);
}
diff --git a/tests/fcntl_test.cpp b/tests/fcntl_test.cpp
index b3be18e..47f3d91 100644
--- a/tests/fcntl_test.cpp
+++ b/tests/fcntl_test.cpp
@@ -363,5 +363,5 @@
}
TEST_F(fcntl_DeathTest, fcntl_F_SETFD) {
- EXPECT_DEATH(fcntl(0, F_SETFD, O_NONBLOCK), "non-FD_CLOEXEC");
+ EXPECT_DEATH(fcntl(0, F_SETFD, O_NONBLOCK), "only supports FD_CLOEXEC");
}
diff --git a/tests/libs/stack_tagging_helper.cpp b/tests/libs/stack_tagging_helper.cpp
index d29844d..7396dd0 100644
--- a/tests/libs/stack_tagging_helper.cpp
+++ b/tests/libs/stack_tagging_helper.cpp
@@ -240,14 +240,14 @@
}
void test_longjmp_sigaltstack() {
- constexpr size_t kAltStackSize = kStackAllocationSize + PAGE_SIZE * 16;
+ const size_t kAltStackSize = kStackAllocationSize + getpagesize() * 16;
SigAltStackScoped sigAltStackScoped(kAltStackSize);
SigActionScoped sigActionScoped(
SIGUSR1, [](int, siginfo_t*, void*) { check_longjmp_restores_tags(); });
raise(SIGUSR1);
// same for a secondary thread
- std::thread t([]() {
+ std::thread t([&]() {
SigAltStackScoped sigAltStackScoped(kAltStackSize);
raise(SIGUSR1);
});
diff --git a/tests/sys_mman_test.cpp b/tests/sys_mman_test.cpp
index e785ff4..df13e07 100644
--- a/tests/sys_mman_test.cpp
+++ b/tests/sys_mman_test.cpp
@@ -25,6 +25,8 @@
#include "utils.h"
+static const size_t kPageSize = getpagesize();
+
TEST(sys_mman, mmap_std) {
void* map = mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
ASSERT_NE(MAP_FAILED, map);
@@ -233,42 +235,42 @@
}
TEST(sys_mman, mremap_PTRDIFF_MAX) {
- void* map = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ void* map = mmap(nullptr, kPageSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
ASSERT_NE(MAP_FAILED, map);
- ASSERT_EQ(MAP_FAILED, mremap(map, PAGE_SIZE, kHuge, MREMAP_MAYMOVE));
+ ASSERT_EQ(MAP_FAILED, mremap(map, kPageSize, kHuge, MREMAP_MAYMOVE));
- ASSERT_EQ(0, munmap(map, PAGE_SIZE));
+ ASSERT_EQ(0, munmap(map, kPageSize));
}
TEST(sys_mman, mmap_bug_27265969) {
- char* base = reinterpret_cast<char*>(mmap(nullptr, PAGE_SIZE * 2, PROT_EXEC | PROT_READ,
- MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
+ char* base = reinterpret_cast<char*>(
+ mmap(nullptr, kPageSize * 2, PROT_EXEC | PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
// Some kernels had bugs that would cause segfaults here...
- __builtin___clear_cache(base, base + (PAGE_SIZE * 2));
+ __builtin___clear_cache(base, base + (kPageSize * 2));
}
TEST(sys_mman, mlock) {
- void* map = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ void* map = mmap(nullptr, kPageSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
ASSERT_NE(MAP_FAILED, map);
// Not really anything we can assert about this.
- mlock(map, PAGE_SIZE);
+ mlock(map, kPageSize);
- ASSERT_EQ(0, munmap(map, PAGE_SIZE));
+ ASSERT_EQ(0, munmap(map, kPageSize));
}
TEST(sys_mman, mlock2) {
#if defined(__GLIBC__)
GTEST_SKIP() << "needs glibc 2.27";
#else
- void* map = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ void* map = mmap(nullptr, kPageSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
ASSERT_NE(MAP_FAILED, map);
// Not really anything we can assert about this.
- mlock2(map, PAGE_SIZE, MLOCK_ONFAULT);
+ mlock2(map, kPageSize, MLOCK_ONFAULT);
- ASSERT_EQ(0, munmap(map, PAGE_SIZE));
+ ASSERT_EQ(0, munmap(map, kPageSize));
#endif
}
diff --git a/tests/syslog_test.cpp b/tests/syslog_test.cpp
index 3ec3337..623d8a3 100644
--- a/tests/syslog_test.cpp
+++ b/tests/syslog_test.cpp
@@ -26,6 +26,9 @@
* SUCH DAMAGE.
*/
+#include <stddef.h> // glibc's <syslog.h> breaks without this; musl seems fine.
+
+#define SYSLOG_NAMES
#include <syslog.h>
#include <errno.h>
@@ -72,3 +75,34 @@
},
0, "bar: x{1023}\n");
}
+
+static int by_name(const CODE* array, const char* name) {
+ for (auto c = array; c->c_name != nullptr; c++) {
+ if (!strcmp(c->c_name, name)) return c->c_val;
+ }
+ return -1;
+}
+
+static const char* by_value(const CODE* array, int value) {
+ for (auto c = array; c->c_name != nullptr; c++) {
+ if (c->c_val == value) return c->c_name;
+ }
+ return nullptr;
+}
+
+TEST(syslog, facilitynames) {
+ ASSERT_STREQ("auth", by_value(facilitynames, LOG_AUTH));
+ ASSERT_STREQ("local7", by_value(facilitynames, LOG_LOCAL7));
+ ASSERT_EQ(LOG_AUTH, by_name(facilitynames, "auth"));
+ ASSERT_EQ(LOG_LOCAL7, by_name(facilitynames, "local7"));
+}
+
+TEST(syslog, prioritynames) {
+ ASSERT_STREQ("alert", by_value(prioritynames, LOG_ALERT));
+ ASSERT_STREQ("err", by_value(prioritynames, LOG_ERR));
+ ASSERT_STREQ("warn", by_value(prioritynames, LOG_WARNING));
+ ASSERT_EQ(LOG_ALERT, by_name(prioritynames, "alert"));
+ ASSERT_EQ(LOG_ERR, by_name(prioritynames, "err"));
+ ASSERT_EQ(LOG_WARNING, by_name(prioritynames, "warn"));
+ ASSERT_EQ(LOG_WARNING, by_name(prioritynames, "warning"));
+}