Skip to content

Commit

Permalink
8337536: AArch64: Enable BTI branch protection for runtime part
Browse files Browse the repository at this point in the history
This patch enables BTI branch protection for runtime part on
Linux/aarch64 platform.

Motivation

1. Since Fedora 33, glibc+kernel are PAC/BTI enabled by default.
User-level packages can gain additional hardening by compiling with the
GCC/Clang flag `-mbranch-protection=flag`. See [1].

2. In JDK-8277204 [2], `--enable-branch-protection` was introduced as
one VM configure flag, which would pass `-mbranch-protection=standard`
compilation flags to all c/c++ files. Note that `standard` turns on both
`pac-ret` and `bti` branch protections. For more details about code
reuse attacks and hardware-assisted branch protections on AArch64, see
[3].

However, we checked the `.note.gnu.property` section of all the shared
libraries under `jdk/lib` on Fedora 40, and found that only libjvm.so
didn't set these two target feature bits:

```
  GNU_PROPERTY_AARCH64_FEATURE_1_BTI
  GNU_PROPERTY_AARCH64_FEATURE_1_PAC
```

Note-1: BTI is an all or nothing property for a link unit [4]. That is,
libjvm.so is not BTI-enabled.

Note-2: PAC bit in `.note.gnu.property` section is used to protect
`.got.plt` table. It's independent of whether the relocatable objects
use PAC or not.

Goal

Hence, this patch aims to set PAC/BTI feature bits of the
`.note.gnu.property` section for libjvm.so.

Implementation

Task-1: find out the problematic input objects

From [5], "Static linkers processing ELF relocatable objects must set
the feature bit in the output object or image only if all the input
objects have the corresponding feature bit set." Hence we suspect that
the root cause is probably that the PAC/BTI feature bits are not set
only for some input objects of libjvm.so.

In order to find out these inputs, we passed `--force-bti` linker flag
[4] in my local test. This linker flag would warn if any input object
does not have GNU_PROPERTY_AARCH64_FEATURE_1_BTI. We got the following
list:

```
  src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.S
  src/hotspot/os_cpu/linux_aarch64/copy_linux_aarch64.S
  src/hotspot/os_cpu/linux_aarch64/safefetch_linux_aarch64.S
  src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S
```

Task-2: add `.note.gnu.property` section for these assembly files

As mentioned in Motivation-2 part, `-mbranch-protection=standard` is
passed to compile c/c++ files but these assembly files are missed.

In this patch, we also pass `-mbranch-protection=standard` flag to
assembler (See the update in flags-cflags.m4 and flags-other.m4), and
add `.note.gnu.property` section at the end of these assembler files.

With this change, we can see PAC/BTI feature bits in the final
libjvm.so.

Task-3: add BTI landing pads for hand written assembly

In the local test on Fedora 40 with PAC/BTI-capable hardware, we got
`SIGILL` error, which is one typical BTI error (branch target exception).
The root cause is that we should add the missing BTI landing pads for
hand written assembly in hotspot.

File-1 copy_aarch64.hpp: It's a switch-case statement and we add `bti j`
for these indirect jumps.

File-2 atomic_linux_aarch64.S: We add landings pads `bti c` at the
function entries.

File-3 copy_linux_aarch64.S: There is no need to add `bti c` at the
function entries since they are called via `bl`. And we should handle
the indirect jumps.

File-4 safefetch_linux_aarch64.S: Similar to file-3, there is no need to
handle these function entries.

File-5 threadLS_linux_aarch64.S: No need to handle the function entry
because `paciasp` can act as the landing pad.

Evaluation

1. jtreg test

We ran tier 1-3 jtreg tests on Fedora 40 + GCC 14 + the following AArch64
hardware and all tests passed.

```
  1. w/o PAC and w/o BTI
  2. w/ PAC and w/o BTI
  3. w/ PAC and w/ BTI
```

We also ran the jtreg tests on Fedora 40 + Clang 18 + hardware w/ PAC
and w/ BTI. The test passed too.

2. code size

We got about 2% code size increase before and after
`--enbale-branch-protection` is used. This code size change looks
reasonable. See the evaluation on glibc [6].

[1] https://fedoraproject.org/wiki/Changes/Aarch64_PointerAuthentication
[2] https://bugs.openjdk.org/browse/JDK-8277204
[3] https://community.arm.com/arm-community-blogs/b/tools-software-ides-blog/posts/code-reuse-attacks-the-compiler-story
[4] https://reviews.llvm.org/D62609
[5] https://github.com/ARM-software/abi-aa/blob/2a70c42d62e9c3eb5887fa50b71257f20daca6f9/aaelf64/aaelf64.rst#program-property
[6] https://developer.arm.com/documentation/102433/0100/Applying-these-techniques-to-real-code
  • Loading branch information
shqking authored and fg1417 committed Aug 7, 2024
1 parent fbe8a81 commit d1506d7
Show file tree
Hide file tree
Showing 7 changed files with 221 additions and 24 deletions.
7 changes: 6 additions & 1 deletion make/autoconf/flags-cflags.m4
Original file line number Diff line number Diff line change
Expand Up @@ -937,10 +937,15 @@ AC_DEFUN_ONCE([FLAGS_SETUP_BRANCH_PROTECTION],
fi
fi
# BRANCH_PROTECTION_ASFLAGS will be added to ASFLAGS in flags-other.m4.
BRANCH_PROTECTION_ASFLAGS=""
BRANCH_PROTECTION_CFLAGS=""
UTIL_ARG_ENABLE(NAME: branch-protection, DEFAULT: false,
RESULT: USE_BRANCH_PROTECTION, AVAILABLE: $BRANCH_PROTECTION_AVAILABLE,
DESC: [enable branch protection when compiling C/C++],
IF_ENABLED: [ BRANCH_PROTECTION_CFLAGS=${BRANCH_PROTECTION_FLAG}])
IF_ENABLED: [
BRANCH_PROTECTION_ASFLAGS=${BRANCH_PROTECTION_FLAG}
BRANCH_PROTECTION_CFLAGS=${BRANCH_PROTECTION_FLAG}
])
AC_SUBST(BRANCH_PROTECTION_CFLAGS)
])
7 changes: 7 additions & 0 deletions make/autoconf/flags-other.m4
Original file line number Diff line number Diff line change
Expand Up @@ -150,5 +150,12 @@ AC_DEFUN([FLAGS_SETUP_ASFLAGS_CPU_DEP],
$2JVM_ASFLAGS="${$2JVM_ASFLAGS} $ARM_ARCH_TYPE_ASFLAGS $ARM_FLOAT_TYPE_ASFLAGS"
fi
if test "x$OPENJDK_TARGET_CPU" = xaarch64; then
if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
# BRANCH_PROTECTION_ASFLAGS is setup in flags-cflags.m4.
$2JVM_ASFLAGS="${$2JVM_ASFLAGS} $BRANCH_PROTECTION_ASFLAGS"
fi
fi
AC_SUBST($2JVM_ASFLAGS)
])
11 changes: 10 additions & 1 deletion src/hotspot/cpu/aarch64/copy_aarch64.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
Expand Down Expand Up @@ -64,28 +64,34 @@ static void pd_zero_to_bytes(void* to, size_t count) {
" br %[t0];\n" \
" .align 5;\n" \
"0:" \
" hint #0x24; // bti j\n" \
" b 1f;\n" \
" .align 5;\n" \
" hint #0x24; // bti j\n" \
" ldr %[t0], [%[s], #0];\n" \
" str %[t0], [%[d], #0];\n" \
" b 1f;\n" \
" .align 5;\n" \
" hint #0x24; // bti j\n" \
" ldp %[t0], %[t1], [%[s], #0];\n" \
" stp %[t0], %[t1], [%[d], #0];\n" \
" b 1f;\n" \
" .align 5;\n" \
" hint #0x24; // bti j\n" \
" ldp %[t0], %[t1], [%[s], #0];\n" \
" ldr %[t2], [%[s], #16];\n" \
" stp %[t0], %[t1], [%[d], #0];\n" \
" str %[t2], [%[d], #16];\n" \
" b 1f;\n" \
" .align 5;\n" \
" hint #0x24; // bti j\n" \
" ldp %[t0], %[t1], [%[s], #0];\n" \
" ldp %[t2], %[t3], [%[s], #16];\n" \
" stp %[t0], %[t1], [%[d], #0];\n" \
" stp %[t2], %[t3], [%[d], #16];\n" \
" b 1f;\n" \
" .align 5;\n" \
" hint #0x24; // bti j\n" \
" ldp %[t0], %[t1], [%[s], #0];\n" \
" ldp %[t2], %[t3], [%[s], #16];\n" \
" ldr %[t4], [%[s], #32];\n" \
Expand All @@ -94,6 +100,7 @@ static void pd_zero_to_bytes(void* to, size_t count) {
" str %[t4], [%[d], #32];\n" \
" b 1f;\n" \
" .align 5;\n" \
" hint #0x24; // bti j\n" \
" ldp %[t0], %[t1], [%[s], #0];\n" \
" ldp %[t2], %[t3], [%[s], #16];\n" \
" ldp %[t4], %[t5], [%[s], #32];\n" \
Expand All @@ -103,13 +110,15 @@ static void pd_zero_to_bytes(void* to, size_t count) {
" stp %[t4], %[t5], [%[d], #32];\n" \
" b 1f;\n" \
" .align 5;\n" \
" hint #0x24; // bti j\n" \
" ldr %[t6], [%[s], #0];\n" \
" ldp %[t0], %[t1], [%[s], #8];\n" \
" ldp %[t2], %[t3], [%[s], #24];\n" \
" ldp %[t4], %[t5], [%[s], #40];\n" \
" str %[t6], [%[d]], #8;\n" \
" b 2b;\n" \
" .align 5;\n" \
" hint #0x24; // bti j\n" \
" ldp %[t0], %[t1], [%[s], #0];\n" \
" ldp %[t2], %[t3], [%[s], #16];\n" \
" ldp %[t4], %[t5], [%[s], #32];\n" \
Expand Down
52 changes: 50 additions & 2 deletions src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.S
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

.align 5
DECLARE_FUNC(aarch64_atomic_fetch_add_8_default_impl):
hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
ldaddal x1, x2, [x0]
#else
Expand All @@ -41,6 +42,7 @@ DECLARE_FUNC(aarch64_atomic_fetch_add_8_default_impl):

.align 5
DECLARE_FUNC(aarch64_atomic_fetch_add_4_default_impl):
hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
ldaddal w1, w2, [x0]
#else
Expand All @@ -56,8 +58,9 @@ DECLARE_FUNC(aarch64_atomic_fetch_add_4_default_impl):

.align 5
DECLARE_FUNC(aarch64_atomic_fetch_add_8_relaxed_default_impl):
hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
ldadd x1, x2, [x0]
ldadd x1, x2, [x0]
#else
prfm pstl1strm, [x0]
0: ldxr x2, [x0]
Expand All @@ -70,8 +73,9 @@ DECLARE_FUNC(aarch64_atomic_fetch_add_8_relaxed_default_impl):

.align 5
DECLARE_FUNC(aarch64_atomic_fetch_add_4_relaxed_default_impl):
hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
ldadd w1, w2, [x0]
ldadd w1, w2, [x0]
#else
prfm pstl1strm, [x0]
0: ldxr w2, [x0]
Expand All @@ -84,6 +88,7 @@ DECLARE_FUNC(aarch64_atomic_fetch_add_4_relaxed_default_impl):

.align 5
DECLARE_FUNC(aarch64_atomic_xchg_4_default_impl):
hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
swpal w1, w2, [x0]
#else
Expand All @@ -98,6 +103,7 @@ DECLARE_FUNC(aarch64_atomic_xchg_4_default_impl):

.align 5
DECLARE_FUNC(aarch64_atomic_xchg_8_default_impl):
hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
swpal x1, x2, [x0]
#else
Expand All @@ -112,6 +118,7 @@ DECLARE_FUNC(aarch64_atomic_xchg_8_default_impl):

.align 5
DECLARE_FUNC(aarch64_atomic_cmpxchg_1_default_impl):
hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
mov x3, x1
casalb w3, w2, [x0]
Expand All @@ -131,6 +138,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_1_default_impl):

.align 5
DECLARE_FUNC(aarch64_atomic_cmpxchg_4_default_impl):
hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
mov x3, x1
casal w3, w2, [x0]
Expand All @@ -149,6 +157,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_4_default_impl):

.align 5
DECLARE_FUNC(aarch64_atomic_cmpxchg_8_default_impl):
hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
mov x3, x1
casal x3, x2, [x0]
Expand All @@ -167,6 +176,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_8_default_impl):

.align 5
DECLARE_FUNC(aarch64_atomic_cmpxchg_4_release_default_impl):
hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
mov x3, x1
casl w3, w2, [x0]
Expand All @@ -183,6 +193,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_4_release_default_impl):

.align 5
DECLARE_FUNC(aarch64_atomic_cmpxchg_8_release_default_impl):
hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
mov x3, x1
casl x3, x2, [x0]
Expand All @@ -199,6 +210,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_8_release_default_impl):

.align 5
DECLARE_FUNC(aarch64_atomic_cmpxchg_4_seq_cst_default_impl):
hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
mov x3, x1
casal w3, w2, [x0]
Expand All @@ -215,6 +227,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_4_seq_cst_default_impl):

.align 5
DECLARE_FUNC(aarch64_atomic_cmpxchg_8_seq_cst_default_impl):
hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
mov x3, x1
casal x3, x2, [x0]
Expand All @@ -231,6 +244,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_8_seq_cst_default_impl):

.align 5
DECLARE_FUNC(aarch64_atomic_cmpxchg_1_relaxed_default_impl):
hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
mov x3, x1
casb w3, w2, [x0]
Expand All @@ -248,6 +262,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_1_relaxed_default_impl):

.align 5
DECLARE_FUNC(aarch64_atomic_cmpxchg_4_relaxed_default_impl):
hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
mov x3, x1
cas w3, w2, [x0]
Expand All @@ -264,6 +279,7 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_4_relaxed_default_impl):

.align 5
DECLARE_FUNC(aarch64_atomic_cmpxchg_8_relaxed_default_impl):
hint #0x22 // bti c
#ifdef __ARM_FEATURE_ATOMICS
mov x3, x1
cas x3, x2, [x0]
Expand All @@ -277,3 +293,35 @@ DECLARE_FUNC(aarch64_atomic_cmpxchg_8_relaxed_default_impl):
#endif
1: mov x0, x3
ret

/* Emit .note.gnu.property section in case of PAC or BTI being enabled.
* For more details see "ELF for the Arm® 64-bit Architecture (AArch64)".
* https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst
*/
#ifdef __ARM_FEATURE_BTI_DEFAULT
#ifdef __ARM_FEATURE_PAC_DEFAULT
#define GNU_PROPERTY_AARCH64_FEATURE 3
#else
#define GNU_PROPERTY_AARCH64_FEATURE 1
#endif
#else
#ifdef __ARM_FEATURE_PAC_DEFAULT
#define GNU_PROPERTY_AARCH64_FEATURE 2
#else
#define GNU_PROPERTY_AARCH64_FEATURE 0
#endif
#endif

#if (GNU_PROPERTY_AARCH64_FEATURE != 0)
.pushsection .note.gnu.property, "a"
.align 3
.long 4 /* name length */
.long 0x10 /* data length */
.long 5 /* note type: NT_GNU_PROPERTY_TYPE_0 */
.string "GNU" /* vendor name */
.long 0xc0000000 /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */
.long 4 /* pr_datasze */
.long GNU_PROPERTY_AARCH64_FEATURE
.long 0
.popsection
#endif
Loading

0 comments on commit d1506d7

Please sign in to comment.