Skip to content

Commit c863e96

Browse files
vstinnerstratakis
andauthored
[3.14] gh-139808: Add branch protections for aarch64 in asm_trampoline.S (#130864) (#150189)
gh-139808: Add branch protections for aarch64 in asm_trampoline.S (#130864) Apply protection against ROP/JOP attacks for aarch64 on asm_trampoline.S. The BTI flag must be applied in assembler sources for this class of attacks to be mitigated on newer aarch64 processors. See also: https://sourceware.org/annobin/annobin.html/Test-branch-protection.html and https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/enabling-pac-and-bti-on-aarch64 The 3.14 backport makes Python/jit_unwind.c changes in Python/perf_jit_trampoline.c. (cherry picked from commit da8477b) Co-authored-by: stratakis <cstratak@redhat.com>
1 parent 1d4f9ab commit c863e96

4 files changed

Lines changed: 75 additions & 0 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add branch protections for AArch64 (BTI/PAC) in assembly code used by
2+
:option:`-X perf_jit <-X>` (Linux perf profiler integration).

Python/asm_trampoline.S

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#include "asm_trampoline_aarch64.h"
2+
13
.text
24
.globl _Py_trampoline_func_start
35
# The following assembly is equivalent to:
@@ -21,10 +23,12 @@ _Py_trampoline_func_start:
2123
#if defined(__aarch64__) && defined(__AARCH64EL__) && !defined(__ILP32__)
2224
// ARM64 little endian, 64bit ABI
2325
// generate with aarch64-linux-gnu-gcc 12.1
26+
SIGN_LR
2427
stp x29, x30, [sp, -16]!
2528
mov x29, sp
2629
blr x3
2730
ldp x29, x30, [sp], 16
31+
VERIFY_LR
2832
ret
2933
#endif
3034
#ifdef __riscv

Python/asm_trampoline_aarch64.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#ifndef ASM_TRAMPOLINE_AARCH_64_H_
2+
#define ASM_TRAMPOLINE_AARCH_64_H_
3+
4+
/*
5+
* References:
6+
* - https://developer.arm.com/documentation/101028/0012/5--Feature-test-macros
7+
* - https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst
8+
*/
9+
10+
#if defined(__ARM_FEATURE_BTI_DEFAULT) && __ARM_FEATURE_BTI_DEFAULT == 1
11+
#define BTI_J hint 36 /* bti j: for jumps, IE br instructions */
12+
#define BTI_C hint 34 /* bti c: for calls, IE bl instructions */
13+
#define GNU_PROPERTY_AARCH64_BTI 1 /* bit 0 GNU Notes is for BTI support */
14+
#else
15+
#define BTI_J
16+
#define BTI_C
17+
#define GNU_PROPERTY_AARCH64_BTI 0
18+
#endif
19+
20+
#if defined(__ARM_FEATURE_PAC_DEFAULT)
21+
#if __ARM_FEATURE_PAC_DEFAULT & 1
22+
#define SIGN_LR hint 25 /* paciasp: sign with the A key */
23+
#define VERIFY_LR hint 29 /* autiasp: verify with the A key */
24+
#elif __ARM_FEATURE_PAC_DEFAULT & 2
25+
#define SIGN_LR hint 27 /* pacibsp: sign with the b key */
26+
#define VERIFY_LR hint 31 /* autibsp: verify with the b key */
27+
#endif
28+
#define GNU_PROPERTY_AARCH64_POINTER_AUTH 2 /* bit 1 GNU Notes is for PAC support */
29+
#else
30+
#define SIGN_LR BTI_C
31+
#define VERIFY_LR
32+
#define GNU_PROPERTY_AARCH64_POINTER_AUTH 0
33+
#endif
34+
35+
#if defined(__ARM_FEATURE_GCS_DEFAULT) && __ARM_FEATURE_GCS_DEFAULT == 1
36+
#define GNU_PROPERTY_AARCH64_GCS 4 /* bit 2 GNU Notes is for GCS support */
37+
#else
38+
#define GNU_PROPERTY_AARCH64_GCS 0
39+
#endif
40+
41+
/* Add the BTI, PAC and GCS support to GNU Notes section */
42+
#if GNU_PROPERTY_AARCH64_BTI != 0 || GNU_PROPERTY_AARCH64_POINTER_AUTH != 0 || GNU_PROPERTY_AARCH64_GCS != 0
43+
.pushsection .note.gnu.property, "a"; /* Start a new allocatable section */
44+
.balign 8; /* align it on a byte boundry */
45+
.long 4; /* size of "GNU\0" */
46+
.long 0x10; /* size of descriptor */
47+
.long 0x5; /* NT_GNU_PROPERTY_TYPE_0 */
48+
.asciz "GNU";
49+
.long 0xc0000000; /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */
50+
.long 4; /* Four bytes of data */
51+
.long (GNU_PROPERTY_AARCH64_BTI|GNU_PROPERTY_AARCH64_POINTER_AUTH|GNU_PROPERTY_AARCH64_GCS); /* BTI, PAC or GCS is enabled */
52+
.long 0; /* padding for 8 byte alignment */
53+
.popsection; /* end the section */
54+
#endif
55+
56+
#endif

Python/perf_jit_trampoline.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,9 @@ enum {
406406
DWRF_CFA_offset_extended_sf = 0x11, // Extended signed offset
407407
DWRF_CFA_advance_loc = 0x40, // Advance location counter
408408
DWRF_CFA_offset = 0x80, // Simple offset instruction
409+
#if defined(__aarch64__)
410+
DWRF_CFA_AARCH64_negate_ra_state = 0x2d, // Toggle return address signing state
411+
#endif
409412
DWRF_CFA_restore = 0xc0 // Restore register
410413
};
411414

@@ -924,6 +927,13 @@ static void elf_init_ehframe(ELFObjectContext* ctx) {
924927
DWRF_UV(8); // New offset: SP + 8
925928
#elif defined(__aarch64__) && defined(__AARCH64EL__) && !defined(__ILP32__)
926929
/* AArch64 calling convention unwinding rules */
930+
#if defined(__ARM_FEATURE_PAC_DEFAULT) || \
931+
(defined(__ARM_FEATURE_BTI_DEFAULT) && __ARM_FEATURE_BTI_DEFAULT == 1)
932+
DWRF_U8(DWRF_CFA_advance_loc | 1); // Advance past SIGN_LR (4 bytes)
933+
#endif
934+
#if defined(__ARM_FEATURE_PAC_DEFAULT)
935+
DWRF_U8(DWRF_CFA_AARCH64_negate_ra_state); // Saved LR is PAC-signed from here
936+
#endif
927937
DWRF_U8(DWRF_CFA_advance_loc | 1); // Advance by 1 instruction (4 bytes)
928938
DWRF_U8(DWRF_CFA_def_cfa_offset); // CFA = SP + 16
929939
DWRF_UV(16); // Stack pointer moved by 16 bytes
@@ -932,6 +942,9 @@ static void elf_init_ehframe(ELFObjectContext* ctx) {
932942
DWRF_U8(DWRF_CFA_offset | DWRF_REG_RA); // x30 (link register) saved
933943
DWRF_UV(1); // At CFA-8 (1 * 8 = 8 bytes from CFA)
934944
DWRF_U8(DWRF_CFA_advance_loc | 3); // Advance by 3 instructions (12 bytes)
945+
#if defined(__ARM_FEATURE_PAC_DEFAULT)
946+
DWRF_U8(DWRF_CFA_AARCH64_negate_ra_state); // LR is authenticated, no longer PAC-signed
947+
#endif
935948
DWRF_U8(DWRF_CFA_restore | DWRF_REG_RA); // Restore x30 - NO DWRF_UV() after this!
936949
DWRF_U8(DWRF_CFA_restore | DWRF_REG_FP); // Restore x29 - NO DWRF_UV() after this!
937950
DWRF_U8(DWRF_CFA_def_cfa_offset); // CFA = SP + 0 (stack restored)

0 commit comments

Comments
 (0)