Merge "Update linkerconfig configuration format"
diff --git a/libc/Android.bp b/libc/Android.bp
index a761e3b..06eb6dd 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -62,6 +62,7 @@
cppflags: [],
include_dirs: [
"bionic/libc/async_safe/include",
+ "bionic/libc/platform",
// For android_filesystem_config.h.
"system/core/libcutils/include",
],
@@ -1077,6 +1078,7 @@
"bionic/mblen.cpp",
"bionic/mbrtoc16.cpp",
"bionic/mbrtoc32.cpp",
+ "bionic/memory_mitigation_state.cpp",
"bionic/mempcpy.cpp",
"bionic/mkdir.cpp",
"bionic/mkfifo.cpp",
@@ -1726,7 +1728,7 @@
versions: [
"29",
"R",
- "10000",
+ "current",
],
},
@@ -1738,6 +1740,10 @@
// Sorting bss symbols by size usually results in less dirty pages at run
// time, because small symbols are grouped together.
sort_bss_symbols_by_size: true,
+
+ lto: {
+ never: true,
+ },
}
genrule {
@@ -1785,8 +1791,9 @@
"//external/perfetto:__subpackages__",
"//external/scudo:__subpackages__",
"//system/core/debuggerd:__subpackages__",
- "//system/core/libunwindstack:__subpackages__",
+ "//system/core/libcutils:__subpackages__",
"//system/memory/libmemunreachable:__subpackages__",
+ "//system/unwinding/libunwindstack:__subpackages__",
"//tools/security/sanitizer-status:__subpackages__",
],
vendor_available: true,
@@ -1800,11 +1807,10 @@
stl: "none",
sdk_version: "current",
+ min_sdk_version: "29",
apex_available: [
"//apex_available:platform",
- "com.android.runtime",
- "com.android.art.release", // from libdexfile_external
- "com.android.art.debug", // from libdexfile_external
+ "//apex_available:anyapex",
],
}
diff --git a/libc/arch-arm64/bionic/__bionic_clone.S b/libc/arch-arm64/bionic/__bionic_clone.S
index c3ff0e5..e9932ad 100644
--- a/libc/arch-arm64/bionic/__bionic_clone.S
+++ b/libc/arch-arm64/bionic/__bionic_clone.S
@@ -57,3 +57,5 @@
ldp x0, x1, [sp], #16
b __start_thread
END(__bionic_clone)
+
+NOTE_GNU_PROPERTY()
diff --git a/libc/arch-arm64/bionic/_exit_with_stack_teardown.S b/libc/arch-arm64/bionic/_exit_with_stack_teardown.S
index 6a7b1e5..c53a1f4 100644
--- a/libc/arch-arm64/bionic/_exit_with_stack_teardown.S
+++ b/libc/arch-arm64/bionic/_exit_with_stack_teardown.S
@@ -39,3 +39,5 @@
svc #0
// The exit syscall does not return.
END(_exit_with_stack_teardown)
+
+NOTE_GNU_PROPERTY()
diff --git a/libc/arch-arm64/bionic/setjmp.S b/libc/arch-arm64/bionic/setjmp.S
index a2b2370..07270c9 100644
--- a/libc/arch-arm64/bionic/setjmp.S
+++ b/libc/arch-arm64/bionic/setjmp.S
@@ -118,6 +118,8 @@
// int sigsetjmp(sigjmp_buf env, int save_signal_mask);
ENTRY(sigsetjmp)
__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(sigsetjmp)
+ hint #25 // paciasp
+ .cfi_negate_ra_state
stp x0, x30, [sp, #-16]!
.cfi_def_cfa_offset 16
.cfi_rel_offset x0, 0
@@ -184,6 +186,8 @@
#endif
mov w0, #0
+ hint #29 // autiasp
+ .cfi_negate_ra_state
ret
END(sigsetjmp)
@@ -250,7 +254,9 @@
1:
// Restore core registers.
bic x2, x2, #1
+ // x30 was saved with PAC to jmp_buf in sigsetjmp().
ldp x30, x10, [x0, #(_JB_X30_SP * 8)]
+ .cfi_negate_ra_state
ldp x28, x29, [x0, #(_JB_X28_X29 * 8)]
ldp x26, x27, [x0, #(_JB_X26_X27 * 8)]
ldp x24, x25, [x0, #(_JB_X24_X25 * 8)]
@@ -290,6 +296,8 @@
// Set return value.
cmp w1, wzr
csinc w0, w1, wzr, ne
+ hint #29 // autiasp
+ .cfi_negate_ra_state
ret
END(siglongjmp)
@@ -297,3 +305,5 @@
__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(longjmp)
ALIAS_SYMBOL(_longjmp, siglongjmp)
__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(_longjmp)
+
+NOTE_GNU_PROPERTY()
diff --git a/libc/arch-arm64/bionic/syscall.S b/libc/arch-arm64/bionic/syscall.S
index 8389f98..9e6f68a 100644
--- a/libc/arch-arm64/bionic/syscall.S
+++ b/libc/arch-arm64/bionic/syscall.S
@@ -47,3 +47,5 @@
ret
END(syscall)
+
+NOTE_GNU_PROPERTY()
diff --git a/libc/arch-arm64/bionic/vfork.S b/libc/arch-arm64/bionic/vfork.S
index 5cfb8b0..81b84a3 100644
--- a/libc/arch-arm64/bionic/vfork.S
+++ b/libc/arch-arm64/bionic/vfork.S
@@ -67,6 +67,8 @@
// Clean up stack shadow in the parent process.
// https://github.com/google/sanitizers/issues/925
+ hint #25 // paciasp
+ .cfi_negate_ra_state
stp x0, x30, [sp, #-16]!
.cfi_adjust_cfa_offset 16
.cfi_rel_offset x0, 0
@@ -79,9 +81,13 @@
.cfi_adjust_cfa_offset -16
.cfi_restore x0
.cfi_restore x30
+ hint #29 // autiasp
+ .cfi_negate_ra_state
#endif
.L_exit:
ret
END(vfork)
+
+NOTE_GNU_PROPERTY()
diff --git a/libc/arch-arm64/generic/bionic/__memcpy_chk.S b/libc/arch-arm64/generic/bionic/__memcpy_chk.S
index a6eeca4..a8e9e83 100644
--- a/libc/arch-arm64/generic/bionic/__memcpy_chk.S
+++ b/libc/arch-arm64/generic/bionic/__memcpy_chk.S
@@ -43,3 +43,5 @@
bl __memcpy_chk_fail
END(__memcpy_chk)
+
+NOTE_GNU_PROPERTY()
diff --git a/libc/arch-arm64/generic/bionic/memcpy.S b/libc/arch-arm64/generic/bionic/memcpy.S
index baadb92..bc1945c 100644
--- a/libc/arch-arm64/generic/bionic/memcpy.S
+++ b/libc/arch-arm64/generic/bionic/memcpy.S
@@ -33,3 +33,5 @@
ENTRY(__memcpy)
#include "memcpy_base.S"
END(__memcpy)
+
+NOTE_GNU_PROPERTY()
diff --git a/libc/arch-arm64/generic/bionic/memmove.S b/libc/arch-arm64/generic/bionic/memmove.S
index 335b7d6..0f752ea 100644
--- a/libc/arch-arm64/generic/bionic/memmove.S
+++ b/libc/arch-arm64/generic/bionic/memmove.S
@@ -153,3 +153,5 @@
ALIAS_SYMBOL(memcpy, memmove)
#endif
+
+NOTE_GNU_PROPERTY()
diff --git a/libc/arch-arm64/generic/bionic/memset.S b/libc/arch-arm64/generic/bionic/memset.S
index 12fc09d..19d3510 100644
--- a/libc/arch-arm64/generic/bionic/memset.S
+++ b/libc/arch-arm64/generic/bionic/memset.S
@@ -249,3 +249,5 @@
b L(tail64)
END(memset)
+
+NOTE_GNU_PROPERTY()
diff --git a/libc/arch-arm64/generic/bionic/wmemmove.S b/libc/arch-arm64/generic/bionic/wmemmove.S
index e4f67f7..b130530 100644
--- a/libc/arch-arm64/generic/bionic/wmemmove.S
+++ b/libc/arch-arm64/generic/bionic/wmemmove.S
@@ -28,3 +28,5 @@
#define WMEMMOVE
#include "memmove.S"
#undef WMEMMOVE
+
+NOTE_GNU_PROPERTY()
diff --git a/libc/arch-arm64/static_function_dispatch.S b/libc/arch-arm64/static_function_dispatch.S
index 65a1492..161ece8 100644
--- a/libc/arch-arm64/static_function_dispatch.S
+++ b/libc/arch-arm64/static_function_dispatch.S
@@ -42,3 +42,5 @@
FUNCTION_DELEGATE(strlen, __strlen_aarch64_mte)
FUNCTION_DELEGATE(strrchr, __strrchr_aarch64_mte)
FUNCTION_DELEGATE(strncmp, __strncmp_aarch64_mte)
+
+NOTE_GNU_PROPERTY()
diff --git a/libc/arch-common/bionic/crtbegin.c b/libc/arch-common/bionic/crtbegin.c
index b7043dc..1f8dfd2 100644
--- a/libc/arch-common/bionic/crtbegin.c
+++ b/libc/arch-common/bionic/crtbegin.c
@@ -49,7 +49,7 @@
#define POST "; .size _start, .-_start"
#if defined(__aarch64__)
-__asm__(PRE "mov x0,sp; b _start_main" POST);
+__asm__(PRE "/* BTI J */ hint #36; mov x0,sp; b _start_main" POST);
#elif defined(__arm__)
__asm__(PRE "mov r0,sp; b _start_main" POST);
#elif defined(__i386__)
diff --git a/libc/arch-common/bionic/crtbrand.S b/libc/arch-common/bionic/crtbrand.S
index 34d6480..3d80d73 100644
--- a/libc/arch-common/bionic/crtbrand.S
+++ b/libc/arch-common/bionic/crtbrand.S
@@ -26,6 +26,12 @@
* SUCH DAMAGE.
*/
+#if defined(__aarch64__)
+#include <private/bionic_asm_arm64.h>
+
+__bionic_asm_custom_note_gnu_section()
+#endif
+
.section .note.android.ident,"a",%note
.balign 4
.type abitag, %object
diff --git a/libc/arch-common/bionic/crtend.S b/libc/arch-common/bionic/crtend.S
index 87d1120..9676db8 100644
--- a/libc/arch-common/bionic/crtend.S
+++ b/libc/arch-common/bionic/crtend.S
@@ -28,6 +28,12 @@
#include "asm_multiarch.h"
+#if defined(__aarch64__)
+#include <private/bionic_asm_arm64.h>
+
+__bionic_asm_custom_note_gnu_section()
+#endif
+
.section .preinit_array, "aw"
ASM_ALIGN_TO_PTR_SIZE
ASM_PTR_SIZE(0)
@@ -43,11 +49,9 @@
#if defined(__linux__) && defined(__ELF__)
.section .note.GNU-stack,"",%progbits
#endif
-#if defined(__i386__) || defined(__x86_64__)
+#if !defined(__arm__)
.section .eh_frame,"a",@progbits
-#if defined(__i386__)
.balign 4
-#endif
.type __FRAME_END__, @object
.size __FRAME_END__, 4
__FRAME_END__:
diff --git a/libc/arch-common/bionic/crtend_so.S b/libc/arch-common/bionic/crtend_so.S
index e7b8cac..5875acb 100644
--- a/libc/arch-common/bionic/crtend_so.S
+++ b/libc/arch-common/bionic/crtend_so.S
@@ -26,14 +26,18 @@
* SUCH DAMAGE.
*/
+#if defined(__aarch64__)
+#include <private/bionic_asm_arm64.h>
+
+__bionic_asm_custom_note_gnu_section()
+#endif
+
#if defined(__linux__) && defined(__ELF__)
.section .note.GNU-stack,"",%progbits
#endif
-#if defined(__i386__) || defined(__x86_64__)
+#if !defined(__arm__)
.section .eh_frame,"a",@progbits
-#if defined(__i386__)
.balign 4
-#endif
.type __FRAME_END__, @object
.size __FRAME_END__, 4
__FRAME_END__:
diff --git a/libc/arch-x86/bionic/__restore.S b/libc/arch-x86/bionic/__restore.S
index cb18fd0..5977eab 100644
--- a/libc/arch-x86/bionic/__restore.S
+++ b/libc/arch-x86/bionic/__restore.S
@@ -27,14 +27,7 @@
*/
#include <private/bionic_asm.h>
-
-// DWARF constants.
-#define DW_CFA_def_cfa_expression 0x0f
-#define DW_CFA_expression 0x10
-#define DW_EH_PE_pcrel 0x10
-#define DW_EH_PE_sdata4 0x0b
-#define DW_OP_breg4 0x74
-#define DW_OP_deref 0x06
+#include <private/bionic_asm_dwarf_exprs.h>
// Offsets into struct sigcontext.
#define OFFSET_EDI 16
@@ -52,84 +45,47 @@
#define DW_x86_REG_ECX 1
#define DW_x86_REG_EDX 2
#define DW_x86_REG_EBX 3
+#define DW_x86_REG_ESP 4
#define DW_x86_REG_EBP 5
#define DW_x86_REG_ESI 6
#define DW_x86_REG_EDI 7
#define DW_x86_REG_EIP 8
-#define cfi_signal_frame_start(f) \
-.section .eh_frame,"a",@progbits; \
-.L ## f ## _START_EH_FRAME: \
- .long 2f - 1f; /* CIE length. */ \
-1:.long 0; /* CIE ID. */ \
- .byte 1; /* Version. */ \
- .string "zRS"; /* Augmentation string. */ \
- .uleb128 1; /* Code alignment factor. */ \
- .sleb128 -4; /* Data alignment factor. */ \
- .uleb128 DW_x86_REG_EIP; /* Return address register. */ \
- .uleb128 1; /* 1 byte of augmentation data. */ \
- .byte (DW_EH_PE_pcrel|DW_EH_PE_sdata4); /* FDE encoding. */ \
- .align 8; \
-2: \
- .long .L ## f ## _END_FDE - .L ## f ## _START_FDE; /* FDE length. */ \
-.L ## f ## _START_FDE: \
- .long .L ## f ## _START_FDE - .L ## f ## _START_EH_FRAME; /* CIE location. */ \
- .long (.L ## f ## _START - 1) - .; /* pcrel start address (see FDE encoding above). */ \
- .long .L ## f ## _END - (.L ## f ## _START - 1); /* Function this FDE applies to. */ \
- .uleb128 0; /* FDE augmentation length. */ \
+#define RESTORE_GPR(reg, extra_offset) \
+ m_cfi_breg_offset DW_x86_REG_ ## reg, \
+ DW_x86_REG_ESP, \
+ (OFFSET_ ## reg + (extra_offset));
-#define cfi_signal_frame_end(f) \
-.L ## f ## _END_FDE: \
+// Restoring ESP is unnecessary as the unwinder simply uses the CFA value.
+#define RESTORE_GPRS(extra_offset) \
+ m_cfi_def_cfa_deref DW_x86_REG_ESP, (OFFSET_ESP + (extra_offset)); \
+ RESTORE_GPR(EDI, extra_offset) \
+ RESTORE_GPR(ESI, extra_offset) \
+ RESTORE_GPR(EBP, extra_offset) \
+ RESTORE_GPR(EBX, extra_offset) \
+ RESTORE_GPR(EDX, extra_offset) \
+ RESTORE_GPR(ECX, extra_offset) \
+ RESTORE_GPR(EAX, extra_offset) \
+ RESTORE_GPR(EIP, extra_offset) \
-#define cfi_def_cfa(offset) \
- .byte DW_CFA_def_cfa_expression; \
- .uleb128 2f-1f; \
-1:.byte DW_OP_breg4; \
- .sleb128 offset; \
- .byte DW_OP_deref; \
-2: \
+ .text
-#define cfi_offset(reg_number,offset) \
- .byte DW_CFA_expression; \
- .uleb128 reg_number; \
- .uleb128 2f-1f; \
-1:.byte DW_OP_breg4; \
- .sleb128 offset; \
-2: \
-
-ENTRY_PRIVATE(__restore)
-.L__restore_START:
+ .cfi_startproc
+ .cfi_signal_frame
+ RESTORE_GPRS(4)
+ nop // See comment in libc/arch-x86_64/bionic/__restore_rt.S about this nop.
+ENTRY_PRIVATE_NO_DWARF(__restore)
popl %eax
+ RESTORE_GPRS(0)
movl $__NR_sigreturn, %eax
int $0x80
-.L__restore_END:
END(__restore)
-cfi_signal_frame_start(__restore)
- cfi_def_cfa(OFFSET_ESP + 4)
- cfi_offset(DW_x86_REG_EDI, OFFSET_EDI + 4)
- cfi_offset(DW_x86_REG_ESI, OFFSET_ESI + 4)
- cfi_offset(DW_x86_REG_EBP, OFFSET_EBP + 4)
- cfi_offset(DW_x86_REG_EBX, OFFSET_EBX + 4)
- cfi_offset(DW_x86_REG_EDX, OFFSET_EDX + 4)
- cfi_offset(DW_x86_REG_ECX, OFFSET_ECX + 4)
- cfi_offset(DW_x86_REG_EAX, OFFSET_EAX + 4)
- cfi_offset(DW_x86_REG_EIP, OFFSET_EIP + 4)
-cfi_signal_frame_end(__restore)
-ENTRY_PRIVATE(__restore_rt)
-.L__restore_rt_START:
+ .cfi_startproc
+ .cfi_signal_frame
+ RESTORE_GPRS(160)
+ nop // See comment in libc/arch-x86_64/bionic/__restore_rt.S about this nop.
+ENTRY_PRIVATE_NO_DWARF(__restore_rt)
movl $__NR_rt_sigreturn, %eax
int $0x80
-.L__restore_rt_END:
END(__restore_rt)
-cfi_signal_frame_start(__restore_rt)
- cfi_def_cfa(OFFSET_ESP + 160)
- cfi_offset(DW_x86_REG_EDI, OFFSET_EDI + 160)
- cfi_offset(DW_x86_REG_ESI, OFFSET_ESI + 160)
- cfi_offset(DW_x86_REG_EBP, OFFSET_EBP + 160)
- cfi_offset(DW_x86_REG_EBX, OFFSET_EBX + 160)
- cfi_offset(DW_x86_REG_EDX, OFFSET_EDX + 160)
- cfi_offset(DW_x86_REG_ECX, OFFSET_ECX + 160)
- cfi_offset(DW_x86_REG_EAX, OFFSET_EAX + 160)
- cfi_offset(DW_x86_REG_EIP, OFFSET_EIP + 160)
-cfi_signal_frame_end(__restore_rt)
diff --git a/libc/arch-x86_64/bionic/__restore_rt.S b/libc/arch-x86_64/bionic/__restore_rt.S
index 785b3b3..f3e4012 100644
--- a/libc/arch-x86_64/bionic/__restore_rt.S
+++ b/libc/arch-x86_64/bionic/__restore_rt.S
@@ -27,15 +27,9 @@
*/
#include <private/bionic_asm.h>
+#include <private/bionic_asm_dwarf_exprs.h>
-// DWARF constants.
-#define DW_CFA_def_cfa_expression 0x0f
-#define DW_CFA_expression 0x10
-#define DW_EH_PE_pcrel 0x10
-#define DW_EH_PE_sdata4 0x0b
-#define DW_OP_breg4 0x74
-#define DW_OP_breg7 0x77
-#define DW_OP_deref 0x06
+// In the signal trampoline frame, rsp points to a ucontext_t struct.
// Offsets into struct ucontext_t of uc_mcontext.gregs[x].
#define OFFSET_R8 40
@@ -49,11 +43,11 @@
#define OFFSET_RDI 104
#define OFFSET_RSI 112
#define OFFSET_RBP 120
-#define OFFSET_RSP 160
#define OFFSET_RBX 128
#define OFFSET_RDX 136
#define OFFSET_RAX 144
#define OFFSET_RCX 152
+#define OFFSET_RSP 160
#define OFFSET_RIP 168
// Non-standard DWARF constants for the x86-64 registers.
@@ -75,69 +69,47 @@
#define DW_x86_64_R15 15
#define DW_x86_64_RIP 16
-#define cfi_signal_frame_start(f) \
-.section .eh_frame,"a",@progbits; \
-.L ## f ## _START_EH_FRAME: \
- .long 2f - 1f; /* CIE length. */ \
-1:.long 0; /* CIE ID. */ \
- .byte 1; /* Version. */ \
- .string "zRS"; /* Augmentation string. */ \
- .uleb128 1; /* Code alignment factor. */ \
- .sleb128 -8; /* Data alignment factor. */ \
- .uleb128 DW_x86_64_RIP; /* Return address register. */ \
- .uleb128 1; /* 1 byte of augmentation data. */ \
- .byte (DW_EH_PE_pcrel | DW_EH_PE_sdata4); /* FDE encoding. */ \
- .align 8; \
-2: \
- .long .L ## f ## _END_FDE - .L ## f ## _START_FDE; /* FDE length. */ \
-.L ## f ## _START_FDE: \
- .long .L ## f ## _START_FDE - .L ## f ## _START_EH_FRAME; /* CIE location. */ \
- .long (.L ## f ## _START - 1) - .; /* pcrel start address (see FDE encoding above). */ \
- .long .L ## f ## _END - (.L ## f ## _START - 1); /* Function this FDE applies to. */ \
- .uleb128 0; /* FDE augmentation length. */ \
+// Insert a nop between .cfi_startproc and the trampoline symbol so that unwinders can find the FDE.
+// A function's last instruction can be a call instruction (e.g. to __cxa_throw), in which case the
+// return address (e.g. from __cxa_throw to the caller) will be just after the function. This
+// address may also be the start of the next function, so to avoid ambiguity, unwinders assume that
+// a return address PC can refer to the address just after a function, but never to the start of a
+// function. (This is implemented by subtracting 1 from the return address PC before looking it up.)
+// This is fine for ordinary functions, but breaks on trampolines. Inserting a nop fixes it.
+//
+// N.B. Unwinders have two other strategies for recognizing the signal trampoline:
+// - Read the instructions that the return address PC points at and look for a sigreturn syscall.
+// (Hence, the instructions must not change at all.)
+// - Do a symbol table lookup and check that against the PC (e.g. LLDB looks for
+// __kernel_rt_sigreturn and __restore_rt.)
+// Either way, the nop is needed to avoid ambiguity if the function before the trampoline could end
+// with a call.
-#define cfi_signal_frame_end(f) \
-.L ## f ## _END_FDE: \
+#define RESTORE_GPR(reg) m_cfi_breg_offset DW_x86_64_ ## reg, DW_x86_64_RSP, OFFSET_ ## reg;
-#define cfi_def_cfa(offset) \
- .byte DW_CFA_def_cfa_expression; \
- .uleb128 2f-1f; \
-1:.byte DW_OP_breg7; \
- .sleb128 offset; \
- .byte DW_OP_deref; \
-2: \
-
-#define cfi_offset(reg_number,offset) \
- .byte DW_CFA_expression; \
- .uleb128 reg_number; \
- .uleb128 2f-1f; \
-1:.byte DW_OP_breg7; \
- .sleb128 offset; \
-2: \
-
-ENTRY_PRIVATE(__restore_rt)
-.L__restore_rt_START:
+ .text
+ .cfi_startproc
+ .cfi_signal_frame
+ m_cfi_def_cfa_deref DW_x86_64_RSP, OFFSET_RSP
+ RESTORE_GPR(R8)
+ RESTORE_GPR(R9)
+ RESTORE_GPR(R10)
+ RESTORE_GPR(R11)
+ RESTORE_GPR(R12)
+ RESTORE_GPR(R13)
+ RESTORE_GPR(R14)
+ RESTORE_GPR(R15)
+ RESTORE_GPR(RDI)
+ RESTORE_GPR(RSI)
+ RESTORE_GPR(RBP)
+ RESTORE_GPR(RBX)
+ RESTORE_GPR(RDX)
+ RESTORE_GPR(RAX)
+ RESTORE_GPR(RCX)
+ // Restoring RSP is unnecessary as the unwinder simply uses the CFA value.
+ RESTORE_GPR(RIP)
+ nop
+ENTRY_PRIVATE_NO_DWARF(__restore_rt)
mov $__NR_rt_sigreturn, %rax
syscall
-.L__restore_rt_END:
END(__restore_rt)
-cfi_signal_frame_start(__restore_rt)
- cfi_def_cfa(OFFSET_RSP)
- cfi_offset(DW_x86_64_R8, OFFSET_R8)
- cfi_offset(DW_x86_64_R9, OFFSET_R9)
- cfi_offset(DW_x86_64_R10, OFFSET_R10)
- cfi_offset(DW_x86_64_R11, OFFSET_R11)
- cfi_offset(DW_x86_64_R12, OFFSET_R12)
- cfi_offset(DW_x86_64_R13, OFFSET_R13)
- cfi_offset(DW_x86_64_R14, OFFSET_R14)
- cfi_offset(DW_x86_64_R15, OFFSET_R15)
- cfi_offset(DW_x86_64_RDI, OFFSET_RDI)
- cfi_offset(DW_x86_64_RSI, OFFSET_RSI)
- cfi_offset(DW_x86_64_RBP, OFFSET_RBP)
- cfi_offset(DW_x86_64_RSP, OFFSET_RSP)
- cfi_offset(DW_x86_64_RBX, OFFSET_RBX)
- cfi_offset(DW_x86_64_RDX, OFFSET_RDX)
- cfi_offset(DW_x86_64_RAX, OFFSET_RAX)
- cfi_offset(DW_x86_64_RCX, OFFSET_RCX)
- cfi_offset(DW_x86_64_RIP, OFFSET_RIP)
-cfi_signal_frame_end(__restore_rt)
diff --git a/libc/bionic/fork.cpp b/libc/bionic/fork.cpp
index 5bc7d3f..8c5cf2b 100644
--- a/libc/bionic/fork.cpp
+++ b/libc/bionic/fork.cpp
@@ -33,8 +33,8 @@
#include "private/bionic_defs.h"
#include "pthread_internal.h"
-__BIONIC_WEAK_FOR_NATIVE_BRIDGE
-extern "C" __LIBC_HIDDEN__ int __clone_for_fork() {
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE_INLINE
+int __clone_for_fork() {
pthread_internal_t* self = __get_thread();
int result = clone(nullptr, nullptr, (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD),
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index 01b6a42..80adbbe 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -58,6 +58,7 @@
__LIBC_HIDDEN__ WriteProtected<libc_globals> __libc_globals;
// Not public, but well-known in the BSDs.
+__BIONIC_WEAK_VARIABLE_FOR_NATIVE_BRIDGE
const char* __progname;
void __libc_init_globals() {
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
index ed5537f..6b7006d 100644
--- a/libc/bionic/malloc_common.cpp
+++ b/libc/bionic/malloc_common.cpp
@@ -46,6 +46,7 @@
#include "malloc_common.h"
#include "malloc_limit.h"
#include "malloc_tagged_pointers.h"
+#include "memory_mitigation_state.h"
// =============================================================================
// Global variables instantations.
@@ -326,6 +327,9 @@
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 6a82ae3..eeeaff9 100644
--- a/libc/bionic/malloc_common_dynamic.cpp
+++ b/libc/bionic/malloc_common_dynamic.cpp
@@ -70,6 +70,7 @@
#include "malloc_common_dynamic.h"
#include "malloc_heapprofd.h"
#include "malloc_limit.h"
+#include "memory_mitigation_state.h"
// =============================================================================
// Global variables instantations.
@@ -533,6 +534,9 @@
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/memory_mitigation_state.cpp b/libc/bionic/memory_mitigation_state.cpp
new file mode 100644
index 0000000..82b0b7b
--- /dev/null
+++ b/libc/bionic/memory_mitigation_state.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "memory_mitigation_state.h"
+
+#include <dirent.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdatomic.h>
+#include <stdlib.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+
+#include <bionic/mte.h>
+#include <bionic/reserved_signals.h>
+
+#include "private/ScopedRWLock.h"
+#include "pthread_internal.h"
+
+extern "C" void scudo_malloc_set_zero_contents(int zero_contents);
+extern "C" void scudo_malloc_disable_memory_tagging();
+
+#ifdef ANDROID_EXPERIMENTAL_MTE
+static bool set_tcf_on_all_threads(int tcf) {
+ static int g_tcf;
+ g_tcf = tcf;
+
+ return android_run_on_all_threads(
+ [](void*) {
+ int tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
+ if (tagged_addr_ctrl < 0) {
+ return false;
+ }
+
+ tagged_addr_ctrl = (tagged_addr_ctrl & ~PR_MTE_TCF_MASK) | g_tcf;
+ if (prctl(PR_SET_TAGGED_ADDR_CTRL, tagged_addr_ctrl, 0, 0, 0) < 0) {
+ return false;
+ }
+ return true;
+ },
+ nullptr);
+}
+#endif
+
+bool DisableMemoryMitigations(void* arg, size_t arg_size) {
+ if (arg || arg_size) {
+ return false;
+ }
+
+#ifdef USE_SCUDO
+ scudo_malloc_set_zero_contents(0);
+
+#ifdef ANDROID_EXPERIMENTAL_MTE
+ if (mte_supported() && set_tcf_on_all_threads(PR_MTE_TCF_NONE)) {
+ scudo_malloc_disable_memory_tagging();
+ }
+#endif
+#endif
+
+ return true;
+}
diff --git a/libc/bionic/memory_mitigation_state.h b/libc/bionic/memory_mitigation_state.h
new file mode 100644
index 0000000..ffa1912
--- /dev/null
+++ b/libc/bionic/memory_mitigation_state.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <stddef.h>
+
+bool DisableMemoryMitigations(void* arg, size_t arg_size);
diff --git a/libc/bionic/pthread_cond.cpp b/libc/bionic/pthread_cond.cpp
index e857069..793dcd9 100644
--- a/libc/bionic/pthread_cond.cpp
+++ b/libc/bionic/pthread_cond.cpp
@@ -116,7 +116,8 @@
}
#if defined(__LP64__)
- char __reserved[44];
+ atomic_uint waiters;
+ char __reserved[40];
#endif
};
@@ -141,6 +142,10 @@
}
atomic_init(&cond->state, init_state);
+#if defined(__LP64__)
+ atomic_init(&cond->waiters, 0);
+#endif
+
return 0;
}
@@ -163,6 +168,12 @@
// not be called. That's why pthread_wait/signal pair can't be used as a method for memory
// synchronization. And it doesn't help even if we use any fence here.
+#if defined(__LP64__)
+ if (atomic_load_explicit(&cond->waiters, memory_order_relaxed) == 0) {
+ return 0;
+ }
+#endif
+
// The increase of value should leave flags alone, even if the value can overflows.
atomic_fetch_add_explicit(&cond->state, COND_COUNTER_STEP, memory_order_relaxed);
@@ -178,9 +189,19 @@
}
unsigned int old_state = atomic_load_explicit(&cond->state, memory_order_relaxed);
+
+#if defined(__LP64__)
+ atomic_fetch_add_explicit(&cond->waiters, 1, memory_order_relaxed);
+#endif
+
pthread_mutex_unlock(mutex);
int status = __futex_wait_ex(&cond->state, cond->process_shared(), old_state,
use_realtime_clock, abs_timeout_or_null);
+
+#if defined(__LP64__)
+ atomic_fetch_sub_explicit(&cond->waiters, 1, memory_order_relaxed);
+#endif
+
pthread_mutex_lock(mutex);
if (status == -ETIMEDOUT) {
diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
index c528105..206d5fd 100644
--- a/libc/bionic/pthread_create.cpp
+++ b/libc/bionic/pthread_create.cpp
@@ -39,6 +39,7 @@
#include <async_safe/log.h>
+#include "private/ScopedRWLock.h"
#include "private/bionic_constants.h"
#include "private/bionic_defs.h"
#include "private/bionic_globals.h"
@@ -357,6 +358,7 @@
return nullptr;
}
+pthread_rwlock_t g_thread_creation_lock = PTHREAD_RWLOCK_INITIALIZER;
__BIONIC_WEAK_FOR_NATIVE_BRIDGE
int pthread_create(pthread_t* thread_out, pthread_attr_t const* attr,
@@ -406,6 +408,8 @@
tls = &tls_descriptor;
#endif
+ ScopedReadLock locker(&g_thread_creation_lock);
+
sigset64_t block_all_mask;
sigfillset64(&block_all_mask);
__rt_sigprocmask(SIG_SETMASK, &block_all_mask, &thread->start_mask, sizeof(thread->start_mask));
diff --git a/libc/bionic/pthread_exit.cpp b/libc/bionic/pthread_exit.cpp
index 81dab57..bde95ec 100644
--- a/libc/bionic/pthread_exit.cpp
+++ b/libc/bionic/pthread_exit.cpp
@@ -35,6 +35,7 @@
#include "private/bionic_constants.h"
#include "private/bionic_defs.h"
+#include "private/ScopedRWLock.h"
#include "private/ScopedSignalBlocker.h"
#include "pthread_internal.h"
@@ -103,9 +104,18 @@
!atomic_compare_exchange_weak(&thread->join_state, &old_state, THREAD_EXITED_NOT_JOINED)) {
}
- // We don't want to take a signal after unmapping the stack, the shadow call
- // stack, or dynamic TLS memory.
- ScopedSignalBlocker ssb;
+ // android_run_on_all_threads() needs to see signals blocked atomically with setting the
+ // terminating flag, so take the creation lock while doing these operations.
+ {
+ ScopedReadLock locker(&g_thread_creation_lock);
+ atomic_store(&thread->terminating, true);
+
+ // We don't want to take a signal after unmapping the stack, the shadow call stack, or dynamic
+ // TLS memory.
+ sigset64_t set;
+ sigfillset64(&set);
+ __rt_sigprocmask(SIG_BLOCK, &set, nullptr, sizeof(sigset64_t));
+ }
#ifdef __aarch64__
// Free the shadow call stack and guard pages.
diff --git a/libc/bionic/pthread_internal.cpp b/libc/bionic/pthread_internal.cpp
index e091158..6a7ee2f 100644
--- a/libc/bionic/pthread_internal.cpp
+++ b/libc/bionic/pthread_internal.cpp
@@ -29,12 +29,15 @@
#include "pthread_internal.h"
#include <errno.h>
+#include <semaphore.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <async_safe/log.h>
+#include <bionic/reserved_signals.h>
+#include "private/ErrnoRestorer.h"
#include "private/ScopedRWLock.h"
#include "private/bionic_futex.h"
#include "private/bionic_tls.h"
@@ -115,3 +118,76 @@
}
return nullptr;
}
+
+bool android_run_on_all_threads(bool (*func)(void*), void* arg) {
+ // Take the locks in this order to avoid inversion (pthread_create ->
+ // __pthread_internal_add).
+ ScopedWriteLock creation_locker(&g_thread_creation_lock);
+ ScopedReadLock list_locker(&g_thread_list_lock);
+
+ // Call the function directly for the current thread so that we don't need to worry about
+ // the consequences of synchronizing with ourselves.
+ if (!func(arg)) {
+ return false;
+ }
+
+ static sem_t g_sem;
+ if (sem_init(&g_sem, 0, 0) != 0) {
+ return false;
+ }
+
+ static bool (*g_func)(void*);
+ static void *g_arg;
+ g_func = func;
+ g_arg = arg;
+
+ static _Atomic(bool) g_retval;
+ atomic_init(&g_retval, true);
+
+ auto handler = [](int, siginfo_t*, void*) {
+ ErrnoRestorer restorer;
+ if (!g_func(g_arg)) {
+ atomic_store(&g_retval, false);
+ }
+ sem_post(&g_sem);
+ };
+
+ struct sigaction act = {}, oldact;
+ act.sa_flags = SA_SIGINFO;
+ act.sa_sigaction = handler;
+ sigfillset(&act.sa_mask);
+ if (sigaction(BIONIC_SIGNAL_RUN_ON_ALL_THREADS, &act, &oldact) != 0) {
+ sem_destroy(&g_sem);
+ return false;
+ }
+
+ pid_t my_pid = getpid();
+ size_t num_tids = 0;
+ for (pthread_internal_t* t = g_thread_list; t != nullptr; t = t->next) {
+ // The function is called directly for the current thread above, so no need to send a signal to
+ // ourselves to call it here.
+ if (t == __get_thread()) continue;
+
+ // If a thread is terminating (has blocked signals) or has already terminated, our signal will
+ // never be received, so we need to check for that condition and skip the thread if it is the
+ // case.
+ if (atomic_load(&t->terminating)) continue;
+
+ if (tgkill(my_pid, t->tid, BIONIC_SIGNAL_RUN_ON_ALL_THREADS) == 0) {
+ ++num_tids;
+ } else {
+ atomic_store(&g_retval, false);
+ }
+ }
+
+ for (size_t i = 0; i != num_tids; ++i) {
+ if (TEMP_FAILURE_RETRY(sem_wait(&g_sem)) != 0) {
+ atomic_store(&g_retval, false);
+ break;
+ }
+ }
+
+ sigaction(BIONIC_SIGNAL_RUN_ON_ALL_THREADS, &oldact, 0);
+ sem_destroy(&g_sem);
+ return atomic_load(&g_retval);
+}
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index 1f055f5..071a5bc 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -132,6 +132,11 @@
// top of the stack quickly, which would otherwise require special logic for the main thread.
uintptr_t stack_top;
+ // Whether the thread is in the process of terminating (has blocked signals), or has already
+ // terminated. This is used by android_run_on_all_threads() to avoid sending a signal to a thread
+ // that will never receive it.
+ _Atomic(bool) terminating;
+
Lock startup_handshake_lock;
void* mmap_base;
@@ -242,3 +247,7 @@
__LIBC_HIDDEN__ extern void __bionic_atfork_run_prepare();
__LIBC_HIDDEN__ extern void __bionic_atfork_run_child();
__LIBC_HIDDEN__ extern void __bionic_atfork_run_parent();
+
+extern "C" bool android_run_on_all_threads(bool (*func)(void*), void* arg);
+
+extern pthread_rwlock_t g_thread_creation_lock;
diff --git a/libc/bionic/sys_thread_properties.cpp b/libc/bionic/sys_thread_properties.cpp
index 24d7551..d1a73b7 100644
--- a/libc/bionic/sys_thread_properties.cpp
+++ b/libc/bionic/sys_thread_properties.cpp
@@ -39,6 +39,11 @@
#include <sys/uio.h>
#include <sys/user.h>
+#if defined(__i386__)
+#include <asm/ldt.h>
+#endif
+
+#include "private/ErrnoRestorer.h"
#include "private/bionic_elf_tls.h"
#include "private/bionic_globals.h"
#include "private/bionic_tls.h"
@@ -72,21 +77,30 @@
// Find the thread-pointer register for the given thread.
void** tp_reg = nullptr;
-
-#if defined(__x86_64__) || defined(__i386__)
+#if defined(__x86_64__)
+ {
+ ErrnoRestorer errno_restorer;
+ errno = 0;
+ uintptr_t fs_base = ptrace(PTRACE_PEEKUSER, tid, offsetof(user_regs_struct, fs_base), nullptr);
+ if (errno == 0) {
+ tp_reg = reinterpret_cast<void**>(fs_base);
+ }
+ }
+#elif defined(__i386__)
struct user_regs_struct regs;
struct iovec pt_iov = {
.iov_base = ®s,
.iov_len = sizeof(regs),
};
+
if (ptrace(PTRACE_GETREGSET, tid, NT_PRSTATUS, &pt_iov) == 0) {
-#if defined(__x86_64__)
- tp_reg = reinterpret_cast<void**>(regs.fs);
-#elif defined(__i386__)
- tp_reg = reinterpret_cast<void**>(regs.xgs);
-#endif
+ struct user_desc u_info;
+ u_info.entry_number = regs.xgs >> 3;
+ if (ptrace(PTRACE_GET_THREAD_AREA, tid, u_info.entry_number, &u_info) == 0) {
+ tp_reg = reinterpret_cast<void**>(u_info.base_addr);
+ }
}
-#elif defined(__aarch64__) || defined(__arm__)
+#elif defined(__aarch64__)
uint64_t reg;
struct iovec pt_iov {
.iov_base = ®, .iov_len = sizeof(reg),
@@ -95,6 +109,11 @@
if (ptrace(PTRACE_GETREGSET, tid, NT_ARM_TLS, &pt_iov) == 0) {
tp_reg = reinterpret_cast<void**>(reg);
}
+#elif defined(__arm__)
+ if (ptrace(PTRACE_GET_THREAD_AREA, tid, nullptr, &tp_reg) != 0) {
+ // Reset the tp_reg if ptrace was unsuccessful.
+ tp_reg = nullptr;
+ }
#endif
if (tp_reg == nullptr) {
diff --git a/libc/dns/net/gethnamaddr.c b/libc/dns/net/gethnamaddr.c
index 7e18840..84942f8 100644
--- a/libc/dns/net/gethnamaddr.c
+++ b/libc/dns/net/gethnamaddr.c
@@ -90,6 +90,8 @@
#include "hostent.h"
+#include "private/bionic_defs.h"
+
#define maybe_ok(res, nm, ok) (((res)->options & RES_NOCHECKNAME) != 0U || \
(ok)(nm) != 0)
#define maybe_hnok(res, hn) maybe_ok((res), (hn), res_hnok)
@@ -1533,6 +1535,7 @@
* Non-reentrant versions.
*/
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
struct hostent *
gethostbyname(const char *name)
{
@@ -1590,6 +1593,7 @@
return hp;
}
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
struct hostent *
gethostbyaddr(const void *addr, socklen_t len, int af)
{
diff --git a/libc/dns/net/getnameinfo.c b/libc/dns/net/getnameinfo.c
index 31d07c5..413b37e 100644
--- a/libc/dns/net/getnameinfo.c
+++ b/libc/dns/net/getnameinfo.c
@@ -68,6 +68,8 @@
#include <stddef.h>
#include <string.h>
+#include "private/bionic_defs.h"
+
/* This macro is modelled after the ones in <netinet/in6.h>. */
/* RFC 6052, section 2.1 */
#define IN6_IS_ADDR_WKP(a) \
@@ -110,6 +112,7 @@
* Top-level getnameinfo() code. Look at the address family, and pick an
* appropriate function to call.
*/
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
int getnameinfo(const struct sockaddr* sa, socklen_t salen, char* host, size_t hostlen,
char* serv, size_t servlen, int flags)
{
diff --git a/libc/include/bits/elf_arm64.h b/libc/include/bits/elf_arm64.h
index 6bb8384..9330d7b 100644
--- a/libc/include/bits/elf_arm64.h
+++ b/libc/include/bits/elf_arm64.h
@@ -89,4 +89,9 @@
#define R_AARCH64_TLSDESC 1031 /* 16-byte descriptor: resolver func + arg. */
#define R_AARCH64_IRELATIVE 1032
+/* Dynamic array tags */
+#define DT_AARCH64_BTI_PLT 0x70000001
+#define DT_AARCH64_PAC_PLT 0x70000003
+#define DT_AARCH64_VARIANT_PCS 0x70000005
+
#endif /* _AARCH64_ELF_MACHDEP_H_ */
diff --git a/libc/include/malloc.h b/libc/include/malloc.h
index 833fa59..a237254 100644
--- a/libc/include/malloc.h
+++ b/libc/include/malloc.h
@@ -170,6 +170,16 @@
* Available since API level 28.
*/
#define M_PURGE (-101)
+/*
+ * mallopt() option for per-thread memory initialization tuning.
+ * The value argument should be one of:
+ * 1: Disable automatic heap initialization and, where possible, memory tagging,
+ * on this thread.
+ * 0: Normal behavior.
+ *
+ * Available since API level 31.
+ */
+#define M_THREAD_DISABLE_MEM_INIT (-103)
/**
* mallopt() option to set the maximum number of items in the secondary
* cache of the scudo allocator.
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index a224eab..a17a33f 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1476,8 +1476,8 @@
# Used by libandroid_net
android_getaddrinfofornet; # apex
- # Used by libandroid_runtime, libmedia and libmediautils
- android_mallopt; # apex
+ # Used by libandroid_runtime, libcutils, libmedia, and libmediautils
+ android_mallopt; # apex llndk
} LIBC_P;
LIBC_R { # introduced=R
@@ -1718,6 +1718,7 @@
android_gethostbyaddrfornetcontext;
android_gethostbynamefornet;
android_gethostbynamefornetcontext;
+ android_run_on_all_threads;
android_unsafe_frame_pointer_chase;
arc4random_addrandom; # arm x86
arc4random_stir; # arm x86
diff --git a/libc/malloc_debug/MapData.cpp b/libc/malloc_debug/MapData.cpp
index e8fbc54..ded81a2 100644
--- a/libc/malloc_debug/MapData.cpp
+++ b/libc/malloc_debug/MapData.cpp
@@ -116,14 +116,17 @@
if (!get_val<ElfW(Word)>(entry, addr + offsetof(ElfW(Phdr), p_type), &phdr.p_type)) {
return;
}
+ if (!get_val<ElfW(Word)>(entry, addr + offsetof(ElfW(Phdr), p_flags), &phdr.p_flags)) {
+ return;
+ }
if (!get_val<ElfW(Off)>(entry, addr + offsetof(ElfW(Phdr), p_offset), &phdr.p_offset)) {
return;
}
- if (phdr.p_type == PT_LOAD && phdr.p_offset == entry->offset) {
+ if ((phdr.p_type == PT_LOAD) && (phdr.p_flags & PF_X) ) {
if (!get_val<ElfW(Addr)>(entry, addr + offsetof(ElfW(Phdr), p_vaddr), &phdr.p_vaddr)) {
return;
}
- entry->load_bias = phdr.p_vaddr;
+ entry->load_bias = phdr.p_vaddr - phdr.p_offset;
return;
}
addr += sizeof(phdr);
diff --git a/libc/malloc_hooks/Android.bp b/libc/malloc_hooks/Android.bp
index 77b523e..487f3fb 100644
--- a/libc/malloc_hooks/Android.bp
+++ b/libc/malloc_hooks/Android.bp
@@ -70,6 +70,7 @@
cflags: [
"-Wall",
"-Werror",
+ "-O1", // FIXME: http://b/169206016 - issues with aligned_alloc and -O2
],
test_suites: ["general-tests"],
}
diff --git a/libc/platform/bionic/malloc.h b/libc/platform/bionic/malloc.h
index f9eb03f..16ef3a0 100644
--- a/libc/platform/bionic/malloc.h
+++ b/libc/platform/bionic/malloc.h
@@ -105,6 +105,13 @@
// 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 {
diff --git a/libc/platform/bionic/reserved_signals.h b/libc/platform/bionic/reserved_signals.h
index e8e517e..dab58af 100644
--- a/libc/platform/bionic/reserved_signals.h
+++ b/libc/platform/bionic/reserved_signals.h
@@ -43,9 +43,7 @@
// 37 (__SIGRTMIN + 5) coverage (libprofile-extras)
// 38 (__SIGRTMIN + 6) heapprofd ART managed heap dumps
// 39 (__SIGRTMIN + 7) fdtrack
-//
-// If you change this, also change __ndk_legacy___libc_current_sigrtmin
-// in <android/legacy_signal_inlines.h> to match.
+// 40 (__SIGRTMIN + 8) android_run_on_all_threads (bionic/pthread_internal.cpp)
#define BIONIC_SIGNAL_POSIX_TIMERS (__SIGRTMIN + 0)
#define BIONIC_SIGNAL_BACKTRACE (__SIGRTMIN + 1)
@@ -53,8 +51,9 @@
#define BIONIC_SIGNAL_PROFILER (__SIGRTMIN + 4)
#define BIONIC_SIGNAL_ART_PROFILER (__SIGRTMIN + 6)
#define BIONIC_SIGNAL_FDTRACK (__SIGRTMIN + 7)
+#define BIONIC_SIGNAL_RUN_ON_ALL_THREADS (__SIGRTMIN + 8)
-#define __SIGRT_RESERVED 8
+#define __SIGRT_RESERVED 9
static inline __always_inline sigset64_t filter_reserved_signals(sigset64_t sigset, int how) {
int (*block)(sigset64_t*, int);
int (*unblock)(sigset64_t*, int);
@@ -83,5 +82,6 @@
unblock(&sigset, __SIGRTMIN + 5);
unblock(&sigset, __SIGRTMIN + 6);
unblock(&sigset, __SIGRTMIN + 7);
+ unblock(&sigset, __SIGRTMIN + 8);
return sigset;
}
diff --git a/libc/private/bionic_asm.h b/libc/private/bionic_asm.h
index 6409563..6d4f7d5 100644
--- a/libc/private/bionic_asm.h
+++ b/libc/private/bionic_asm.h
@@ -35,6 +35,7 @@
#define __bionic_asm_custom_entry(f)
#define __bionic_asm_custom_end(f)
#define __bionic_asm_function_type @function
+#define __bionic_asm_custom_note_gnu_section()
#if defined(__aarch64__)
#include <private/bionic_asm_arm64.h>
@@ -83,4 +84,7 @@
.globl alias; \
.equ alias, original
+#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 463ca31..c11732a 100644
--- a/libc/private/bionic_asm_arm64.h
+++ b/libc/private/bionic_asm_arm64.h
@@ -41,3 +41,32 @@
#undef __bionic_asm_function_type
#define __bionic_asm_function_type %function
+
+#if defined(__ARM_FEATURE_BTI_DEFAULT)
+#define __bionic_asm_aarch64_feature_bti (1 << 0)
+#undef __bionic_asm_custom_entry
+#define __bionic_asm_custom_entry(f) hint #34 // BTI C
+#else
+#define __bionic_asm_aarch64_feature_bti 0
+#endif
+
+#if defined(__ARM_FEATURE_PAC_DEFAULT)
+#define __bionic_asm_aarch64_feature_pac (1 << 1)
+#else
+#define __bionic_asm_aarch64_feature_pac 0
+#endif
+
+#undef __bionic_asm_custom_note_gnu_section
+#define __bionic_asm_custom_note_gnu_section() \
+ .pushsection .note.gnu.property, "a"; \
+ .balign 8; \
+ .long 4; \
+ .long 0x10; \
+ .long 0x5; /* NT_GNU_PROPERTY_TYPE_0 */ \
+ .asciz "GNU"; \
+ .long 0xc0000000; /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */ \
+ .long 4; \
+ .long (__bionic_asm_aarch64_feature_pac | \
+ __bionic_asm_aarch64_feature_bti); \
+ .long 0; \
+ .popsection; \
diff --git a/libc/private/bionic_asm_dwarf_exprs.h b/libc/private/bionic_asm_dwarf_exprs.h
new file mode 100644
index 0000000..f988c6e
--- /dev/null
+++ b/libc/private/bionic_asm_dwarf_exprs.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+// Define assembler macros for generating DWARF CFI instructions that use DWARF expressions.
+// Assemblers don't natively support DWARF expressions, so use the C preprocessor and assembler
+// macros to lower them to .cfi_escape directives.
+//
+// Signal trampolines need to use DWARF expressions to record the locations of saved registers,
+// because the offsets from the restored SP to the saved registers is variable. e.g. A signal frame
+// can have optional FP/SIMD extensions, and there may be extra padding if the interrupted SP wasn't
+// aligned.
+
+// DWARF constants.
+#define DW_CFA_def_cfa_expression 0x0f
+#define DW_CFA_expression 0x10
+#define DW_OP_breg0 0x70
+#define DW_OP_deref 0x06
+
+// Return the size of a small uleb128 value: either 1 or 2 bytes
+#define ULEB128_14BIT_SIZE(val) \
+ (1 + (((val) > 0x7f) & 1))
+
+// Return the size of a small sleb128 value: either 1 or 2 bytes
+#define SLEB128_14BIT_SIZE(val) \
+ (1 + (((val) < -0x40) & 1) + \
+ (((val) > 0x3f) & 1) )
+
+// Output a 1 or 2-byte CFI uleb128 absolute value.
+.macro m_cfi_uleb128 val
+ .if (\val) < 0 || (\val) > 0x3fff
+ .error "m_cfi_uleb128 value is out of range (\val)"
+ .elseif (\val) > 0x7f
+ .cfi_escape ((\val) & 0x7f) | 0x80
+ .cfi_escape (\val) >> 7
+ .else
+ .cfi_escape (\val)
+ .endif
+.endm
+
+// Output a 1 or 2-byte CFI sleb128 absolute value.
+.macro m_cfi_sleb128 val
+ .if (\val) < -0x2000 || (\val) > 0x1fff
+ .error "m_cfi_sleb128 value is out of range (\val)"
+ .elseif (\val) < -0x40 || (\val) > 0x3f
+ .cfi_escape ((\val) & 0x7f) | 0x80
+ .cfi_escape ((\val) >> 7) & 0x7f
+ .else
+ .cfi_escape (\val) & 0x7f
+ .endif
+.endm
+
+.macro check_base_reg reg_no
+ .if (\reg_no) < 0 || (\reg_no) > 31
+ .error "base register is out of range for DW_OP_breg0..DW_OP_breg31 (\reg_no)"
+ .endif
+.endm
+
+// Set CFA to the expression, *(base_reg + offset)
+.macro m_cfi_def_cfa_deref base_reg, offset
+ check_base_reg (\base_reg)
+ .cfi_escape DW_CFA_def_cfa_expression
+ m_cfi_uleb128 (1 + SLEB128_14BIT_SIZE(\offset) + 1) // size of DWARF expression in bytes
+ .cfi_escape DW_OP_breg0 + (\base_reg) // expr: 1 byte
+ m_cfi_sleb128 (\offset) // expr: 1 or 2 bytes
+ .cfi_escape DW_OP_deref // expr: 1 byte
+.endm
+
+// Set the address of the register's previous value to the expression, (base_reg + offset)
+.macro m_cfi_breg_offset dest_reg, base_reg, offset
+ check_base_reg (\base_reg)
+ .cfi_escape DW_CFA_expression
+ m_cfi_uleb128 (\dest_reg)
+ m_cfi_uleb128 (1 + SLEB128_14BIT_SIZE(\offset)) // size of DWARF expression in bytes
+ .cfi_escape DW_OP_breg0 + (\base_reg) // expr: 1 byte
+ m_cfi_sleb128 (\offset) // expr: 1 or 2 bytes
+.endm
diff --git a/libc/private/bionic_defs.h b/libc/private/bionic_defs.h
index 1d4f86b..5a48f25 100644
--- a/libc/private/bionic_defs.h
+++ b/libc/private/bionic_defs.h
@@ -33,7 +33,15 @@
* This label is used to mark libc/libdl symbols that may need to be replaced
* by native bridge implementation.
*/
+#ifdef __ANDROID_NATIVE_BRIDGE__
#define __BIONIC_WEAK_FOR_NATIVE_BRIDGE __attribute__((__weak__, __noinline__))
#define __BIONIC_WEAK_VARIABLE_FOR_NATIVE_BRIDGE __attribute__((__weak__))
+#define __BIONIC_WEAK_FOR_NATIVE_BRIDGE_INLINE \
+ __BIONIC_WEAK_FOR_NATIVE_BRIDGE extern "C" __LIBC_HIDDEN__
+#else
+#define __BIONIC_WEAK_FOR_NATIVE_BRIDGE
+#define __BIONIC_WEAK_VARIABLE_FOR_NATIVE_BRIDGE
+#define __BIONIC_WEAK_FOR_NATIVE_BRIDGE_INLINE static inline
+#endif
#endif /* __BIONIC_PRIVATE_BIONIC_DEFS_H_ */
diff --git a/libc/tools/gensyscalls.py b/libc/tools/gensyscalls.py
index 0271a04..0e0e25f 100755
--- a/libc/tools/gensyscalls.py
+++ b/libc/tools/gensyscalls.py
@@ -459,6 +459,8 @@
if syscall.has_key("asm-%s" % arch):
print(syscall["asm-%s" % arch])
+ if arch == 'arm64':
+ print('\nNOTE_GNU_PROPERTY()\n')
if __name__ == "__main__":
if len(sys.argv) < 2:
diff --git a/libdl/Android.bp b/libdl/Android.bp
index 6a3a82e..1a5439f 100644
--- a/libdl/Android.bp
+++ b/libdl/Android.bp
@@ -116,7 +116,7 @@
symbol_file: "libdl.map.txt",
versions: [
"29",
- "10000",
+ "current",
],
},
@@ -124,6 +124,10 @@
"//apex_available:platform",
"com.android.runtime",
],
+
+ lto: {
+ never: true,
+ },
}
cc_library {
@@ -193,13 +197,17 @@
stubs: {
symbol_file: "libdl_android.map.txt",
- versions: ["10000"],
+ versions: ["current"],
},
apex_available: [
"//apex_available:platform",
"com.android.runtime",
],
+
+ lto: {
+ never: true,
+ },
}
ndk_library {
diff --git a/libm/Android.bp b/libm/Android.bp
index 6a348e1..7f96975 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -498,7 +498,7 @@
symbol_file: "libm.map.txt",
versions: [
"29",
- "10000",
+ "current",
],
},
@@ -506,6 +506,10 @@
"//apex_available:platform",
"com.android.runtime",
],
+
+ lto: {
+ never: true,
+ },
}
ndk_library {
diff --git a/libm/arm64/lrint.S b/libm/arm64/lrint.S
index 5f95ae8..e835d08 100644
--- a/libm/arm64/lrint.S
+++ b/libm/arm64/lrint.S
@@ -32,3 +32,5 @@
ALIAS_SYMBOL(llrint, lrint);
ALIAS_SYMBOL(llrintf, lrintf);
+
+NOTE_GNU_PROPERTY()
diff --git a/libm/arm64/sqrt.S b/libm/arm64/sqrt.S
index 3a58ef3..0659b13 100644
--- a/libm/arm64/sqrt.S
+++ b/libm/arm64/sqrt.S
@@ -25,3 +25,5 @@
fsqrt s0, s0
ret
END(sqrtf)
+
+NOTE_GNU_PROPERTY()
diff --git a/linker/Android.bp b/linker/Android.bp
index 08b2c7b..15585a7 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -39,6 +39,9 @@
"linker_wrapper.cpp",
],
arch: {
+ arm64: {
+ srcs: ["arch/arm64/begin.S"],
+ },
x86_64: {
srcs: ["arch/x86_64/begin.S"],
},
@@ -166,6 +169,7 @@
"linker_namespaces.cpp",
"linker_logger.cpp",
"linker_mapped_file_fragment.cpp",
+ "linker_note_gnu_property.cpp",
"linker_phdr.cpp",
"linker_relocate.cpp",
"linker_sdk_versions.cpp",
@@ -353,6 +357,10 @@
],
}
},
+
+ lto: {
+ never: true,
+ },
}
// ========================================================
@@ -423,6 +431,10 @@
"//apex_available:platform",
"com.android.runtime",
],
+
+ lto: {
+ never: true,
+ },
}
cc_test {
@@ -444,6 +456,7 @@
"linker_block_allocator_test.cpp",
"linker_config_test.cpp",
"linked_list_test.cpp",
+ "linker_note_gnu_property_test.cpp",
"linker_sleb128_test.cpp",
"linker_utils_test.cpp",
"linker_gnu_hash_test.cpp",
@@ -452,6 +465,7 @@
"linker_block_allocator.cpp",
"linker_config.cpp",
"linker_debug.cpp",
+ "linker_note_gnu_property.cpp",
"linker_test_globals.cpp",
"linker_utils.cpp",
],
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 302e4b3..77f754c 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -3141,6 +3141,14 @@
// resolves everything eagerly, so these can be ignored.
break;
+#if defined(__aarch64__)
+ case DT_AARCH64_BTI_PLT:
+ case DT_AARCH64_PAC_PLT:
+ case DT_AARCH64_VARIANT_PCS:
+ // Ignored: AArch64 processor-specific dynamic array tags.
+ break;
+#endif
+
default:
if (!relocating_linker) {
const char* tag_name;
diff --git a/linker/linker.h b/linker/linker.h
index 3e851da..e1775fb 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -181,3 +181,9 @@
int get_application_target_sdk_version();
ElfW(Versym) find_verdef_version_index(const soinfo* si, const version_info* vi);
bool validate_verdef_section(const soinfo* si);
+
+struct platform_properties {
+#if defined(__aarch64__)
+ bool bti_supported = false;
+#endif
+};
diff --git a/linker/linker_globals.cpp b/linker/linker_globals.cpp
index 31da02c..4a17d09 100644
--- a/linker/linker_globals.cpp
+++ b/linker/linker_globals.cpp
@@ -40,6 +40,8 @@
std::unordered_map<uintptr_t, soinfo*> g_soinfo_handles_map;
+platform_properties g_platform_properties;
+
static char __linker_dl_err_buf[768];
char* linker_get_error_buffer() {
diff --git a/linker/linker_globals.h b/linker/linker_globals.h
index 83cedca..0998629 100644
--- a/linker/linker_globals.h
+++ b/linker/linker_globals.h
@@ -79,11 +79,14 @@
struct soinfo;
struct android_namespace_t;
+struct platform_properties;
extern android_namespace_t g_default_namespace;
extern std::unordered_map<uintptr_t, soinfo*> g_soinfo_handles_map;
+extern platform_properties g_platform_properties;
+
// Error buffer "variable"
char* linker_get_error_buffer();
size_t linker_get_error_buffer_size();
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index 41bb4ba..aad8f6f 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -297,6 +297,13 @@
return result;
}
+static void platform_properties_init() {
+#if defined(__aarch64__)
+ const unsigned long hwcap2 = getauxval(AT_HWCAP2);
+ g_platform_properties.bti_supported = (hwcap2 & HWCAP2_BTI) != 0;
+#endif
+}
+
static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load) {
ProtectedDataGuard guard;
@@ -311,6 +318,9 @@
// Initialize system properties
__system_properties_init(); // may use 'environ'
+ // Initialize platform properties.
+ platform_properties_init();
+
// Register the debuggerd signal handler.
linker_debuggerd_init();
@@ -381,6 +391,20 @@
solinker->set_realpath(interp);
init_link_map_head(*solinker);
+#if defined(__aarch64__)
+ if (exe_to_load == nullptr) {
+ // Kernel does not add PROT_BTI to executable pages of the loaded ELF.
+ // Apply appropriate protections here if it is needed.
+ auto note_gnu_property = GnuPropertySection(somain);
+ if (note_gnu_property.IsBTICompatible() &&
+ (phdr_table_protect_segments(somain->phdr, somain->phnum, somain->load_bias,
+ ¬e_gnu_property) < 0)) {
+ __linker_error("error: can't protect segments for \"%s\": %s", exe_info.path.c_str(),
+ strerror(errno));
+ }
+ }
+#endif
+
// Register the main executable and the linker upfront to have
// gdb aware of them before loading the rest of the dependency
// tree.
diff --git a/linker/linker_note_gnu_property.cpp b/linker/linker_note_gnu_property.cpp
new file mode 100644
index 0000000..be1aebc
--- /dev/null
+++ b/linker/linker_note_gnu_property.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "linker_note_gnu_property.h"
+
+#include <elf.h>
+#include <link.h>
+
+#include "linker.h"
+#include "linker_debug.h"
+#include "linker_globals.h"
+#include "linker_soinfo.h"
+
+GnuPropertySection::GnuPropertySection(const soinfo* si)
+ : GnuPropertySection(si->phdr, si->phnum, si->load_bias, si->get_realpath()) {}
+
+GnuPropertySection::GnuPropertySection(const ElfW(Phdr)* phdr, size_t phdr_count,
+ const ElfW(Addr) load_bias, const char* name) {
+ // Try to find PT_GNU_PROPERTY segment.
+ auto note_gnu_property = FindSegment(phdr, phdr_count, load_bias, name);
+ // Perform some validity checks.
+ if (note_gnu_property && SanityCheck(note_gnu_property, name)) {
+ // Parse section.
+ Parse(note_gnu_property, name);
+ }
+}
+
+const ElfW(NhdrGNUProperty)* GnuPropertySection::FindSegment(const ElfW(Phdr)* phdr,
+ size_t phdr_count,
+ const ElfW(Addr) load_bias,
+ const char* name) const {
+ // According to Linux gABI extension this segment should contain
+ // .note.gnu.property section only.
+ if (phdr != nullptr) {
+ for (size_t i = 0; i < phdr_count; ++i) {
+ if (phdr[i].p_type != PT_GNU_PROPERTY) {
+ continue;
+ }
+
+ TRACE("\"%s\" PT_GNU_PROPERTY: found at segment index %zu", name, i);
+
+ // Check segment size.
+ if (phdr[i].p_memsz < sizeof(ElfW(NhdrGNUProperty))) {
+ DL_ERR_AND_LOG(
+ "\"%s\" PT_GNU_PROPERTY segment is too small. Segment "
+ "size is %zu, minimum is %zu.",
+ name, static_cast<size_t>(phdr[i].p_memsz), sizeof(ElfW(NhdrGNUProperty)));
+ return nullptr;
+ }
+
+ // PT_GNU_PROPERTY contains .note.gnu.property which has SHF_ALLOC
+ // attribute, therefore it is loaded.
+ auto note_nhdr = reinterpret_cast<ElfW(NhdrGNUProperty)*>(load_bias + phdr[i].p_vaddr);
+
+ // Check that the n_descsz <= p_memsz
+ if ((phdr[i].p_memsz - sizeof(ElfW(NhdrGNUProperty))) < note_nhdr->nhdr.n_descsz) {
+ DL_ERR_AND_LOG(
+ "\"%s\" PT_GNU_PROPERTY segment p_memsz (%zu) is too small for note n_descsz (%zu).",
+ name, static_cast<size_t>(phdr[i].p_memsz),
+ static_cast<size_t>(note_nhdr->nhdr.n_descsz));
+ return nullptr;
+ }
+
+ return note_nhdr;
+ }
+ }
+
+ TRACE("\"%s\" PT_GNU_PROPERTY: not found", name);
+ return nullptr;
+}
+
+bool GnuPropertySection::SanityCheck(const ElfW(NhdrGNUProperty)* note_nhdr,
+ const char* name) const {
+ // Check .note section type
+ if (note_nhdr->nhdr.n_type != NT_GNU_PROPERTY_TYPE_0) {
+ DL_ERR_AND_LOG("\"%s\" .note.gnu.property: unexpected note type. Expected %u, got %u.", name,
+ NT_GNU_PROPERTY_TYPE_0, note_nhdr->nhdr.n_type);
+ return false;
+ }
+
+ if (note_nhdr->nhdr.n_namesz != 4) {
+ DL_ERR_AND_LOG("\"%s\" .note.gnu.property: unexpected name size. Expected 4, got %u.", name,
+ note_nhdr->nhdr.n_namesz);
+ return false;
+ }
+
+ if (strncmp(note_nhdr->n_name, "GNU", 4) != 0) {
+ DL_ERR_AND_LOG("\"%s\" .note.gnu.property: unexpected name. Expected 'GNU', got '%s'.", name,
+ note_nhdr->n_name);
+ return false;
+ }
+
+ return true;
+}
+
+bool GnuPropertySection::Parse(const ElfW(NhdrGNUProperty)* note_nhdr, const char* name) {
+ // The total length of the program property array is in _bytes_.
+ ElfW(Word) offset = 0;
+ while (offset < note_nhdr->nhdr.n_descsz) {
+ DEBUG("\"%s\" .note.gnu.property: processing at offset 0x%x", name, offset);
+
+ // At least the "header" part must fit.
+ // The ABI doesn't say that pr_datasz can't be 0.
+ if ((note_nhdr->nhdr.n_descsz - offset) < sizeof(ElfW(Prop))) {
+ DL_ERR_AND_LOG(
+ "\"%s\" .note.gnu.property: no more space left for a "
+ "Program Property Note header.",
+ name);
+ return false;
+ }
+
+ // Loop on program property array.
+ const ElfW(Prop)* property = reinterpret_cast<const ElfW(Prop)*>(¬e_nhdr->n_desc[offset]);
+ const ElfW(Word) property_size =
+ align_up(sizeof(ElfW(Prop)) + property->pr_datasz, sizeof(ElfW(Addr)));
+ if ((note_nhdr->nhdr.n_descsz - offset) < property_size) {
+ DL_ERR_AND_LOG(
+ "\"%s\" .note.gnu.property: property descriptor size is "
+ "invalid. Expected at least %u bytes, got %u.",
+ name, property_size, note_nhdr->nhdr.n_descsz - offset);
+ return false;
+ }
+
+ // Cache found properties.
+ switch (property->pr_type) {
+#if defined(__aarch64__)
+ case GNU_PROPERTY_AARCH64_FEATURE_1_AND: {
+ if (property->pr_datasz != 4) {
+ DL_ERR_AND_LOG(
+ "\"%s\" .note.gnu.property: property descriptor size is "
+ "invalid. Expected %u bytes for GNU_PROPERTY_AARCH64_FEATURE_1_AND, got %u.",
+ name, 4, property->pr_datasz);
+ return false;
+ }
+
+ const ElfW(Word) flags = *reinterpret_cast<const ElfW(Word)*>(&property->pr_data[0]);
+ properties_.bti_compatible = (flags & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) != 0;
+ if (properties_.bti_compatible) {
+ INFO("[ BTI compatible: \"%s\" ]", name);
+ }
+ break;
+ }
+#endif
+ default:
+ DEBUG("\"%s\" .note.gnu.property: found property pr_type %u pr_datasz 0x%x", name,
+ property->pr_type, property->pr_datasz);
+ break;
+ }
+
+ // Move offset, this should be safe to add because of previous checks.
+ offset += property_size;
+ }
+
+ return true;
+}
+
+#if defined(__aarch64__)
+bool GnuPropertySection::IsBTICompatible() const {
+ return (g_platform_properties.bti_supported && properties_.bti_compatible);
+}
+#endif
diff --git a/linker/linker_note_gnu_property.h b/linker/linker_note_gnu_property.h
new file mode 100644
index 0000000..b8b4ef7
--- /dev/null
+++ b/linker/linker_note_gnu_property.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <elf.h>
+#include <link.h>
+
+#include "linker_soinfo.h"
+
+// The Elf* structures below are derived from the document
+// Linux Extensions to gABI (https://github.com/hjl-tools/linux-abi/wiki).
+// Essentially, these types would be defined in <elf.h>, but this is not
+// the case at the moment.
+
+struct Elf32_Prop {
+ Elf32_Word pr_type;
+ Elf32_Word pr_datasz;
+ char pr_data[0];
+};
+
+// On 32-bit machines this should be 4-byte aligned.
+struct Elf32_NhdrGNUProperty {
+ Elf32_Nhdr nhdr;
+ char n_name[4];
+ char n_desc[0];
+};
+
+struct Elf64_Prop {
+ Elf64_Word pr_type;
+ Elf64_Word pr_datasz;
+ char pr_data[0];
+};
+
+// On 64-bit machines this should be 8-byte aligned.
+struct Elf64_NhdrGNUProperty {
+ Elf64_Nhdr nhdr;
+ char n_name[4];
+ char n_desc[0];
+};
+
+struct ElfProgramProperty {
+#if defined(__aarch64__)
+ bool bti_compatible = false;
+#endif
+};
+
+// Representation of the .note.gnu.property section found in the segment
+// with p_type = PT_GNU_PROPERTY.
+class GnuPropertySection {
+ public:
+ GnuPropertySection(){};
+ explicit GnuPropertySection(const soinfo* si);
+ GnuPropertySection(const ElfW(Phdr)* phdr, size_t phdr_count, const ElfW(Addr) load_bias,
+ const char* name);
+
+#if defined(__aarch64__)
+ bool IsBTICompatible() const;
+#endif
+
+ private:
+ const ElfW(NhdrGNUProperty)* FindSegment(const ElfW(Phdr)* phdr, size_t phdr_count,
+ const ElfW(Addr) load_bias, const char* name) const;
+ bool SanityCheck(const ElfW(NhdrGNUProperty)* note_nhdr, const char* name) const;
+ bool Parse(const ElfW(NhdrGNUProperty)* note_nhdr, const char* name);
+
+ ElfProgramProperty properties_ __unused;
+};
diff --git a/linker/linker_note_gnu_property_test.cpp b/linker/linker_note_gnu_property_test.cpp
new file mode 100644
index 0000000..41fc47b
--- /dev/null
+++ b/linker/linker_note_gnu_property_test.cpp
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include "linker.h"
+#include "linker_globals.h"
+#include "linker_note_gnu_property.h"
+#include "platform/bionic/macros.h"
+
+#define SONAME "test_so"
+
+static char error_buffer[1024];
+
+char* linker_get_error_buffer() {
+ return error_buffer;
+}
+
+size_t linker_get_error_buffer_size() {
+ return std::size(error_buffer);
+}
+
+static void reset_error_buffer() {
+ error_buffer[0] = '\0';
+}
+
+platform_properties g_platform_properties {
+#if defined(__aarch64__)
+ // Assume "hardware" supports Armv8.5-A BTI.
+ .bti_supported = true
+#endif
+};
+
+// Helper macro to make the test cleaner.
+#define PHDR_WITH_NOTE_GNU_PROPERTY(__prop) \
+ reset_error_buffer(); \
+ ElfW(Phdr) phdrs[] = { \
+ {.p_type = PT_LOAD}, \
+ { \
+ .p_type = PT_GNU_PROPERTY, \
+ .p_vaddr = reinterpret_cast<ElfW(Addr)>(__prop), \
+ .p_memsz = sizeof(ElfW(NhdrGNUProperty)) + (__prop)->nhdr.n_descsz, \
+ }, \
+ {.p_type = PT_NULL}, \
+ }; \
+ auto note = GnuPropertySection(&phdrs[0], std::size(phdrs), 0, SONAME)
+
+// Helper to check for no error message.
+#define ASSERT_NO_ERROR_MSG() ASSERT_STREQ(error_buffer, "")
+
+// Helper to check expected error message.
+#define ASSERT_ERROR_MSG_EQ(__expected) ASSERT_STREQ(error_buffer, "\"" SONAME "\" " __expected)
+
+static void test_bti_not_supported(GnuPropertySection& note __unused) {
+#if defined(__aarch64__)
+ ASSERT_FALSE(note.IsBTICompatible());
+#endif
+}
+
+#if defined(__aarch64__)
+static void test_bti_supported(GnuPropertySection& note __unused) {
+ ASSERT_TRUE(note.IsBTICompatible());
+}
+#endif
+
+// Helper class to build a well-formed .note.gnu.property section.
+class GnuPropertySectionBuilder {
+ public:
+ GnuPropertySectionBuilder() {
+ note = reinterpret_cast<ElfW(NhdrGNUProperty)*>(§ion[0]);
+ note->nhdr.n_namesz = 4;
+ note->nhdr.n_descsz = 0;
+ note->nhdr.n_type = NT_GNU_PROPERTY_TYPE_0;
+ memcpy(note->n_name, "GNU", 4);
+ }
+
+ template <typename T>
+ bool push(ElfW(Word) pr_type, ElfW(Word) pr_datasz, const T* pr_data) {
+ // Must be aligned.
+ const uintptr_t addition = align_up(pr_datasz, sizeof(ElfW(Addr)));
+ if ((offset() + addition) > kMaxSectionSize) {
+ return false;
+ }
+ ++entries;
+ ElfW(Prop)* prop = reinterpret_cast<ElfW(Prop)*>(§ion[offset()]);
+ // Header
+ prop->pr_type = pr_type;
+ prop->pr_datasz = pr_datasz;
+ step(2 * sizeof(ElfW(Word)));
+ // Data
+ memcpy(§ion[offset()], reinterpret_cast<const void*>(pr_data), pr_datasz);
+ step(pr_datasz);
+ // Padding
+ memset(§ion[offset()], 0xAA, addition - pr_datasz);
+ step(addition - pr_datasz);
+ return true;
+ }
+
+ ElfW(NhdrGNUProperty)* data() const { return note; }
+
+ void dump() const {
+ std::cout << ".note.gnu.property\n";
+ dump_member("n_namesz", note->nhdr.n_namesz);
+ dump_member("n_descsz", note->nhdr.n_descsz);
+ dump_member("n_type ", note->nhdr.n_type);
+ dump_member("n_name ", note->n_name);
+ dump_member("entries ", entries);
+ if (entries > 0) {
+ std::cout << " raw data:";
+ const uintptr_t offset = note->nhdr.n_descsz + 16;
+ for (uintptr_t offs = 16; offs < offset; ++offs) {
+ std::cout << std::hex;
+ if ((offs % 8) == 0) {
+ std::cout << "\n ";
+ }
+ auto value = static_cast<unsigned>(section[offs]);
+ std::cout << " ";
+ if (value < 0x10) {
+ std::cout << "0";
+ }
+ std::cout << static_cast<unsigned>(section[offs]);
+ }
+ std::cout << std::dec << "\n";
+ }
+ }
+
+ void corrupt_n_descsz(ElfW(Word) n_descsz) { note->nhdr.n_descsz = n_descsz; }
+
+ private:
+ template <typename T>
+ void dump_member(const char* name, T value) const {
+ std::cout << " " << name << " " << value << "\n";
+ }
+
+ ElfW(Word) offset() const { return note->nhdr.n_descsz + 16; }
+
+ template <typename T>
+ void step(T value) {
+ note->nhdr.n_descsz += static_cast<ElfW(Word)>(value);
+ }
+
+ static const size_t kMaxSectionSize = 1024;
+
+ alignas(8) uint8_t section[kMaxSectionSize];
+ ElfW(NhdrGNUProperty)* note;
+ size_t entries = 0;
+};
+
+// Tests that the default constructed instance does not report support
+// for Armv8.5-A BTI.
+TEST(note_gnu_property, default) {
+ GnuPropertySection note;
+ test_bti_not_supported(note);
+ ASSERT_NO_ERROR_MSG();
+}
+
+// Tests that an instance without valid phdr pointer does not report
+// support for Armv8.5-A BTI.
+TEST(note_gnu_property, phdr_null) {
+ auto note = GnuPropertySection(nullptr, 0, 0, SONAME);
+ test_bti_not_supported(note);
+ ASSERT_NO_ERROR_MSG();
+}
+
+// Tests that an instance without finding PT_GNU_PROPERTY does not
+// report support for Armv8.5-A BTI.
+TEST(note_gnu_property, no_pt_gnu_property) {
+ ElfW(Phdr) phdrs[] = {
+ {.p_type = PT_LOAD},
+ {.p_type = PT_NULL},
+ };
+
+ reset_error_buffer();
+ auto note = GnuPropertySection(&phdrs[0], std::size(phdrs), 0, SONAME);
+ test_bti_not_supported(note);
+ ASSERT_NO_ERROR_MSG();
+}
+
+// Tests the validity check for invalid PT_GNU_PROPERTY size.
+TEST(note_gnu_property, pt_gnu_property_bad_size) {
+ ElfW(Phdr) phdrs[] = {
+ {.p_type = PT_LOAD},
+ {
+ .p_type = PT_GNU_PROPERTY,
+ .p_vaddr = 0,
+ .p_memsz = sizeof(ElfW(NhdrGNUProperty)) - 1, // Invalid
+ },
+ {.p_type = PT_NULL},
+ };
+
+ reset_error_buffer();
+ auto note = GnuPropertySection(&phdrs[0], std::size(phdrs), 0, SONAME);
+ test_bti_not_supported(note);
+ ASSERT_ERROR_MSG_EQ("PT_GNU_PROPERTY segment is too small. Segment size is 15, minimum is 16.");
+}
+
+// Tests that advertised n_descsz should still fit into p_memsz.
+TEST(note_gnu_property, pt_gnu_property_too_small) {
+ ElfW(NhdrGNUProperty) prop = {
+ .nhdr = {.n_namesz = PT_GNU_PROPERTY, .n_descsz = 1, .n_type = NT_GNU_PROPERTY_TYPE_0},
+ .n_name = "GNU",
+ };
+ ElfW(Phdr) phdrs[] = {
+ {
+ .p_type = PT_GNU_PROPERTY,
+ .p_vaddr = reinterpret_cast<ElfW(Addr)>(&prop),
+ .p_memsz = sizeof(ElfW(NhdrGNUProperty)), // Off by one
+ },
+ };
+
+ reset_error_buffer();
+ auto note = GnuPropertySection(&phdrs[0], std::size(phdrs), 0, SONAME);
+ test_bti_not_supported(note);
+ ASSERT_ERROR_MSG_EQ("PT_GNU_PROPERTY segment p_memsz (16) is too small for note n_descsz (1).");
+}
+
+// Tests the validity check for invalid .note.gnu.property type.
+TEST(note_gnu_property, pt_gnu_property_bad_type) {
+ ElfW(NhdrGNUProperty) prop = {
+ .nhdr =
+ {
+ .n_namesz = 4,
+ .n_descsz = 0,
+ .n_type = NT_GNU_PROPERTY_TYPE_0 - 1 // Invalid
+ },
+ .n_name = "GNU",
+ };
+ PHDR_WITH_NOTE_GNU_PROPERTY(&prop);
+ test_bti_not_supported(note);
+ ASSERT_ERROR_MSG_EQ(".note.gnu.property: unexpected note type. Expected 5, got 4.");
+}
+
+// Tests the validity check for invalid .note.gnu.property name size.
+TEST(note_gnu_property, pt_gnu_property_bad_namesz) {
+ ElfW(NhdrGNUProperty) prop = {
+ .nhdr = {.n_namesz = 3, // Invalid
+ .n_descsz = 0,
+ .n_type = NT_GNU_PROPERTY_TYPE_0},
+ .n_name = "GNU",
+ };
+ PHDR_WITH_NOTE_GNU_PROPERTY(&prop);
+ test_bti_not_supported(note);
+ ASSERT_ERROR_MSG_EQ(".note.gnu.property: unexpected name size. Expected 4, got 3.");
+}
+
+// Tests the validity check for invalid .note.gnu.property name.
+TEST(note_gnu_property, pt_gnu_property_bad_name) {
+ ElfW(NhdrGNUProperty) prop = {
+ .nhdr = {.n_namesz = 4, .n_descsz = 0, .n_type = NT_GNU_PROPERTY_TYPE_0},
+ .n_name = "ABC", // Invalid
+ };
+ PHDR_WITH_NOTE_GNU_PROPERTY(&prop);
+ test_bti_not_supported(note);
+ ASSERT_ERROR_MSG_EQ(".note.gnu.property: unexpected name. Expected 'GNU', got 'ABC'.");
+}
+
+// Tests the validity check for not enough space for a Program Property header.
+TEST(note_gnu_property, pt_gnu_property_pphdr_no_space) {
+ ElfW(NhdrGNUProperty) prop = {
+ .nhdr = {.n_namesz = 4,
+ .n_descsz = 7, // Invalid
+ .n_type = NT_GNU_PROPERTY_TYPE_0},
+ .n_name = "GNU",
+ };
+ PHDR_WITH_NOTE_GNU_PROPERTY(&prop);
+ test_bti_not_supported(note);
+ ASSERT_ERROR_MSG_EQ(".note.gnu.property: no more space left for a Program Property Note header.");
+}
+
+// Tests an empty .note.gnu.property.
+TEST(note_gnu_property, pt_gnu_property_no_data) {
+ GnuPropertySectionBuilder prop;
+ PHDR_WITH_NOTE_GNU_PROPERTY(prop.data());
+ test_bti_not_supported(note);
+ ASSERT_NO_ERROR_MSG();
+}
+
+// Tests a .note.gnu.property section with elements with pr_datasz = 0.
+TEST(note_gnu_property, pt_gnu_property_no_prop) {
+ GnuPropertySectionBuilder prop;
+ ASSERT_TRUE(prop.push(1, 0, (void*)nullptr));
+ ASSERT_TRUE(prop.push(2, 0, (void*)nullptr));
+ ASSERT_TRUE(prop.push(3, 0, (void*)nullptr));
+ PHDR_WITH_NOTE_GNU_PROPERTY(prop.data());
+ test_bti_not_supported(note);
+ ASSERT_NO_ERROR_MSG();
+}
+
+// Tests that GNU_PROPERTY_AARCH64_FEATURE_1_AND must have pr_datasz = 4.
+TEST(note_gnu_property, pt_gnu_property_bad_pr_datasz) {
+#if defined(__aarch64__)
+ GnuPropertySectionBuilder prop;
+ ElfW(Word) pr_data[] = {GNU_PROPERTY_AARCH64_FEATURE_1_BTI, 0, 0};
+ ASSERT_TRUE(prop.push(GNU_PROPERTY_AARCH64_FEATURE_1_AND, 12, &pr_data));
+ PHDR_WITH_NOTE_GNU_PROPERTY(prop.data());
+ test_bti_not_supported(note);
+ ASSERT_ERROR_MSG_EQ(
+ ".note.gnu.property: property descriptor size is invalid. Expected 4 bytes for "
+ "GNU_PROPERTY_AARCH64_FEATURE_1_AND, got 12.");
+#else
+ GTEST_SKIP() << "BTI is not supported on this architecture.";
+#endif
+}
+
+// Tests a .note.gnu.property section with only GNU_PROPERTY_AARCH64_FEATURE_1_BTI property array.
+TEST(note_gnu_property, pt_gnu_property_ok_1) {
+#if defined(__aarch64__)
+ GnuPropertySectionBuilder prop;
+ ElfW(Word) pr_data[] = {GNU_PROPERTY_AARCH64_FEATURE_1_BTI};
+ ASSERT_TRUE(prop.push(GNU_PROPERTY_AARCH64_FEATURE_1_AND, sizeof(pr_data), &pr_data));
+ PHDR_WITH_NOTE_GNU_PROPERTY(prop.data());
+ ASSERT_NO_ERROR_MSG();
+ test_bti_supported(note);
+#else
+ GTEST_SKIP() << "BTI is not supported on this architecture.";
+#endif
+}
+
+// Tests a .note.gnu.property section with only GNU_PROPERTY_AARCH64_FEATURE_1_BTI property array.
+TEST(note_gnu_property, pt_gnu_property_ok_2) {
+#if defined(__aarch64__)
+ GnuPropertySectionBuilder prop;
+ ElfW(Word) pr_data[] = {static_cast<ElfW(Word)>(~GNU_PROPERTY_AARCH64_FEATURE_1_BTI)};
+ ASSERT_TRUE(prop.push(GNU_PROPERTY_AARCH64_FEATURE_1_AND, sizeof(pr_data), &pr_data));
+ PHDR_WITH_NOTE_GNU_PROPERTY(prop.data());
+ ASSERT_NO_ERROR_MSG();
+ test_bti_not_supported(note);
+#else
+ GTEST_SKIP() << "BTI is not supported on this architecture.";
+#endif
+}
+
+// Tests a .note.gnu.property section with more property arrays.
+TEST(note_gnu_property, pt_gnu_property_ok_3) {
+#if defined(__aarch64__)
+ GnuPropertySectionBuilder prop;
+
+ ElfW(Word) pr_data_0[8] = {0xCD};
+ ASSERT_TRUE(prop.push(1, 4, &pr_data_0));
+ ASSERT_TRUE(prop.push(2, 3, &pr_data_0));
+ ASSERT_TRUE(prop.push(3, 8, &pr_data_0));
+
+ ElfW(Word) pr_data[] = {GNU_PROPERTY_AARCH64_FEATURE_1_BTI};
+ ASSERT_TRUE(prop.push(GNU_PROPERTY_AARCH64_FEATURE_1_AND, sizeof(pr_data), &pr_data));
+
+ ASSERT_TRUE(prop.push(4, 1, &pr_data_0));
+
+ PHDR_WITH_NOTE_GNU_PROPERTY(prop.data());
+ ASSERT_NO_ERROR_MSG();
+ test_bti_supported(note);
+#else
+ GTEST_SKIP() << "BTI is not supported on this architecture.";
+#endif
+}
+
+// Tests a .note.gnu.property but with bad property descriptor size.
+TEST(note_gnu_property, pt_gnu_property_bad_n_descsz) {
+#if defined(__aarch64__)
+ GnuPropertySectionBuilder prop;
+ ElfW(Word) pr_data[] = {GNU_PROPERTY_AARCH64_FEATURE_1_BTI};
+ ASSERT_TRUE(prop.push(GNU_PROPERTY_AARCH64_FEATURE_1_AND, sizeof(pr_data), &pr_data));
+
+ ElfW(Word) n_descsz;
+ if (sizeof(ElfW(Addr)) == 4) {
+ n_descsz = 11;
+ } else {
+ n_descsz = 15;
+ }
+
+ prop.corrupt_n_descsz(n_descsz);
+
+ PHDR_WITH_NOTE_GNU_PROPERTY(prop.data());
+ if (sizeof(ElfW(Addr)) == 4) {
+ ASSERT_ERROR_MSG_EQ(
+ ".note.gnu.property: property descriptor size is invalid. Expected at least 12 bytes, got "
+ "11.");
+ } else {
+ ASSERT_ERROR_MSG_EQ(
+ ".note.gnu.property: property descriptor size is invalid. Expected at least 16 bytes, got "
+ "15.");
+ }
+ test_bti_not_supported(note);
+#else
+ GTEST_SKIP() << "BTI is not supported on this architecture.";
+#endif
+}
+
+// Tests if platform support is missing.
+TEST(note_gnu_property, no_platform_support) {
+#if defined(__aarch64__)
+ auto bti_supported_orig = g_platform_properties.bti_supported;
+ g_platform_properties.bti_supported = false;
+
+ GnuPropertySectionBuilder prop;
+ ElfW(Word) pr_data[] = {GNU_PROPERTY_AARCH64_FEATURE_1_BTI};
+ ASSERT_TRUE(prop.push(GNU_PROPERTY_AARCH64_FEATURE_1_AND, sizeof(pr_data), &pr_data));
+ PHDR_WITH_NOTE_GNU_PROPERTY(prop.data());
+ ASSERT_NO_ERROR_MSG();
+ test_bti_not_supported(note);
+
+ g_platform_properties.bti_supported = bti_supported_orig;
+#else
+ GTEST_SKIP() << "BTI is not supported on this architecture.";
+#endif
+}
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 1e89094..9b1b99f 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -169,8 +169,16 @@
if (did_load_) {
return true;
}
- if (ReserveAddressSpace(address_space) && LoadSegments() && FindPhdr()) {
+ if (ReserveAddressSpace(address_space) && LoadSegments() && FindPhdr() &&
+ FindGnuPropertySection()) {
did_load_ = true;
+#if defined(__aarch64__)
+ // For Armv8.5-A loaded executable segments may require PROT_BTI.
+ if (note_gnu_property_.IsBTICompatible()) {
+ did_load_ = (phdr_table_protect_segments(phdr_table_, phdr_num_, load_bias_,
+ ¬e_gnu_property_) == 0);
+ }
+#endif
}
return did_load_;
@@ -748,15 +756,21 @@
ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
ElfW(Addr) seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
- int prot = PFLAGS_TO_PROT(phdr->p_flags);
- if ((extra_prot_flags & PROT_WRITE) != 0) {
+ int prot = PFLAGS_TO_PROT(phdr->p_flags) | extra_prot_flags;
+ if ((prot & PROT_WRITE) != 0) {
// make sure we're never simultaneously writable / executable
prot &= ~PROT_EXEC;
}
+#if defined(__aarch64__)
+ if ((prot & PROT_EXEC) == 0) {
+ // Though it is not specified don't add PROT_BTI if segment is not
+ // executable.
+ prot &= ~PROT_BTI;
+ }
+#endif
- int ret = mprotect(reinterpret_cast<void*>(seg_page_start),
- seg_page_end - seg_page_start,
- prot | extra_prot_flags);
+ int ret =
+ mprotect(reinterpret_cast<void*>(seg_page_start), seg_page_end - seg_page_start, prot);
if (ret < 0) {
return -1;
}
@@ -768,16 +782,26 @@
* You should only call this after phdr_table_unprotect_segments and
* applying all relocations.
*
+ * AArch64: also called from linker_main and ElfReader::Load to apply
+ * PROT_BTI for loaded main so and other so-s.
+ *
* Input:
* phdr_table -> program header table
* phdr_count -> number of entries in tables
* load_bias -> load bias
+ * prop -> GnuPropertySection or nullptr
* Return:
* 0 on error, -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) {
- return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, 0);
+int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+ ElfW(Addr) load_bias, const GnuPropertySection* prop __unused) {
+ int prot = 0;
+#if defined(__aarch64__)
+ if ((prop != nullptr) && prop->IsBTICompatible()) {
+ prot |= PROT_BTI;
+ }
+#endif
+ return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, prot);
}
/* Change the protection of all loaded segments in memory to writable.
@@ -1081,7 +1105,7 @@
* Return:
* pointer to the program interpreter string.
*/
-const char* phdr_table_get_interpreter_name(const ElfW(Phdr) * phdr_table, size_t phdr_count,
+const char* phdr_table_get_interpreter_name(const ElfW(Phdr)* phdr_table, size_t phdr_count,
ElfW(Addr) load_bias) {
for (size_t i = 0; i<phdr_count; ++i) {
const ElfW(Phdr)& phdr = phdr_table[i];
@@ -1124,6 +1148,15 @@
return false;
}
+// Tries to find .note.gnu.property section.
+// It is not considered an error if such section is missing.
+bool ElfReader::FindGnuPropertySection() {
+#if defined(__aarch64__)
+ note_gnu_property_ = GnuPropertySection(phdr_table_, phdr_num_, load_start(), name_.c_str());
+#endif
+ return true;
+}
+
// Ensures that our program header is actually within a loadable
// segment. This should help catch badly-formed ELF files that
// would cause the linker to crash later when trying to access it.
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index 4cb48f5..548dc51 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -37,6 +37,7 @@
#include "linker.h"
#include "linker_mapped_file_fragment.h"
+#include "linker_note_gnu_property.h"
class ElfReader {
public:
@@ -67,6 +68,7 @@
bool ReserveAddressSpace(address_space_params* address_space);
bool LoadSegments();
bool FindPhdr();
+ bool FindGnuPropertySection();
bool CheckPhdr(ElfW(Addr));
bool CheckFileRange(ElfW(Addr) offset, size_t size, size_t alignment);
@@ -110,13 +112,16 @@
// Is map owned by the caller
bool mapped_by_caller_;
+
+ // Only used by AArch64 at the moment.
+ GnuPropertySection note_gnu_property_ __unused;
};
size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count,
ElfW(Addr)* min_vaddr = nullptr, ElfW(Addr)* max_vaddr = nullptr);
-int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table,
- size_t phdr_count, ElfW(Addr) load_bias);
+int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+ ElfW(Addr) load_bias, const GnuPropertySection* prop = nullptr);
int phdr_table_unprotect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count,
ElfW(Addr) load_bias);
@@ -139,5 +144,5 @@
ElfW(Addr) load_bias, ElfW(Dyn)** dynamic,
ElfW(Word)* dynamic_flags);
-const char* phdr_table_get_interpreter_name(const ElfW(Phdr) * phdr_table, size_t phdr_count,
+const char* phdr_table_get_interpreter_name(const ElfW(Phdr)* phdr_table, size_t phdr_count,
ElfW(Addr) load_bias);
diff --git a/tests/Android.bp b/tests/Android.bp
index 8760256..9b95c61 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -41,6 +41,9 @@
// We want to test deprecated API too.
"-Wno-deprecated-declarations",
+ // Needed to test pthread_internal_t layout.
+ "-Wno-invalid-offsetof",
+
// For glibc.
"-D__STDC_LIMIT_MACROS",
],
@@ -392,6 +395,7 @@
"string_posix_strerror_r_test.cpp",
"strings_nofortify_test.cpp",
"strings_test.cpp",
+ "struct_layout_test.cpp",
"sstream_test.cpp",
"sys_auxv_test.cpp",
"sys_epoll_test.cpp",
@@ -987,6 +991,8 @@
"ld_config_test_helper_lib1",
"ld_config_test_helper_lib2",
"ld_config_test_helper_lib3",
+ "tls_properties_helper",
+ "thread_exit_cb_helper",
],
}
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index ef4fddd..4b86faf 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -80,7 +80,7 @@
}
cc_test {
- name: "thread_exit_cb_helper.cpp",
+ name: "thread_exit_cb_helper",
defaults: ["bionic_testlib_defaults"],
srcs: ["thread_exit_cb_helper.cpp"],
cflags: ["-fno-emulated-tls"],
diff --git a/tests/libs/tls_properties_helper.cpp b/tests/libs/tls_properties_helper.cpp
index 3f8d118..5982de4 100644
--- a/tests/libs/tls_properties_helper.cpp
+++ b/tests/libs/tls_properties_helper.cpp
@@ -34,8 +34,19 @@
#include <assert.h>
#include <dlfcn.h>
+#include <elf.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
#include <stdio.h>
-#include <unistd.h> // for gettid
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/ptrace.h>
+#include <sys/uio.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+#include <unistd.h>
// Helper binary to use TLS-related functions in thread_properties
@@ -59,20 +70,54 @@
// Tests iterate_dynamic tls chunks.
// Export a var from the shared so.
__thread char large_tls_var[4 * 1024 * 1024];
+// found_count has to be Global variable so that the non-capturing lambda
+// can access it.
+int found_count = 0;
void test_iter_tls() {
void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW);
-
- int i = 0;
- auto cb = [&](void* dtls_begin, void* dtls_end, size_t dso_id, void* arg) {
- printf("iterate_cb i = %d\n", i++);
+ large_tls_var[1025] = 'a';
+ auto cb = +[](void* dtls_begin, void* dtls_end, size_t dso_id, void* arg) {
+ if (&large_tls_var >= dtls_begin && &large_tls_var < dtls_end) ++found_count;
};
__libc_iterate_dynamic_tls(gettid(), cb, nullptr);
+
+ // It should be found exactly once.
+ assert(found_count == 1);
printf("done_iterate_dynamic_tls\n");
}
+void* parent_addr = nullptr;
+void test_iterate_another_thread_tls() {
+ large_tls_var[1025] = 'b';
+ parent_addr = &large_tls_var;
+ found_count = 0;
+
+ pid_t pid = fork();
+ assert(pid != -1);
+ int status;
+ if (pid) {
+ // Parent.
+ assert(pid == wait(&status));
+ assert(0 == status);
+ } else {
+ // Child.
+ pid_t parent_pid = getppid();
+ assert(0 == ptrace(PTRACE_ATTACH, parent_pid));
+ assert(parent_pid == waitpid(parent_pid, &status, 0));
+
+ auto cb = +[](void* dtls_begin, void* dtls_end, size_t dso_id, void* arg) {
+ if (parent_addr >= dtls_begin && parent_addr < dtls_end) ++found_count;
+ };
+ __libc_iterate_dynamic_tls(parent_pid, cb, nullptr);
+ // It should be found exactly once.
+ assert(found_count == 1);
+ printf("done_iterate_another_thread_tls\n");
+ }
+}
int main() {
test_static_tls_bounds();
test_iter_tls();
+ test_iterate_another_thread_tls();
return 0;
}
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index 55bd149..4ea6d2b 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -20,6 +20,7 @@
#include <limits.h>
#include <malloc.h>
#include <pthread.h>
+#include <semaphore.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
@@ -45,6 +46,7 @@
#include "SignalUtils.h"
#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"
@@ -84,6 +86,24 @@
free(ptr);
}
+TEST(malloc, calloc_mem_init_disabled) {
+#if defined(__BIONIC__)
+ // calloc should still zero memory if mem-init is disabled.
+ // With jemalloc the mallopts will fail but that shouldn't affect the
+ // execution of the test.
+ mallopt(M_THREAD_DISABLE_MEM_INIT, 1);
+ size_t alloc_len = 100;
+ char *ptr = reinterpret_cast<char*>(calloc(1, alloc_len));
+ for (size_t i = 0; i < alloc_len; i++) {
+ ASSERT_EQ(0, ptr[i]);
+ }
+ free(ptr);
+ mallopt(M_THREAD_DISABLE_MEM_INIT, 0);
+#else
+ GTEST_SKIP() << "bionic-only test";
+#endif
+}
+
TEST(malloc, calloc_illegal) {
SKIP_WITH_HWASAN;
errno = 0;
@@ -1241,3 +1261,39 @@
GTEST_SKIP() << "bionic extension";
#endif
}
+
+TEST(android_mallopt, 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));
+
+ pthread_t thread;
+ ASSERT_EQ(0, pthread_create(
+ &thread, nullptr,
+ [](void* ptr) -> void* {
+ auto* sem = reinterpret_cast<sem_t*>(ptr);
+ sem_wait(sem);
+ return reinterpret_cast<void*>(prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0));
+ },
+ &sem));
+
+ ASSERT_TRUE(android_mallopt(M_DISABLE_MEMORY_MITIGATIONS, nullptr, 0));
+ ASSERT_EQ(0, sem_post(&sem));
+
+ int my_tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
+ ASSERT_EQ(PR_MTE_TCF_NONE, my_tagged_addr_ctrl & PR_MTE_TCF_MASK);
+
+ void* retval;
+ 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/pthread_test.cpp b/tests/pthread_test.cpp
index 851b86f..d9ad3cc 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -2975,3 +2975,48 @@
spin_helper.UnSpin();
ASSERT_EQ(0, pthread_join(t, nullptr));
}
+
+extern "C" bool android_run_on_all_threads(bool (*func)(void*), void* arg);
+
+TEST(pthread, run_on_all_threads) {
+#if defined(__BIONIC__)
+ pthread_t t;
+ ASSERT_EQ(
+ 0, pthread_create(
+ &t, nullptr,
+ [](void*) -> void* {
+ pthread_attr_t detached;
+ if (pthread_attr_init(&detached) != 0 ||
+ pthread_attr_setdetachstate(&detached, PTHREAD_CREATE_DETACHED) != 0) {
+ return reinterpret_cast<void*>(errno);
+ }
+
+ for (int i = 0; i != 1000; ++i) {
+ pthread_t t1, t2;
+ if (pthread_create(
+ &t1, &detached, [](void*) -> void* { return nullptr; }, nullptr) != 0 ||
+ pthread_create(
+ &t2, nullptr, [](void*) -> void* { return nullptr; }, nullptr) != 0 ||
+ pthread_join(t2, nullptr) != 0) {
+ return reinterpret_cast<void*>(errno);
+ }
+ }
+
+ if (pthread_attr_destroy(&detached) != 0) {
+ return reinterpret_cast<void*>(errno);
+ }
+ return nullptr;
+ },
+ nullptr));
+
+ for (int i = 0; i != 1000; ++i) {
+ ASSERT_TRUE(android_run_on_all_threads([](void* arg) { return arg == nullptr; }, nullptr));
+ }
+
+ void *retval;
+ ASSERT_EQ(0, pthread_join(t, &retval));
+ ASSERT_EQ(nullptr, retval);
+#else
+ GTEST_SKIP() << "bionic-only test";
+#endif
+}
diff --git a/tests/struct_layout_test.cpp b/tests/struct_layout_test.cpp
new file mode 100644
index 0000000..00fd4d5
--- /dev/null
+++ b/tests/struct_layout_test.cpp
@@ -0,0 +1,158 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include <stdio.h>
+
+#if defined(__BIONIC__)
+#include "bionic/pthread_internal.h"
+
+// Ensure that the layout of these data structures is architecture independent and only depends on
+// the bitness of the architecture.
+template <typename CheckSize, typename CheckOffset>
+void tests(CheckSize check_size, CheckOffset check_offset) {
+#define CHECK_SIZE(name, size) \
+ check_size(#name, sizeof(name), size);
+#define CHECK_OFFSET(name, field, offset) \
+ check_offset(#name, #field, offsetof(name, field), offset);
+#ifdef __LP64__
+ CHECK_SIZE(pthread_internal_t, 776);
+ CHECK_OFFSET(pthread_internal_t, next, 0);
+ CHECK_OFFSET(pthread_internal_t, prev, 8);
+ CHECK_OFFSET(pthread_internal_t, tid, 16);
+ CHECK_OFFSET(pthread_internal_t, attr, 24);
+ CHECK_OFFSET(pthread_internal_t, join_state, 80);
+ CHECK_OFFSET(pthread_internal_t, cleanup_stack, 88);
+ CHECK_OFFSET(pthread_internal_t, start_routine, 96);
+ CHECK_OFFSET(pthread_internal_t, start_routine_arg, 104);
+ CHECK_OFFSET(pthread_internal_t, return_value, 112);
+ CHECK_OFFSET(pthread_internal_t, start_mask, 120);
+ CHECK_OFFSET(pthread_internal_t, alternate_signal_stack, 128);
+ CHECK_OFFSET(pthread_internal_t, shadow_call_stack_guard_region, 136);
+ CHECK_OFFSET(pthread_internal_t, stack_top, 144);
+ CHECK_OFFSET(pthread_internal_t, startup_handshake_lock, 156);
+ CHECK_OFFSET(pthread_internal_t, mmap_base, 168);
+ CHECK_OFFSET(pthread_internal_t, mmap_size, 176);
+ CHECK_OFFSET(pthread_internal_t, mmap_base_unguarded, 184);
+ CHECK_OFFSET(pthread_internal_t, mmap_size_unguarded, 192);
+ CHECK_OFFSET(pthread_internal_t, vma_name_buffer, 200);
+ CHECK_OFFSET(pthread_internal_t, thread_local_dtors, 232);
+ CHECK_OFFSET(pthread_internal_t, current_dlerror, 240);
+ CHECK_OFFSET(pthread_internal_t, dlerror_buffer, 248);
+ CHECK_OFFSET(pthread_internal_t, bionic_tls, 760);
+ CHECK_OFFSET(pthread_internal_t, errno_value, 768);
+ CHECK_SIZE(bionic_tls, 12200);
+ CHECK_OFFSET(bionic_tls, key_data, 0);
+ CHECK_OFFSET(bionic_tls, locale, 2080);
+ CHECK_OFFSET(bionic_tls, basename_buf, 2088);
+ CHECK_OFFSET(bionic_tls, dirname_buf, 6184);
+ CHECK_OFFSET(bionic_tls, mntent_buf, 10280);
+ CHECK_OFFSET(bionic_tls, mntent_strings, 10320);
+ CHECK_OFFSET(bionic_tls, ptsname_buf, 11344);
+ CHECK_OFFSET(bionic_tls, ttyname_buf, 11376);
+ CHECK_OFFSET(bionic_tls, strerror_buf, 11440);
+ CHECK_OFFSET(bionic_tls, strsignal_buf, 11695);
+ CHECK_OFFSET(bionic_tls, group, 11952);
+ CHECK_OFFSET(bionic_tls, passwd, 12040);
+ CHECK_OFFSET(bionic_tls, fdtrack_disabled, 12192);
+ CHECK_OFFSET(bionic_tls, padding, 12193);
+#else
+ CHECK_SIZE(pthread_internal_t, 668);
+ CHECK_OFFSET(pthread_internal_t, next, 0);
+ CHECK_OFFSET(pthread_internal_t, prev, 4);
+ CHECK_OFFSET(pthread_internal_t, tid, 8);
+ CHECK_OFFSET(pthread_internal_t, attr, 16);
+ CHECK_OFFSET(pthread_internal_t, join_state, 40);
+ CHECK_OFFSET(pthread_internal_t, cleanup_stack, 44);
+ CHECK_OFFSET(pthread_internal_t, start_routine, 48);
+ CHECK_OFFSET(pthread_internal_t, start_routine_arg, 52);
+ CHECK_OFFSET(pthread_internal_t, return_value, 56);
+ CHECK_OFFSET(pthread_internal_t, start_mask, 60);
+ CHECK_OFFSET(pthread_internal_t, alternate_signal_stack, 68);
+ CHECK_OFFSET(pthread_internal_t, shadow_call_stack_guard_region, 72);
+ CHECK_OFFSET(pthread_internal_t, stack_top, 76);
+ CHECK_OFFSET(pthread_internal_t, startup_handshake_lock, 84);
+ CHECK_OFFSET(pthread_internal_t, mmap_base, 92);
+ CHECK_OFFSET(pthread_internal_t, mmap_size, 96);
+ CHECK_OFFSET(pthread_internal_t, mmap_base_unguarded, 100);
+ CHECK_OFFSET(pthread_internal_t, mmap_size_unguarded, 104);
+ CHECK_OFFSET(pthread_internal_t, vma_name_buffer, 108);
+ CHECK_OFFSET(pthread_internal_t, thread_local_dtors, 140);
+ CHECK_OFFSET(pthread_internal_t, current_dlerror, 144);
+ CHECK_OFFSET(pthread_internal_t, dlerror_buffer, 148);
+ CHECK_OFFSET(pthread_internal_t, bionic_tls, 660);
+ CHECK_OFFSET(pthread_internal_t, errno_value, 664);
+ CHECK_SIZE(bionic_tls, 11080);
+ CHECK_OFFSET(bionic_tls, key_data, 0);
+ CHECK_OFFSET(bionic_tls, locale, 1040);
+ CHECK_OFFSET(bionic_tls, basename_buf, 1044);
+ CHECK_OFFSET(bionic_tls, dirname_buf, 5140);
+ CHECK_OFFSET(bionic_tls, mntent_buf, 9236);
+ CHECK_OFFSET(bionic_tls, mntent_strings, 9260);
+ CHECK_OFFSET(bionic_tls, ptsname_buf, 10284);
+ CHECK_OFFSET(bionic_tls, ttyname_buf, 10316);
+ CHECK_OFFSET(bionic_tls, strerror_buf, 10380);
+ CHECK_OFFSET(bionic_tls, strsignal_buf, 10635);
+ CHECK_OFFSET(bionic_tls, group, 10892);
+ CHECK_OFFSET(bionic_tls, passwd, 10952);
+ CHECK_OFFSET(bionic_tls, fdtrack_disabled, 11076);
+ CHECK_OFFSET(bionic_tls, padding, 11077);
+#endif // __LP64__
+#undef CHECK_SIZE
+#undef CHECK_OFFSET
+}
+#endif // defined(__BIONIC__)
+
+TEST(struct_layout, sizes_offsets) {
+#if defined(__BIONIC__)
+ bool failed = false;
+
+ auto check_size = [&](const char* name, size_t size, size_t expected_size) {
+ EXPECT_EQ(expected_size, size) << "sizeof(" << name << ")";
+ if (size != expected_size) {
+ failed = true;
+ }
+ };
+ auto check_offset = [&](const char* name, const char* field, size_t offset,
+ size_t expected_offset) {
+ EXPECT_EQ(expected_offset, offset) << "offsetof(" << name << ", " << field << ")";
+ if (offset != expected_offset) {
+ failed = true;
+ }
+ };
+ tests(check_size, check_offset);
+
+ if (failed) {
+ printf(
+ "Please update the tests function in bionic/tests/struct_layout_test.cpp with the "
+ "following contents:\n");
+
+ auto print_size = [&](const char* name, size_t size, size_t expected_size) {
+ (void)expected_size;
+ printf(" CHECK_SIZE(%s, %zu);\n", name, size);
+ };
+ auto print_offset = [&](const char* name, const char* field, size_t offset,
+ size_t expected_offset) {
+ (void)expected_offset;
+ printf(" CHECK_OFFSET(%s, %s, %zu);\n", name, field, offset);
+ };
+ tests(print_size, print_offset);
+ }
+#else
+ GTEST_SKIP() << "bionic-only test";
+#endif
+}
diff --git a/tools/versioner/src/Driver.cpp b/tools/versioner/src/Driver.cpp
index 184c3d4..adf93c3 100644
--- a/tools/versioner/src/Driver.cpp
+++ b/tools/versioner/src/Driver.cpp
@@ -42,6 +42,7 @@
#include <llvm/ADT/SmallVector.h>
#include <llvm/ADT/StringRef.h>
#include <llvm/Option/Option.h>
+#include <llvm/Support/Host.h>
#include <llvm/Support/VirtualFileSystem.h>
#include "Arch.h"