Skip to content

Commit 6fab8a2

Browse files
a74nhadinn
authored andcommitted
8277204: Implement PAC-RET branch protection on Linux/AArch64
Reviewed-by: erikj, ihse, adinn, ngasson
1 parent abc0ce1 commit 6fab8a2

35 files changed

+1445
-903
lines changed

doc/building.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,14 @@ space is required.
135135
If you do not have access to sufficiently powerful hardware, it is also
136136
possible to use [cross-compiling](#cross-compiling).
137137

138+
#### Branch Protection
139+
140+
In order to use Branch Protection features in the VM, `--enable-branch-protection`
141+
must be used. This option requires C++ compiler support (GCC 9.1.0+ or Clang
142+
10+). The resulting build can be run on both machines with and without support
143+
for branch protection in hardware. Branch Protection is only supported for
144+
Linux targets.
145+
138146
### Building on 32-bit arm
139147

140148
This is not recommended. Instead, see the section on [Cross-compiling](

make/autoconf/flags-cflags.m4

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
2+
# Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
33
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
#
55
# This code is free software; you can redistribute it and/or modify it
@@ -803,17 +803,19 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP],
803803
fi
804804
AC_SUBST(FILE_MACRO_CFLAGS)
805805
806+
FLAGS_SETUP_BRANCH_PROTECTION
807+
806808
# EXPORT to API
807809
CFLAGS_JVM_COMMON="$ALWAYS_CFLAGS_JVM $ALWAYS_DEFINES_JVM \
808810
$TOOLCHAIN_CFLAGS_JVM ${$1_TOOLCHAIN_CFLAGS_JVM} \
809811
$OS_CFLAGS $OS_CFLAGS_JVM $CFLAGS_OS_DEF_JVM $DEBUG_CFLAGS_JVM \
810812
$WARNING_CFLAGS $WARNING_CFLAGS_JVM $JVM_PICFLAG $FILE_MACRO_CFLAGS \
811-
$REPRODUCIBLE_CFLAGS"
813+
$REPRODUCIBLE_CFLAGS $BRANCH_PROTECTION_CFLAGS"
812814
813815
CFLAGS_JDK_COMMON="$ALWAYS_CFLAGS_JDK $ALWAYS_DEFINES_JDK $TOOLCHAIN_CFLAGS_JDK \
814816
$OS_CFLAGS $CFLAGS_OS_DEF_JDK $DEBUG_CFLAGS_JDK $DEBUG_OPTIONS_FLAGS_JDK \
815817
$WARNING_CFLAGS $WARNING_CFLAGS_JDK $DEBUG_SYMBOLS_CFLAGS_JDK \
816-
$FILE_MACRO_CFLAGS $REPRODUCIBLE_CFLAGS"
818+
$FILE_MACRO_CFLAGS $REPRODUCIBLE_CFLAGS $BRANCH_PROTECTION_CFLAGS"
817819
818820
# Use ${$2EXTRA_CFLAGS} to block EXTRA_CFLAGS to be added to build flags.
819821
# (Currently we don't have any OPENJDK_BUILD_EXTRA_CFLAGS, but that might
@@ -879,3 +881,24 @@ AC_DEFUN([FLAGS_SETUP_GCC6_COMPILER_FLAGS],
879881
PREFIX: $2, IF_FALSE: [NO_LIFETIME_DSE_CFLAG=""])
880882
$1_GCC6_CFLAGS="${NO_DELETE_NULL_POINTER_CHECKS_CFLAG} ${NO_LIFETIME_DSE_CFLAG}"
881883
])
884+
885+
AC_DEFUN_ONCE([FLAGS_SETUP_BRANCH_PROTECTION],
886+
[
887+
# Is branch protection available?
888+
BRANCH_PROTECTION_AVAILABLE=false
889+
BRANCH_PROTECTION_FLAG="-mbranch-protection=standard"
890+
891+
if test "x$OPENJDK_TARGET_CPU" = xaarch64; then
892+
if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
893+
FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [${BRANCH_PROTECTION_FLAG}],
894+
IF_TRUE: [BRANCH_PROTECTION_AVAILABLE=true])
895+
fi
896+
fi
897+
898+
BRANCH_PROTECTION_CFLAGS=""
899+
UTIL_ARG_ENABLE(NAME: branch-protection, DEFAULT: false,
900+
RESULT: USE_BRANCH_PROTECTION, AVAILABLE: $BRANCH_PROTECTION_AVAILABLE,
901+
DESC: [enable branch protection when compiling C/C++],
902+
IF_ENABLED: [ BRANCH_PROTECTION_CFLAGS=${BRANCH_PROTECTION_FLAG}])
903+
AC_SUBST(BRANCH_PROTECTION_CFLAGS)
904+
])

make/autoconf/spec.gmk.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,7 @@ LIBFFI_CFLAGS:=@LIBFFI_CFLAGS@
407407
ENABLE_LIBFFI_BUNDLING:=@ENABLE_LIBFFI_BUNDLING@
408408
LIBFFI_LIB_FILE:=@LIBFFI_LIB_FILE@
409409
FILE_MACRO_CFLAGS := @FILE_MACRO_CFLAGS@
410+
BRANCH_PROTECTION_CFLAGS := @BRANCH_PROTECTION_CFLAGS@
410411

411412
STATIC_LIBS_CFLAGS := @STATIC_LIBS_CFLAGS@
412413

src/hotspot/cpu/aarch64/aarch64.ad

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1853,6 +1853,10 @@ void MachPrologNode::format(PhaseRegAlloc *ra_, outputStream *st) const {
18531853
if (C->output()->need_stack_bang(framesize))
18541854
st->print("# stack bang size=%d\n\t", framesize);
18551855

1856+
if (VM_Version::use_rop_protection()) {
1857+
st->print("ldr zr, [lr]\n\t");
1858+
st->print("pacia lr, rfp\n\t");
1859+
}
18561860
if (framesize < ((1 << 9) + 2 * wordSize)) {
18571861
st->print("sub sp, sp, #%d\n\t", framesize);
18581862
st->print("stp rfp, lr, [sp, #%d]", framesize - 2 * wordSize);
@@ -1961,6 +1965,10 @@ void MachEpilogNode::format(PhaseRegAlloc *ra_, outputStream *st) const {
19611965
st->print("add sp, sp, rscratch1\n\t");
19621966
st->print("ldp lr, rfp, [sp],#%d\n\t", (2 * wordSize));
19631967
}
1968+
if (VM_Version::use_rop_protection()) {
1969+
st->print("autia lr, rfp\n\t");
1970+
st->print("ldr zr, [lr]\n\t");
1971+
}
19641972

19651973
if (do_polling() && C->is_method_compilation()) {
19661974
st->print("# test polling word\n\t");

src/hotspot/cpu/aarch64/assembler_aarch64.hpp

Lines changed: 103 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -987,33 +987,35 @@ class Assembler : public AbstractAssembler {
987987
rf(rt, 0);
988988
}
989989

990-
void hint(int imm) {
991-
system(0b00, 0b011, 0b0010, 0b0000, imm);
992-
}
993-
994-
void nop() {
995-
hint(0);
996-
}
997-
998-
void yield() {
999-
hint(1);
1000-
}
990+
// Hint instructions
1001991

1002-
void wfe() {
1003-
hint(2);
992+
#define INSN(NAME, crm, op2) \
993+
void NAME() { \
994+
system(0b00, 0b011, 0b0010, crm, op2); \
1004995
}
1005996

1006-
void wfi() {
1007-
hint(3);
1008-
}
997+
INSN(nop, 0b000, 0b0000);
998+
INSN(yield, 0b000, 0b0001);
999+
INSN(wfe, 0b000, 0b0010);
1000+
INSN(wfi, 0b000, 0b0011);
1001+
INSN(sev, 0b000, 0b0100);
1002+
INSN(sevl, 0b000, 0b0101);
10091003

1010-
void sev() {
1011-
hint(4);
1012-
}
1004+
INSN(autia1716, 0b0001, 0b100);
1005+
INSN(autiasp, 0b0011, 0b101);
1006+
INSN(autiaz, 0b0011, 0b100);
1007+
INSN(autib1716, 0b0001, 0b110);
1008+
INSN(autibsp, 0b0011, 0b111);
1009+
INSN(autibz, 0b0011, 0b110);
1010+
INSN(pacia1716, 0b0001, 0b000);
1011+
INSN(paciasp, 0b0011, 0b001);
1012+
INSN(paciaz, 0b0011, 0b000);
1013+
INSN(pacib1716, 0b0001, 0b010);
1014+
INSN(pacibsp, 0b0011, 0b011);
1015+
INSN(pacibz, 0b0011, 0b010);
1016+
INSN(xpaclri, 0b0000, 0b111);
10131017

1014-
void sevl() {
1015-
hint(5);
1016-
}
1018+
#undef INSN
10171019

10181020
// we only provide mrs and msr for the special purpose system
10191021
// registers where op1 (instr[20:19]) == 11 and, (currently) only
@@ -1099,18 +1101,21 @@ class Assembler : public AbstractAssembler {
10991101
}
11001102

11011103
// Unconditional branch (register)
1102-
void branch_reg(Register R, int opc) {
1104+
1105+
void branch_reg(int OP, int A, int M, Register RN, Register RM) {
11031106
starti;
11041107
f(0b1101011, 31, 25);
1105-
f(opc, 24, 21);
1106-
f(0b11111000000, 20, 10);
1107-
rf(R, 5);
1108-
f(0b00000, 4, 0);
1108+
f(OP, 24, 21);
1109+
f(0b111110000, 20, 12);
1110+
f(A, 11, 11);
1111+
f(M, 10, 10);
1112+
rf(RN, 5);
1113+
rf(RM, 0);
11091114
}
11101115

1111-
#define INSN(NAME, opc) \
1112-
void NAME(Register R) { \
1113-
branch_reg(R, opc); \
1116+
#define INSN(NAME, opc) \
1117+
void NAME(Register RN) { \
1118+
branch_reg(opc, 0, 0, RN, r0); \
11141119
}
11151120

11161121
INSN(br, 0b0000);
@@ -1121,14 +1126,48 @@ class Assembler : public AbstractAssembler {
11211126

11221127
#undef INSN
11231128

1124-
#define INSN(NAME, opc) \
1125-
void NAME() { \
1126-
branch_reg(dummy_reg, opc); \
1129+
#define INSN(NAME, opc) \
1130+
void NAME() { \
1131+
branch_reg(opc, 0, 0, dummy_reg, r0); \
11271132
}
11281133

11291134
INSN(eret, 0b0100);
11301135
INSN(drps, 0b0101);
11311136

1137+
#undef INSN
1138+
1139+
#define INSN(NAME, M) \
1140+
void NAME() { \
1141+
branch_reg(0b0010, 1, M, dummy_reg, dummy_reg); \
1142+
}
1143+
1144+
INSN(retaa, 0);
1145+
INSN(retab, 1);
1146+
1147+
#undef INSN
1148+
1149+
#define INSN(NAME, OP, M) \
1150+
void NAME(Register rn) { \
1151+
branch_reg(OP, 1, M, rn, dummy_reg); \
1152+
}
1153+
1154+
INSN(braaz, 0b0000, 0);
1155+
INSN(brabz, 0b0000, 1);
1156+
INSN(blraaz, 0b0001, 0);
1157+
INSN(blrabz, 0b0001, 1);
1158+
1159+
#undef INSN
1160+
1161+
#define INSN(NAME, OP, M) \
1162+
void NAME(Register rn, Register rm) { \
1163+
branch_reg(OP, 1, M, rn, rm); \
1164+
}
1165+
1166+
INSN(braa, 0b1000, 0);
1167+
INSN(brab, 0b1000, 1);
1168+
INSN(blraa, 0b1001, 0);
1169+
INSN(blrab, 0b1001, 1);
1170+
11321171
#undef INSN
11331172

11341173
// Load/store exclusive
@@ -1792,6 +1831,37 @@ void mvnw(Register Rd, Register Rm,
17921831
INSN(clz, 0b110, 0b00000, 0b00100);
17931832
INSN(cls, 0b110, 0b00000, 0b00101);
17941833

1834+
// PAC instructions
1835+
INSN(pacia, 0b110, 0b00001, 0b00000);
1836+
INSN(pacib, 0b110, 0b00001, 0b00001);
1837+
INSN(pacda, 0b110, 0b00001, 0b00010);
1838+
INSN(pacdb, 0b110, 0b00001, 0b00011);
1839+
INSN(autia, 0b110, 0b00001, 0b00100);
1840+
INSN(autib, 0b110, 0b00001, 0b00101);
1841+
INSN(autda, 0b110, 0b00001, 0b00110);
1842+
INSN(autdb, 0b110, 0b00001, 0b00111);
1843+
1844+
#undef INSN
1845+
1846+
#define INSN(NAME, op29, opcode2, opcode) \
1847+
void NAME(Register Rd) { \
1848+
starti; \
1849+
f(opcode2, 20, 16); \
1850+
data_processing(current_insn, op29, opcode, Rd, dummy_reg); \
1851+
}
1852+
1853+
// PAC instructions (with zero modifier)
1854+
INSN(paciza, 0b110, 0b00001, 0b01000);
1855+
INSN(pacizb, 0b110, 0b00001, 0b01001);
1856+
INSN(pacdza, 0b110, 0b00001, 0b01010);
1857+
INSN(pacdzb, 0b110, 0b00001, 0b01011);
1858+
INSN(autiza, 0b110, 0b00001, 0b01100);
1859+
INSN(autizb, 0b110, 0b00001, 0b01101);
1860+
INSN(autdza, 0b110, 0b00001, 0b01110);
1861+
INSN(autdzb, 0b110, 0b00001, 0b01111);
1862+
INSN(xpaci, 0b110, 0b00001, 0b10000);
1863+
INSN(xpacd, 0b110, 0b00001, 0b10001);
1864+
17951865
#undef INSN
17961866

17971867
// (2 sources)

src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
33
* Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved.
44
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
55
*
@@ -385,6 +385,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
385385

386386
// load issuing PC (the return address for this stub) into r3
387387
__ ldr(exception_pc, Address(rfp, 1*BytesPerWord));
388+
__ authenticate_return_address(exception_pc, rscratch1);
388389

389390
// make sure that the vm_results are cleared (may be unnecessary)
390391
__ str(zr, Address(rthread, JavaThread::vm_result_offset()));
@@ -433,6 +434,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
433434
__ str(exception_pc, Address(rthread, JavaThread::exception_pc_offset()));
434435

435436
// patch throwing pc into return address (has bci & oop map)
437+
__ protect_return_address(exception_pc, rscratch1);
436438
__ str(exception_pc, Address(rfp, 1*BytesPerWord));
437439

438440
// compute the exception handler.
@@ -448,6 +450,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
448450
__ invalidate_registers(false, true, true, true, true, true);
449451

450452
// patch the return address, this stub will directly return to the exception handler
453+
__ protect_return_address(r0, rscratch1);
451454
__ str(r0, Address(rfp, 1*BytesPerWord));
452455

453456
switch (id) {
@@ -496,10 +499,12 @@ void Runtime1::generate_unwind_exception(StubAssembler *sasm) {
496499
// Save our return address because
497500
// exception_handler_for_return_address will destroy it. We also
498501
// save exception_oop
502+
__ mov(r3, lr);
503+
__ protect_return_address();
499504
__ stp(lr, exception_oop, Address(__ pre(sp, -2 * wordSize)));
500505

501506
// search the exception handler address of the caller (using the return address)
502-
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), rthread, lr);
507+
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), rthread, r3);
503508
// r0: exception handler address of the caller
504509

505510
// Only R0 is valid at this time; all other registers have been
@@ -512,6 +517,7 @@ void Runtime1::generate_unwind_exception(StubAssembler *sasm) {
512517
// get throwing pc (= return address).
513518
// lr has been destroyed by the call
514519
__ ldp(lr, exception_oop, Address(__ post(sp, 2 * wordSize)));
520+
__ authenticate_return_address();
515521
__ mov(r3, lr);
516522

517523
__ verify_not_null_oop(exception_oop);

0 commit comments

Comments
 (0)