8277204: Implement PAC-RET branch protection on Linux/AArch64

Reviewed-by: erikj, ihse, adinn, ngasson
This commit is contained in:
Alan Hayward 2022-02-24 16:38:56 +00:00 committed by Andrew Dinn
parent abc0ce11df
commit 6fab8a2d6a
35 changed files with 1446 additions and 904 deletions

View File

@ -135,6 +135,14 @@ space is required.
If you do not have access to sufficiently powerful hardware, it is also
possible to use [cross-compiling](#cross-compiling).
#### Branch Protection
In order to use Branch Protection features in the VM, `--enable-branch-protection`
must be used. This option requires C++ compiler support (GCC 9.1.0+ or Clang
10+). The resulting build can be run on both machines with and without support
for branch protection in hardware. Branch Protection is only supported for
Linux targets.
### Building on 32-bit arm
This is not recommended. Instead, see the section on [Cross-compiling](

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@ -803,17 +803,19 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP],
fi
AC_SUBST(FILE_MACRO_CFLAGS)
FLAGS_SETUP_BRANCH_PROTECTION
# EXPORT to API
CFLAGS_JVM_COMMON="$ALWAYS_CFLAGS_JVM $ALWAYS_DEFINES_JVM \
$TOOLCHAIN_CFLAGS_JVM ${$1_TOOLCHAIN_CFLAGS_JVM} \
$OS_CFLAGS $OS_CFLAGS_JVM $CFLAGS_OS_DEF_JVM $DEBUG_CFLAGS_JVM \
$WARNING_CFLAGS $WARNING_CFLAGS_JVM $JVM_PICFLAG $FILE_MACRO_CFLAGS \
$REPRODUCIBLE_CFLAGS"
$REPRODUCIBLE_CFLAGS $BRANCH_PROTECTION_CFLAGS"
CFLAGS_JDK_COMMON="$ALWAYS_CFLAGS_JDK $ALWAYS_DEFINES_JDK $TOOLCHAIN_CFLAGS_JDK \
$OS_CFLAGS $CFLAGS_OS_DEF_JDK $DEBUG_CFLAGS_JDK $DEBUG_OPTIONS_FLAGS_JDK \
$WARNING_CFLAGS $WARNING_CFLAGS_JDK $DEBUG_SYMBOLS_CFLAGS_JDK \
$FILE_MACRO_CFLAGS $REPRODUCIBLE_CFLAGS"
$FILE_MACRO_CFLAGS $REPRODUCIBLE_CFLAGS $BRANCH_PROTECTION_CFLAGS"
# Use ${$2EXTRA_CFLAGS} to block EXTRA_CFLAGS to be added to build flags.
# (Currently we don't have any OPENJDK_BUILD_EXTRA_CFLAGS, but that might
@ -879,3 +881,24 @@ AC_DEFUN([FLAGS_SETUP_GCC6_COMPILER_FLAGS],
PREFIX: $2, IF_FALSE: [NO_LIFETIME_DSE_CFLAG=""])
$1_GCC6_CFLAGS="${NO_DELETE_NULL_POINTER_CHECKS_CFLAG} ${NO_LIFETIME_DSE_CFLAG}"
])
AC_DEFUN_ONCE([FLAGS_SETUP_BRANCH_PROTECTION],
[
# Is branch protection available?
BRANCH_PROTECTION_AVAILABLE=false
BRANCH_PROTECTION_FLAG="-mbranch-protection=standard"
if test "x$OPENJDK_TARGET_CPU" = xaarch64; then
if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [${BRANCH_PROTECTION_FLAG}],
IF_TRUE: [BRANCH_PROTECTION_AVAILABLE=true])
fi
fi
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}])
AC_SUBST(BRANCH_PROTECTION_CFLAGS)
])

View File

@ -407,6 +407,7 @@ LIBFFI_CFLAGS:=@LIBFFI_CFLAGS@
ENABLE_LIBFFI_BUNDLING:=@ENABLE_LIBFFI_BUNDLING@
LIBFFI_LIB_FILE:=@LIBFFI_LIB_FILE@
FILE_MACRO_CFLAGS := @FILE_MACRO_CFLAGS@
BRANCH_PROTECTION_CFLAGS := @BRANCH_PROTECTION_CFLAGS@
STATIC_LIBS_CFLAGS := @STATIC_LIBS_CFLAGS@

View File

@ -1853,6 +1853,10 @@ void MachPrologNode::format(PhaseRegAlloc *ra_, outputStream *st) const {
if (C->output()->need_stack_bang(framesize))
st->print("# stack bang size=%d\n\t", framesize);
if (VM_Version::use_rop_protection()) {
st->print("ldr zr, [lr]\n\t");
st->print("pacia lr, rfp\n\t");
}
if (framesize < ((1 << 9) + 2 * wordSize)) {
st->print("sub sp, sp, #%d\n\t", framesize);
st->print("stp rfp, lr, [sp, #%d]", framesize - 2 * wordSize);
@ -1961,6 +1965,10 @@ void MachEpilogNode::format(PhaseRegAlloc *ra_, outputStream *st) const {
st->print("add sp, sp, rscratch1\n\t");
st->print("ldp lr, rfp, [sp],#%d\n\t", (2 * wordSize));
}
if (VM_Version::use_rop_protection()) {
st->print("autia lr, rfp\n\t");
st->print("ldr zr, [lr]\n\t");
}
if (do_polling() && C->is_method_compilation()) {
st->print("# test polling word\n\t");

View File

@ -987,33 +987,35 @@ public:
rf(rt, 0);
}
void hint(int imm) {
system(0b00, 0b011, 0b0010, 0b0000, imm);
// Hint instructions
#define INSN(NAME, crm, op2) \
void NAME() { \
system(0b00, 0b011, 0b0010, crm, op2); \
}
void nop() {
hint(0);
}
INSN(nop, 0b000, 0b0000);
INSN(yield, 0b000, 0b0001);
INSN(wfe, 0b000, 0b0010);
INSN(wfi, 0b000, 0b0011);
INSN(sev, 0b000, 0b0100);
INSN(sevl, 0b000, 0b0101);
void yield() {
hint(1);
}
INSN(autia1716, 0b0001, 0b100);
INSN(autiasp, 0b0011, 0b101);
INSN(autiaz, 0b0011, 0b100);
INSN(autib1716, 0b0001, 0b110);
INSN(autibsp, 0b0011, 0b111);
INSN(autibz, 0b0011, 0b110);
INSN(pacia1716, 0b0001, 0b000);
INSN(paciasp, 0b0011, 0b001);
INSN(paciaz, 0b0011, 0b000);
INSN(pacib1716, 0b0001, 0b010);
INSN(pacibsp, 0b0011, 0b011);
INSN(pacibz, 0b0011, 0b010);
INSN(xpaclri, 0b0000, 0b111);
void wfe() {
hint(2);
}
void wfi() {
hint(3);
}
void sev() {
hint(4);
}
void sevl() {
hint(5);
}
#undef INSN
// we only provide mrs and msr for the special purpose system
// registers where op1 (instr[20:19]) == 11 and, (currently) only
@ -1099,18 +1101,21 @@ public:
}
// Unconditional branch (register)
void branch_reg(Register R, int opc) {
void branch_reg(int OP, int A, int M, Register RN, Register RM) {
starti;
f(0b1101011, 31, 25);
f(opc, 24, 21);
f(0b11111000000, 20, 10);
rf(R, 5);
f(0b00000, 4, 0);
f(OP, 24, 21);
f(0b111110000, 20, 12);
f(A, 11, 11);
f(M, 10, 10);
rf(RN, 5);
rf(RM, 0);
}
#define INSN(NAME, opc) \
void NAME(Register R) { \
branch_reg(R, opc); \
#define INSN(NAME, opc) \
void NAME(Register RN) { \
branch_reg(opc, 0, 0, RN, r0); \
}
INSN(br, 0b0000);
@ -1121,14 +1126,48 @@ public:
#undef INSN
#define INSN(NAME, opc) \
void NAME() { \
branch_reg(dummy_reg, opc); \
#define INSN(NAME, opc) \
void NAME() { \
branch_reg(opc, 0, 0, dummy_reg, r0); \
}
INSN(eret, 0b0100);
INSN(drps, 0b0101);
#undef INSN
#define INSN(NAME, M) \
void NAME() { \
branch_reg(0b0010, 1, M, dummy_reg, dummy_reg); \
}
INSN(retaa, 0);
INSN(retab, 1);
#undef INSN
#define INSN(NAME, OP, M) \
void NAME(Register rn) { \
branch_reg(OP, 1, M, rn, dummy_reg); \
}
INSN(braaz, 0b0000, 0);
INSN(brabz, 0b0000, 1);
INSN(blraaz, 0b0001, 0);
INSN(blrabz, 0b0001, 1);
#undef INSN
#define INSN(NAME, OP, M) \
void NAME(Register rn, Register rm) { \
branch_reg(OP, 1, M, rn, rm); \
}
INSN(braa, 0b1000, 0);
INSN(brab, 0b1000, 1);
INSN(blraa, 0b1001, 0);
INSN(blrab, 0b1001, 1);
#undef INSN
// Load/store exclusive
@ -1792,6 +1831,37 @@ void mvnw(Register Rd, Register Rm,
INSN(clz, 0b110, 0b00000, 0b00100);
INSN(cls, 0b110, 0b00000, 0b00101);
// PAC instructions
INSN(pacia, 0b110, 0b00001, 0b00000);
INSN(pacib, 0b110, 0b00001, 0b00001);
INSN(pacda, 0b110, 0b00001, 0b00010);
INSN(pacdb, 0b110, 0b00001, 0b00011);
INSN(autia, 0b110, 0b00001, 0b00100);
INSN(autib, 0b110, 0b00001, 0b00101);
INSN(autda, 0b110, 0b00001, 0b00110);
INSN(autdb, 0b110, 0b00001, 0b00111);
#undef INSN
#define INSN(NAME, op29, opcode2, opcode) \
void NAME(Register Rd) { \
starti; \
f(opcode2, 20, 16); \
data_processing(current_insn, op29, opcode, Rd, dummy_reg); \
}
// PAC instructions (with zero modifier)
INSN(paciza, 0b110, 0b00001, 0b01000);
INSN(pacizb, 0b110, 0b00001, 0b01001);
INSN(pacdza, 0b110, 0b00001, 0b01010);
INSN(pacdzb, 0b110, 0b00001, 0b01011);
INSN(autiza, 0b110, 0b00001, 0b01100);
INSN(autizb, 0b110, 0b00001, 0b01101);
INSN(autdza, 0b110, 0b00001, 0b01110);
INSN(autdzb, 0b110, 0b00001, 0b01111);
INSN(xpaci, 0b110, 0b00001, 0b10000);
INSN(xpacd, 0b110, 0b00001, 0b10001);
#undef INSN
// (2 sources)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -385,6 +385,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
// load issuing PC (the return address for this stub) into r3
__ ldr(exception_pc, Address(rfp, 1*BytesPerWord));
__ authenticate_return_address(exception_pc, rscratch1);
// make sure that the vm_results are cleared (may be unnecessary)
__ str(zr, Address(rthread, JavaThread::vm_result_offset()));
@ -433,6 +434,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
__ str(exception_pc, Address(rthread, JavaThread::exception_pc_offset()));
// patch throwing pc into return address (has bci & oop map)
__ protect_return_address(exception_pc, rscratch1);
__ str(exception_pc, Address(rfp, 1*BytesPerWord));
// compute the exception handler.
@ -448,6 +450,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
__ invalidate_registers(false, true, true, true, true, true);
// patch the return address, this stub will directly return to the exception handler
__ protect_return_address(r0, rscratch1);
__ str(r0, Address(rfp, 1*BytesPerWord));
switch (id) {
@ -496,10 +499,12 @@ void Runtime1::generate_unwind_exception(StubAssembler *sasm) {
// Save our return address because
// exception_handler_for_return_address will destroy it. We also
// save exception_oop
__ mov(r3, lr);
__ protect_return_address();
__ stp(lr, exception_oop, Address(__ pre(sp, -2 * wordSize)));
// search the exception handler address of the caller (using the return address)
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), rthread, lr);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), rthread, r3);
// r0: exception handler address of the caller
// Only R0 is valid at this time; all other registers have been
@ -512,6 +517,7 @@ void Runtime1::generate_unwind_exception(StubAssembler *sasm) {
// get throwing pc (= return address).
// lr has been destroyed by the call
__ ldp(lr, exception_oop, Address(__ post(sp, 2 * wordSize)));
__ authenticate_return_address();
__ mov(r3, lr);
__ verify_not_null_oop(exception_oop);

View File

@ -128,13 +128,13 @@ bool frame::safe_for_sender(JavaThread *thread) {
return false;
}
sender_pc = (address) this->fp()[return_addr_offset];
// for interpreted frames, the value below is the sender "raw" sp,
// which can be different from the sender unextended sp (the sp seen
// by the sender) because of current frame local variables
sender_sp = (intptr_t*) addr_at(sender_sp_offset);
sender_unextended_sp = (intptr_t*) this->fp()[interpreter_frame_sender_sp_offset];
saved_fp = (intptr_t*) this->fp()[link_offset];
sender_pc = pauth_strip_verifiable((address) this->fp()[return_addr_offset], (address)saved_fp);
} else {
// must be some sort of compiled/runtime frame
@ -151,9 +151,9 @@ bool frame::safe_for_sender(JavaThread *thread) {
return false;
}
sender_unextended_sp = sender_sp;
sender_pc = (address) *(sender_sp-1);
// Note: frame::sender_sp_offset is only valid for compiled frame
saved_fp = (intptr_t*) *(sender_sp - frame::sender_sp_offset);
sender_pc = pauth_strip_verifiable((address) *(sender_sp-1), (address)saved_fp);
}
@ -268,17 +268,22 @@ bool frame::safe_for_sender(JavaThread *thread) {
void frame::patch_pc(Thread* thread, address pc) {
assert(_cb == CodeCache::find_blob(pc), "unexpected pc");
address* pc_addr = &(((address*) sp())[-1]);
address signing_sp = (((address*) sp())[-2]);
address signed_pc = pauth_sign_return_address(pc, (address)signing_sp);
address pc_old = pauth_strip_verifiable(*pc_addr, (address)signing_sp);
if (TracePcPatching) {
tty->print_cr("patch_pc at address " INTPTR_FORMAT " [" INTPTR_FORMAT " -> " INTPTR_FORMAT "]",
p2i(pc_addr), p2i(*pc_addr), p2i(pc));
tty->print("patch_pc at address " INTPTR_FORMAT " [" INTPTR_FORMAT " -> " INTPTR_FORMAT "]",
p2i(pc_addr), p2i(pc_old), p2i(pc));
if (VM_Version::use_rop_protection()) {
tty->print(" [signed " INTPTR_FORMAT " -> " INTPTR_FORMAT "]", p2i(*pc_addr), p2i(signed_pc));
}
tty->print_cr("");
}
// Only generated code frames should be patched, therefore the return address will not be signed.
assert(pauth_ptr_is_raw(*pc_addr), "cannot be signed");
// Either the return address is the original one or we are going to
// patch in the same address that's already there.
assert(_pc == *pc_addr || pc == *pc_addr, "must be");
*pc_addr = pc;
assert(_pc == pc_old || pc == pc_old, "must be");
*pc_addr = signed_pc;
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
assert(original_pc == _pc, "expected original PC to be stored before patching");
@ -455,12 +460,12 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
}
#endif // COMPILER2_OR_JVMCI
// Use the raw version of pc - the interpreter should not have signed it.
// For ROP protection, Interpreter will have signed the sender_pc, but there is no requirement to authenticate it here.
address sender_pc = pauth_strip_verifiable(sender_pc_maybe_signed(), (address)link());
return frame(sender_sp, unextended_sp, link(), sender_pc_maybe_signed());
return frame(sender_sp, unextended_sp, link(), sender_pc);
}
//------------------------------------------------------------------------------
// frame::sender_for_compiled_frame
frame frame::sender_for_compiled_frame(RegisterMap* map) const {
@ -482,7 +487,9 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const {
intptr_t* unextended_sp = l_sender_sp;
// the return_address is always the word on the stack
address sender_pc = (address) *(l_sender_sp-1);
// For ROP protection, C1/C2 will have signed the sender_pc, but there is no requirement to authenticate it here.
address sender_pc = pauth_strip_verifiable((address) *(l_sender_sp-1), (address) *(l_sender_sp-2));
intptr_t** saved_fp_addr = (intptr_t**) (l_sender_sp - frame::sender_sp_offset);
@ -530,6 +537,9 @@ frame frame::sender_raw(RegisterMap* map) const {
// Must be native-compiled frame, i.e. the marshaling code for native
// methods that exists in the core system.
// Native code may or may not have signed the return address, we have no way to be sure or what
// signing methods they used. Instead, just ensure the stripped value is used.
return frame(sender_sp(), link(), sender_pc());
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -271,7 +271,7 @@ void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorator
ModRefBarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread);
if (on_oop && on_reference) {
// LR is live. It must be saved around calls.
__ enter(); // barrier may call runtime
__ enter(/*strip_ret_addr*/true); // barrier may call runtime
// Generate the G1 pre-barrier code to log the value of
// the referent field in an SATB buffer.
g1_write_barrier_pre(masm /* masm */,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2021, Red Hat, Inc. All rights reserved.
* Copyright (c) 2018, 2022, Red Hat, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -237,7 +237,7 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm,
bool is_narrow = UseCompressedOops && !is_native;
Label heap_stable, not_cset;
__ enter();
__ enter(/*strip_ret_addr*/true);
Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
__ ldrb(rscratch2, gc_state);
@ -359,7 +359,7 @@ void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet d
// 3: apply keep-alive barrier if needed
if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) {
__ enter();
__ enter(/*strip_ret_addr*/true);
__ push_call_clobbered_registers();
satb_write_barrier_pre(masm /* masm */,
noreg /* obj */,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -78,7 +78,7 @@ void ZBarrierSetAssembler::load_at(MacroAssembler* masm,
__ tst(dst, rscratch1);
__ br(Assembler::EQ, done);
__ enter();
__ enter(/*strip_ret_addr*/true);
__ push_call_clobbered_registers_except(RegSet::of(dst));

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2019, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -118,7 +118,9 @@ define_pd_global(intx, InlineSmallCode, 1000);
product(uint, OnSpinWaitInstCount, 1, DIAGNOSTIC, \
"The number of OnSpinWaitInst instructions to generate." \
"It cannot be used with OnSpinWaitInst=none.") \
range(1, 99)
range(1, 99) \
product(ccstr, UseBranchProtection, "none", \
"Branch Protection to use: none, standard, pac-ret") \
// end of ARCH_FLAGS

View File

@ -1137,6 +1137,8 @@ void MacroAssembler::verify_oop(Register reg, const char* s) {
}
BLOCK_COMMENT("verify_oop {");
strip_return_address(); // This might happen within a stack frame.
protect_return_address();
stp(r0, rscratch1, Address(pre(sp, -2 * wordSize)));
stp(rscratch2, lr, Address(pre(sp, -2 * wordSize)));
@ -1150,6 +1152,7 @@ void MacroAssembler::verify_oop(Register reg, const char* s) {
ldp(rscratch2, lr, Address(post(sp, 2 * wordSize)));
ldp(r0, rscratch1, Address(post(sp, 2 * wordSize)));
authenticate_return_address();
BLOCK_COMMENT("} verify_oop");
}
@ -1166,6 +1169,8 @@ void MacroAssembler::verify_oop_addr(Address addr, const char* s) {
}
BLOCK_COMMENT("verify_oop_addr {");
strip_return_address(); // This might happen within a stack frame.
protect_return_address();
stp(r0, rscratch1, Address(pre(sp, -2 * wordSize)));
stp(rscratch2, lr, Address(pre(sp, -2 * wordSize)));
@ -1186,6 +1191,7 @@ void MacroAssembler::verify_oop_addr(Address addr, const char* s) {
ldp(rscratch2, lr, Address(post(sp, 2 * wordSize)));
ldp(r0, rscratch1, Address(post(sp, 2 * wordSize)));
authenticate_return_address();
BLOCK_COMMENT("} verify_oop_addr");
}
@ -4296,6 +4302,7 @@ void MacroAssembler::load_byte_map_base(Register reg) {
void MacroAssembler::build_frame(int framesize) {
assert(framesize >= 2 * wordSize, "framesize must include space for FP/LR");
assert(framesize % (2*wordSize) == 0, "must preserve 2*wordSize alignment");
protect_return_address();
if (framesize < ((1 << 9) + 2 * wordSize)) {
sub(sp, sp, framesize);
stp(rfp, lr, Address(sp, framesize - 2 * wordSize));
@ -4328,6 +4335,7 @@ void MacroAssembler::remove_frame(int framesize) {
}
ldp(rfp, lr, Address(post(sp, 2 * wordSize)));
}
authenticate_return_address();
}
@ -5169,6 +5177,7 @@ void MacroAssembler::get_thread(Register dst) {
LINUX_ONLY(RegSet::range(r0, r1) + lr - dst)
NOT_LINUX (RegSet::range(r0, r17) + lr - dst);
protect_return_address();
push(saved_regs, sp);
mov(lr, CAST_FROM_FN_PTR(address, JavaThread::aarch64_get_thread_helper));
@ -5178,6 +5187,7 @@ void MacroAssembler::get_thread(Register dst) {
}
pop(saved_regs, sp);
authenticate_return_address();
}
void MacroAssembler::cache_wb(Address line) {
@ -5269,3 +5279,102 @@ void MacroAssembler::spin_wait() {
}
}
}
// Stack frame creation/removal
void MacroAssembler::enter(bool strip_ret_addr) {
if (strip_ret_addr) {
// Addresses can only be signed once. If there are multiple nested frames being created
// in the same function, then the return address needs stripping first.
strip_return_address();
}
protect_return_address();
stp(rfp, lr, Address(pre(sp, -2 * wordSize)));
mov(rfp, sp);
}
void MacroAssembler::leave() {
mov(sp, rfp);
ldp(rfp, lr, Address(post(sp, 2 * wordSize)));
authenticate_return_address();
}
// ROP Protection
// Use the AArch64 PAC feature to add ROP protection for generated code. Use whenever creating/
// destroying stack frames or whenever directly loading/storing the LR to memory.
// If ROP protection is not set then these functions are no-ops.
// For more details on PAC see pauth_aarch64.hpp.
// Sign the LR. Use during construction of a stack frame, before storing the LR to memory.
// Uses the FP as the modifier.
//
void MacroAssembler::protect_return_address() {
if (VM_Version::use_rop_protection()) {
check_return_address();
// The standard convention for C code is to use paciasp, which uses SP as the modifier. This
// works because in C code, FP and SP match on function entry. In the JDK, SP and FP may not
// match, so instead explicitly use the FP.
pacia(lr, rfp);
}
}
// Sign the return value in the given register. Use before updating the LR in the exisiting stack
// frame for the current function.
// Uses the FP from the start of the function as the modifier - which is stored at the address of
// the current FP.
//
void MacroAssembler::protect_return_address(Register return_reg, Register temp_reg) {
if (VM_Version::use_rop_protection()) {
assert(PreserveFramePointer, "PreserveFramePointer must be set for ROP protection");
check_return_address(return_reg);
ldr(temp_reg, Address(rfp));
pacia(return_reg, temp_reg);
}
}
// Authenticate the LR. Use before function return, after restoring FP and loading LR from memory.
//
void MacroAssembler::authenticate_return_address(Register return_reg) {
if (VM_Version::use_rop_protection()) {
autia(return_reg, rfp);
check_return_address(return_reg);
}
}
// Authenticate the return value in the given register. Use before updating the LR in the exisiting
// stack frame for the current function.
// Uses the FP from the start of the function as the modifier - which is stored at the address of
// the current FP.
//
void MacroAssembler::authenticate_return_address(Register return_reg, Register temp_reg) {
if (VM_Version::use_rop_protection()) {
assert(PreserveFramePointer, "PreserveFramePointer must be set for ROP protection");
ldr(temp_reg, Address(rfp));
autia(return_reg, temp_reg);
check_return_address(return_reg);
}
}
// Strip any PAC data from LR without performing any authentication. Use with caution - only if
// there is no guaranteed way of authenticating the LR.
//
void MacroAssembler::strip_return_address() {
if (VM_Version::use_rop_protection()) {
xpaclri();
}
}
#ifndef PRODUCT
// PAC failures can be difficult to debug. After an authentication failure, a segfault will only
// occur when the pointer is used - ie when the program returns to the invalid LR. At this point
// it is difficult to debug back to the callee function.
// This function simply loads from the address in the given register.
// Use directly after authentication to catch authentication failures.
// Also use before signing to check that the pointer is valid and hasn't already been signed.
//
void MacroAssembler::check_return_address(Register return_reg) {
if (VM_Version::use_rop_protection()) {
ldr(zr, Address(return_reg));
}
}
#endif

View File

@ -688,16 +688,16 @@ public:
void align(int modulus);
// Stack frame creation/removal
void enter()
{
stp(rfp, lr, Address(pre(sp, -2 * wordSize)));
mov(rfp, sp);
}
void leave()
{
mov(sp, rfp);
ldp(rfp, lr, Address(post(sp, 2 * wordSize)));
}
void enter(bool strip_ret_addr = false);
void leave();
// ROP Protection
void protect_return_address();
void protect_return_address(Register return_reg, Register temp_reg);
void authenticate_return_address(Register return_reg = lr);
void authenticate_return_address(Register return_reg, Register temp_reg);
void strip_return_address();
void check_return_address(Register return_reg=lr) PRODUCT_RETURN;
// Support for getting the JavaThread pointer (i.e.; a reference to thread-local information)
// The pointer will be loaded into the thread register.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Arm Limited. All rights reserved.
* Copyright (c) 2021, 2022, Arm Limited. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,9 +27,58 @@
#include OS_CPU_HEADER_INLINE(pauth)
// Support for ROP Protection in VM code.
// This is provided via the AArch64 PAC feature.
// For more details on PAC see The Arm ARM, section "Pointer authentication in AArch64 state".
//
// PAC provides a method to sign and authenticate pointer values. Signing combines the register
// being signed, an additional modifier and a per-process secret key, writing the result to unused
// high bits of the signed register. Once signed a register must be authenticated or stripped
// before it can be used.
// Authentication reverses the signing operation, clearing the high bits. If the signed register
// or modifier has changed then authentication will fail and invalid data will be written to the
// high bits and the next time the pointer is used a segfault will be raised.
//
// Assume a malicious attacker is able to edit the stack via an exploit. Control flow can be
// changed by re-writing the return values stored on the stack. ROP protection prevents this by
// signing return addresses before saving them on the stack, then authenticating when they are
// loaded back. The scope of this protection is per function (a value is signed and authenticated
// by the same function), therefore it is possible for different functions within the same
// program to use different signing methods.
//
// The VM and native code is protected by compiling with the GCC AArch64 branch protection flag.
//
// All generated code is protected via the ROP functions provided in macroAssembler.
//
// In addition, the VM needs to be aware of PAC whenever viewing or editing the stack. Functions
// are provided here and in the OS specific files. We should assume all stack frames for generated
// code have signed return values. Rewriting the stack should ensure new values are correctly
// signed. However, we cannot make any assumptions about how (or if) native code uses PAC - here
// we should limit access to viewing via stripping.
//
// Confirm the given pointer has not been signed - ie none of the high bits are set.
//
// Note this can give false positives. The PAC signing can generate a signature with all signing
// bits as zeros, causing this function to return true. Therefore this should only be used for
// assert style checking. In addition, this function should never be used with a "not" to confirm
// a pointer is signed, as it will fail the above case. The only safe way to do this is to instead
// authenticate the pointer.
//
inline bool pauth_ptr_is_raw(address ptr) {
// Confirm none of the high bits are set in the pointer.
return ptr == pauth_strip_pointer(ptr);
}
// Strip a return value (same as pauth_strip_pointer). When debug is enabled then authenticate
// instead.
//
inline address pauth_strip_verifiable(address ret_addr, address modifier) {
if (VM_Version::use_rop_protection()) {
DEBUG_ONLY(ret_addr = pauth_authenticate_return_address(ret_addr, modifier);)
NOT_DEBUG(ret_addr = pauth_strip_pointer(ret_addr));
}
return ret_addr;
}
#endif // CPU_AARCH64_PAUTH_AARCH64_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved.
* Copyright (c) 2021, Azul Systems, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@ -410,6 +410,7 @@ static void patch_callers_callsite(MacroAssembler *masm) {
__ mov(c_rarg0, rmethod);
__ mov(c_rarg1, lr);
__ authenticate_return_address(c_rarg1, rscratch1);
__ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::fixup_callers_callsite)));
__ blr(rscratch1);
@ -2178,8 +2179,8 @@ void SharedRuntime::generate_deopt_blob() {
// load throwing pc from JavaThread and patch it as the return address
// of the current frame. Then clear the field in JavaThread
__ ldr(r3, Address(rthread, JavaThread::exception_pc_offset()));
__ protect_return_address(r3, rscratch1);
__ str(r3, Address(rfp, wordSize));
__ str(zr, Address(rthread, JavaThread::exception_pc_offset()));
@ -2287,6 +2288,7 @@ void SharedRuntime::generate_deopt_blob() {
__ sub(r2, r2, 2 * wordSize);
__ add(sp, sp, r2);
__ ldp(rfp, lr, __ post(sp, 2 * wordSize));
__ authenticate_return_address();
// LR should now be the return address to the caller (3)
#ifdef ASSERT
@ -2428,6 +2430,7 @@ void SharedRuntime::generate_uncommon_trap_blob() {
// Push self-frame. We get here with a return address in LR
// and sp should be 16 byte aligned
// push rfp and retaddr by hand
__ protect_return_address();
__ stp(rfp, lr, Address(__ pre(sp, -2 * wordSize)));
// we don't expect an arg reg save area
#ifndef PRODUCT
@ -2502,6 +2505,7 @@ void SharedRuntime::generate_uncommon_trap_blob() {
__ sub(r2, r2, 2 * wordSize);
__ add(sp, sp, r2);
__ ldp(rfp, lr, __ post(sp, 2 * wordSize));
__ authenticate_return_address();
// LR should now be the return address to the caller (3) frame
#ifdef ASSERT
@ -2624,6 +2628,11 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t
bool cause_return = (poll_type == POLL_AT_RETURN);
RegisterSaver reg_save(poll_type == POLL_AT_VECTOR_LOOP /* save_vectors */);
// When the signal occured, the LR was either signed and stored on the stack (in which
// case it will be restored from the stack before being used) or unsigned and not stored
// on the stack. Stipping ensures we get the right value.
__ strip_return_address();
// Save Integer and Float registers.
map = reg_save.save_live_registers(masm, 0, &frame_size_in_words);
@ -2643,6 +2652,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t
// it later to determine if someone changed the return address for
// us!
__ ldr(r20, Address(rthread, JavaThread::saved_exception_pc_offset()));
__ protect_return_address(r20, rscratch1);
__ str(r20, Address(rfp, wordSize));
}
@ -2683,6 +2693,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t
__ ldr(rscratch1, Address(rfp, wordSize));
__ cmp(r20, rscratch1);
__ br(Assembler::NE, no_adjust);
__ authenticate_return_address(r20, rscratch1);
#ifdef ASSERT
// Verify the correct encoding of the poll we're about to skip.
@ -2697,6 +2708,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t
#endif
// Adjust return pc forward to step over the safepoint poll instruction
__ add(r20, r20, NativeInstruction::instruction_size);
__ protect_return_address(r20, rscratch1);
__ str(r20, Address(rfp, wordSize));
}
@ -2857,6 +2869,7 @@ void OptoRuntime::generate_exception_blob() {
// push rfp and retaddr by hand
// Exception pc is 'return address' for stack walker
__ protect_return_address();
__ stp(rfp, lr, Address(__ pre(sp, -2 * wordSize)));
// there are no callee save registers and we don't expect an
// arg reg save area
@ -2910,6 +2923,7 @@ void OptoRuntime::generate_exception_blob() {
// there are no callee save registers now that adapter frames are gone.
// and we dont' expect an arg reg save area
__ ldp(rfp, r3, Address(__ post(sp, 2 * wordSize)));
__ authenticate_return_address(r3);
// r0: exception handler

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -832,6 +832,7 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
__ ldr(rcpool, Address(rcpool, ConstantPool::cache_offset_in_bytes()));
__ stp(rlocals, rcpool, Address(sp, 2 * wordSize));
__ protect_return_address();
__ stp(rfp, lr, Address(sp, 10 * wordSize));
__ lea(rfp, Address(sp, 10 * wordSize));
@ -1748,6 +1749,8 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
// adapter frames in C2.
Label caller_not_deoptimized;
__ ldr(c_rarg1, Address(rfp, frame::return_addr_offset * wordSize));
// This is a return address, so requires authenticating for PAC.
__ authenticate_return_address(c_rarg1, rscratch1);
__ super_call_VM_leaf(CAST_FROM_FN_PTR(address,
InterpreterRuntime::interpreter_contains), c_rarg1);
__ cbnz(r0, caller_not_deoptimized);
@ -1937,6 +1940,7 @@ void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t,
address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
address entry = __ pc();
__ protect_return_address();
__ push(lr);
__ push(state);
__ push(RegSet::range(r0, r15), sp);
@ -1947,6 +1951,7 @@ address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
__ pop(RegSet::range(r0, r15), sp);
__ pop(state);
__ pop(lr);
__ authenticate_return_address();
__ ret(lr); // return from result handler
return entry;

View File

@ -45,6 +45,7 @@ int VM_Version::_zva_length;
int VM_Version::_dcache_line_size;
int VM_Version::_icache_line_size;
int VM_Version::_initial_sve_vector_length;
bool VM_Version::_rop_protection;
SpinWait VM_Version::_spin_wait;
@ -409,6 +410,39 @@ void VM_Version::initialize() {
UsePopCountInstruction = true;
}
if (UseBranchProtection == nullptr || strcmp(UseBranchProtection, "none") == 0) {
_rop_protection = false;
} else if (strcmp(UseBranchProtection, "standard") == 0) {
_rop_protection = false;
// Enable PAC if this code has been built with branch-protection and the CPU/OS supports it.
#ifdef __ARM_FEATURE_PAC_DEFAULT
if ((_features & CPU_PACA) != 0) {
_rop_protection = true;
}
#endif
} else if (strcmp(UseBranchProtection, "pac-ret") == 0) {
_rop_protection = true;
#ifdef __ARM_FEATURE_PAC_DEFAULT
if ((_features & CPU_PACA) == 0) {
warning("ROP-protection specified, but not supported on this CPU.");
// Disable PAC to prevent illegal instruction crashes.
_rop_protection = false;
}
#else
warning("ROP-protection specified, but this VM was built without ROP-protection support.");
#endif
} else {
vm_exit_during_initialization(err_msg("Unsupported UseBranchProtection: %s", UseBranchProtection));
}
// The frame pointer must be preserved for ROP protection.
if (_rop_protection == true) {
if (FLAG_IS_DEFAULT(PreserveFramePointer) == false && PreserveFramePointer == false ) {
vm_exit_during_initialization(err_msg("PreserveFramePointer cannot be disabled for ROP-protection"));
}
PreserveFramePointer = true;
}
#ifdef COMPILER2
if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
UseMultiplyToLenIntrinsic = true;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -45,6 +45,7 @@ protected:
static int _dcache_line_size;
static int _icache_line_size;
static int _initial_sve_vector_length;
static bool _rop_protection;
static SpinWait _spin_wait;
@ -114,10 +115,11 @@ public:
decl(SHA3, "sha3", 17) \
decl(SHA512, "sha512", 21) \
decl(SVE, "sve", 22) \
decl(PACA, "paca", 30) \
/* flags above must follow Linux HWCAP */ \
decl(SVE2, "sve2", 28) \
decl(STXR_PREFETCH, "stxr_prefetch", 29) \
decl(A53MAC, "a53mac", 30)
decl(A53MAC, "a53mac", 31)
#define DECLARE_CPU_FEATURE_FLAG(id, name, bit) CPU_##id = (1 << bit),
CPU_FEATURE_FLAGS(DECLARE_CPU_FEATURE_FLAG)
@ -156,6 +158,7 @@ public:
static void initialize_cpu_information(void);
static bool use_rop_protection() { return _rop_protection; }
};
#endif // CPU_AARCH64_VM_VERSION_AARCH64_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Arm Limited. All rights reserved.
* Copyright (c) 2021, 2022, Arm Limited. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,29 +25,23 @@
#ifndef OS_CPU_BSD_AARCH64_PAUTH_BSD_AARCH64_INLINE_HPP
#define OS_CPU_BSD_AARCH64_PAUTH_BSD_AARCH64_INLINE_HPP
#ifdef __APPLE__
#include <ptrauth.h>
#endif
// Only the PAC instructions in the NOP space can be used. This ensures the
// binaries work on systems without PAC. Write these instructions using their
// alternate "hint" instructions to ensure older compilers can still be used.
// For Apple, use the provided interface as this may provide additional
// optimization.
#define XPACLRI "hint #0x7;"
// OS specific Support for ROP Protection in VM code.
// For more details on PAC see pauth_aarch64.hpp.
inline address pauth_strip_pointer(address ptr) {
#ifdef __APPLE__
return ptrauth_strip(ptr, ptrauth_key_asib);
#else
register address result __asm__("x30") = ptr;
asm (XPACLRI : "+r"(result));
return result;
#endif
// No PAC support in BSD as of yet.
return ptr;
}
#undef XPACLRI
inline address pauth_sign_return_address(address ret_addr, address sp) {
// No PAC support in BSD as of yet.
return ret_addr;
}
inline address pauth_authenticate_return_address(address ret_addr, address sp) {
// No PAC support in BSD as of yet.
return ret_addr;
}
#endif // OS_CPU_BSD_AARCH64_PAUTH_BSD_AARCH64_INLINE_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Arm Limited. All rights reserved.
* Copyright (c) 2021, 2022, Arm Limited. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,18 +25,57 @@
#ifndef OS_CPU_LINUX_AARCH64_PAUTH_LINUX_AARCH64_INLINE_HPP
#define OS_CPU_LINUX_AARCH64_PAUTH_LINUX_AARCH64_INLINE_HPP
// Only the PAC instructions in the NOP space can be used. This ensures the
// binaries work on systems without PAC. Write these instructions using their
// alternate "hint" instructions to ensure older compilers can still be used.
// OS specific Support for ROP Protection in VM code.
// For more details on PAC see pauth_aarch64.hpp.
#define XPACLRI "hint #0x7;"
inline bool pauth_ptr_is_raw(address ptr);
// Use only the PAC instructions in the NOP space. This ensures the binaries work on systems
// without PAC. Write these instructions using their alternate "hint" instructions to ensure older
// compilers can still be used.
#define XPACLRI "hint #0x7;"
#define PACIA1716 "hint #0x8;"
#define AUTIA1716 "hint #0xc;"
// Strip an address. Use with caution - only if there is no guaranteed way of authenticating the
// value.
//
inline address pauth_strip_pointer(address ptr) {
register address result __asm__("x30") = ptr;
asm (XPACLRI : "+r"(result));
return result;
}
// Sign a return value, using the given modifier.
//
inline address pauth_sign_return_address(address ret_addr, address sp) {
if (VM_Version::use_rop_protection()) {
// A pointer cannot be double signed.
guarantee(pauth_ptr_is_raw(ret_addr), "Return address is already signed");
register address r17 __asm("r17") = ret_addr;
register address r16 __asm("r16") = sp;
asm (PACIA1716 : "+r"(r17) : "r"(r16));
ret_addr = r17;
}
return ret_addr;
}
// Authenticate a return value, using the given modifier.
//
inline address pauth_authenticate_return_address(address ret_addr, address sp) {
if (VM_Version::use_rop_protection()) {
register address r17 __asm("r17") = ret_addr;
register address r16 __asm("r16") = sp;
asm (AUTIA1716 : "+r"(r17) : "r"(r16));
ret_addr = r17;
// Ensure that the pointer authenticated.
guarantee(pauth_ptr_is_raw(ret_addr), "Return address did not authenticate");
}
return ret_addr;
}
#undef XPACLRI
#undef PACIA1716
#undef AUTIA1716
#endif // OS_CPU_LINUX_AARCH64_PAUTH_LINUX_AARCH64_INLINE_HPP

View File

@ -1,4 +1,4 @@
// Copyright (c) 2015, Red Hat Inc. All rights reserved.
// Copyright (c) 2015, 2022, Red Hat Inc. All rights reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
// This code is free software; you can redistribute it and/or modify it
@ -29,6 +29,7 @@
.type _ZN10JavaThread25aarch64_get_thread_helperEv, %function
_ZN10JavaThread25aarch64_get_thread_helperEv:
hint #0x19 // paciasp
stp x29, x30, [sp, -16]!
adrp x0, :tlsdesc:_ZN6Thread12_thr_currentE
ldr x1, [x0, #:tlsdesc_lo12:_ZN6Thread12_thr_currentE]
@ -39,6 +40,7 @@ _ZN10JavaThread25aarch64_get_thread_helperEv:
add x0, x1, x0
ldr x0, [x0]
ldp x29, x30, [sp], 16
hint #0x1d // autiasp
ret
.size _ZN10JavaThread25aarch64_get_thread_helperEv, .-_ZN10JavaThread25aarch64_get_thread_helperEv

View File

@ -72,6 +72,10 @@
#define HWCAP_SVE (1 << 22)
#endif
#ifndef HWCAP_PACA
#define HWCAP_PACA (1 << 30)
#endif
#ifndef HWCAP2_SVE2
#define HWCAP2_SVE2 (1 << 1)
#endif
@ -111,6 +115,7 @@ void VM_Version::get_os_cpu_info() {
static_assert(CPU_SHA3 == HWCAP_SHA3, "Flag CPU_SHA3 must follow Linux HWCAP");
static_assert(CPU_SHA512 == HWCAP_SHA512, "Flag CPU_SHA512 must follow Linux HWCAP");
static_assert(CPU_SVE == HWCAP_SVE, "Flag CPU_SVE must follow Linux HWCAP");
static_assert(CPU_PACA == HWCAP_PACA, "Flag CPU_PACA must follow Linux HWCAP");
_features = auxv & (
HWCAP_FP |
HWCAP_ASIMD |
@ -124,7 +129,8 @@ void VM_Version::get_os_cpu_info() {
HWCAP_DCPOP |
HWCAP_SHA3 |
HWCAP_SHA512 |
HWCAP_SVE);
HWCAP_SVE |
HWCAP_PACA);
if (auxv2 & HWCAP2_SVE2) _features |= CPU_SVE2;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Arm Limited. All rights reserved.
* Copyright (c) 2021, 2022, Arm Limited. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,10 +25,22 @@
#ifndef OS_CPU_WINDOWS_AARCH64_PAUTH_WINDOWS_AARCH64_INLINE_HPP
#define OS_CPU_WINDOWS_AARCH64_PAUTH_WINDOWS_AARCH64_INLINE_HPP
// OS specific Support for ROP Protection in VM code.
// For more details on PAC see pauth_aarch64.hpp.
inline address pauth_strip_pointer(address ptr) {
// No PAC support in windows as of yet.
return ptr;
}
#endif // OS_CPU_WINDOWS_AARCH64_PAUTH_WINDOWS_AARCH64_INLINE_HPP
inline address pauth_sign_return_address(address ret_addr, address sp) {
// No PAC support in windows as of yet.
return ret_addr;
}
inline address pauth_authenticate_return_address(address ret_addr, address sp) {
// No PAC support in windows as of yet.
return ret_addr;
}
#endif // OS_CPU_WINDOWS_AARCH64_PAUTH_WINDOWS_AARCH64_INLINE_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,6 +28,7 @@
#include "gc/shared/barrierSet.hpp"
#include "gc/shared/barrierSetNMethod.hpp"
#include "logging/log.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/thread.hpp"
#include "runtime/threadWXSetters.inline.hpp"
#include "utilities/debug.hpp"
@ -54,6 +55,7 @@ int BarrierSetNMethod::nmethod_stub_entry_barrier(address* return_address_ptr) {
MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, Thread::current()));
address return_address = *return_address_ptr;
AARCH64_ONLY(return_address = pauth_strip_pointer(return_address));
CodeBlob* cb = CodeCache::find_blob(return_address);
assert(cb != NULL, "invariant");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -744,6 +744,7 @@
static_field(VM_Version, _zva_length, int) \
static_field(StubRoutines::aarch64, _has_negatives, address) \
static_field(StubRoutines::aarch64, _has_negatives_long, address) \
static_field(VM_Version, _rop_protection, bool) \
volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*)
#define DECLARE_INT_CPU_FEATURE_CONSTANT(id, name, bit) GENERATE_VM_INT_CONSTANT_ENTRY(VM_Version::CPU_##id)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -1465,6 +1465,12 @@ address OptoRuntime::rethrow_C(oopDesc* exception, JavaThread* thread, address r
// Enable WXWrite: the function called directly by compiled code.
MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, thread));
// ret_pc will have been loaded from the stack, so for AArch64 will be signed.
// This needs authenticating, but to do that here requires the fp of the previous frame.
// A better way of doing it would be authenticate in the caller by adding a
// AuthPAuthNode and using it in GraphKit::gen_stub. For now, just strip it.
AARCH64_ONLY(ret_pc = pauth_strip_pointer(ret_pc));
#ifndef PRODUCT
SharedRuntime::_rethrow_ctr++; // count rethrows
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -1110,6 +1110,11 @@ void frame::verify(const RegisterMap* map) const {
#ifdef ASSERT
bool frame::verify_return_pc(address x) {
#ifdef AARCH64
if (!pauth_ptr_is_raw(x)) {
return false;
}
#endif
if (StubRoutines::returns_to_call_stub(x)) {
return true;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -1947,6 +1947,8 @@ bool SharedRuntime::should_fixup_call_destination(address destination, address e
JRT_LEAF(void, SharedRuntime::fixup_callers_callsite(Method* method, address caller_pc))
Method* moop(method);
AARCH64_ONLY(assert(pauth_ptr_is_raw(caller_pc), "should be raw"));
address entry_point = moop->from_compiled_entry_no_trampoline();
// It's possible that deoptimization can occur at a call site which hasn't

View File

@ -1981,6 +1981,32 @@ Allows user to specify VM options in a file, for example,
\f[CB]java\ \-XX:VMOptionsFile=/var/my_vm_options\ HelloWorld\f[R].
.RS
.RE
.TP
.B \f[CB]\-XX:UseBranchProtection=\f[R]\f[I]mode\f[R]
Specifies the branch protection mode. All options other than none require
the VM to have been built with branch protection enabled. In addition, for
full protection, any native libraries provided by applications should be
compiled with the same level of protection. (AArch64 Linux only).
.RS
.PP
Possible \f[I]mode\f[R] arguments for this option include the
following:
.RS
.TP
.B \f[CB]none\f[R]
Do not use branch protection. This is the default value.
.RS
.RE
.TP
.B \f[CB]standard\f[R]
Enables all branch protection modes available on the current platform.
.RS
.RE
.TP
.B \f[CB]pac-ret\f[R]
Enables protection against ROP based attacks. (AArch64 8.3+ only)
.RS
.RE
.SH ADVANCED JIT COMPILER OPTIONS FOR JAVA
.PP
These \f[CB]java\f[R] options control the dynamic just\-in\-time (JIT)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -177,6 +177,7 @@ public class AArch64 extends Architecture {
SHA3,
SHA512,
SVE,
PACA,
SVE2,
STXR_PREFETCH,
A53MAC,

View File

@ -209,15 +209,17 @@ class Instruction(object):
self._name = name
self.isWord = name.endswith("w") | name.endswith("wi")
self.asmRegPrefix = ["x", "w"][self.isWord]
self.isPostfixException = False
def aname(self):
if (self._name.endswith("wi")):
if self.isPostfixException:
return self._name
elif (self._name.endswith("wi")):
return self._name[:len(self._name)-2]
elif (self._name.endswith("i") | self._name.endswith("w")):
return self._name[:len(self._name)-1]
else:
if (self._name.endswith("i") | self._name.endswith("w")):
return self._name[:len(self._name)-1]
else:
return self._name
return self._name
def emit(self) :
pass
@ -348,6 +350,12 @@ class OneRegOp(Instruction):
return (super(OneRegOp, self).astr()
+ '%s' % self.reg.astr(self.asmRegPrefix))
class PostfixExceptionOneRegOp(OneRegOp):
def __init__(self, op):
OneRegOp.__init__(self, op)
self.isPostfixException=True
class ArithOp(ThreeRegInstruction):
def generate(self):
@ -597,6 +605,13 @@ class Op(Instruction):
def astr(self):
return self.aname();
class PostfixExceptionOp(Op):
def __init__(self, op):
Op.__init__(self, op)
self.isPostfixException=True
class SystemOp(Instruction):
def __init__(self, op):
@ -1335,14 +1350,26 @@ generate (CondBranchOp, ["EQ", "NE", "HS", "CS", "LO", "CC", "MI", "PL", "VS", "
generate (ImmOp, ["svc", "hvc", "smc", "brk", "hlt", # "dcps1", "dcps2", "dcps3"
])
generate (Op, ["nop", "eret", "drps", "isb"])
generate (Op, ["nop", "yield", "wfe", "sev", "sevl",
"autia1716", "autiasp", "autiaz", "autib1716", "autibsp", "autibz",
"pacia1716", "paciasp", "paciaz", "pacib1716", "pacibsp", "pacibz",
"eret", "drps", "isb",])
# Ensure the "i" is not stripped off the end of the instruction
generate (PostfixExceptionOp, ["wfi", "xpaclri"])
barriers = ["OSHLD", "OSHST", "OSH", "NSHLD", "NSHST", "NSH",
"ISHLD", "ISHST", "ISH", "LD", "ST", "SY"]
generate (SystemOp, [["dsb", barriers], ["dmb", barriers]])
generate (OneRegOp, ["br", "blr"])
generate (OneRegOp, ["br", "blr",
"paciza", "pacizb", "pacdza", "pacdzb",
"autiza", "autizb", "autdza", "autdzb", "xpacd",
"braaz", "brabz", "blraaz", "blrabz"])
# Ensure the "i" is not stripped off the end of the instruction
generate (PostfixExceptionOneRegOp, ["xpaci"])
for mode in 'xwhb':
generate (LoadStoreExclusiveOp, [["stxr", mode, 3], ["stlxr", mode, 3],
@ -1387,7 +1414,10 @@ generate(ConditionalSelectOp,
generate(TwoRegOp,
["rbitw", "rev16w", "revw", "clzw", "clsw", "rbit",
"rev16", "rev32", "rev", "clz", "cls"])
"rev16", "rev32", "rev", "clz", "cls",
"pacia", "pacib", "pacda", "pacdb", "autia", "autib", "autda", "autdb",
"braa", "brab", "blraa", "blrab"])
generate(ThreeRegOp,
["udivw", "sdivw", "lslvw", "lsrvw", "asrvw", "rorvw", "udiv", "sdiv",
"lslv", "lsrv", "asrv", "rorv", "umulh", "smulh"])
@ -1839,8 +1869,8 @@ outfile.write("forth:\n")
outfile.close()
# compile for sve with 8.2 and sha3 because of SHA3 crypto extension.
subprocess.check_call([AARCH64_AS, "-march=armv8.2-a+sha3+sve", "aarch64ops.s", "-o", "aarch64ops.o"])
# compile for sve with 8.3 and sha3 because of SHA3 crypto extension.
subprocess.check_call([AARCH64_AS, "-march=armv8.3-a+sha3+sve", "aarch64ops.s", "-o", "aarch64ops.o"])
print
print "/*"

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -54,6 +54,7 @@ public class CodeInstallationTest {
protected final TargetDescription target;
protected final ConstantReflectionProvider constantReflection;
protected final TestHotSpotVMConfig config;
protected final Architecture arch;
public CodeInstallationTest() {
JVMCIBackend backend = JVMCI.getRuntime().getHostJVMCIBackend();
@ -61,7 +62,8 @@ public class CodeInstallationTest {
codeCache = backend.getCodeCache();
target = backend.getTarget();
constantReflection = backend.getConstantReflection();
config = new TestHotSpotVMConfig(HotSpotJVMCIRuntime.runtime().getConfigStore());
arch = codeCache.getTarget().arch;
config = new TestHotSpotVMConfig(HotSpotJVMCIRuntime.runtime().getConfigStore(), arch);
}
protected interface TestCompiler {
@ -70,7 +72,6 @@ public class CodeInstallationTest {
}
private TestAssembler createAssembler() {
Architecture arch = codeCache.getTarget().arch;
if (arch instanceof AMD64) {
return new AMD64TestAssembler(codeCache, config);
} else if (arch instanceof AArch64) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -22,13 +22,16 @@
*/
package jdk.vm.ci.code.test;
import jdk.vm.ci.aarch64.AArch64;
import jdk.vm.ci.code.Architecture;
import jdk.vm.ci.hotspot.HotSpotVMConfigAccess;
import jdk.vm.ci.hotspot.HotSpotVMConfigStore;
public class TestHotSpotVMConfig extends HotSpotVMConfigAccess {
public TestHotSpotVMConfig(HotSpotVMConfigStore config) {
public TestHotSpotVMConfig(HotSpotVMConfigStore config, Architecture arch) {
super(config);
ropProtection = (arch instanceof AArch64) ? getFieldValue("VM_Version::_rop_protection", Boolean.class) : false;
}
public final boolean useCompressedOops = getFlag("UseCompressedOops", Boolean.class);
@ -48,4 +51,6 @@ public class TestHotSpotVMConfig extends HotSpotVMConfigAccess {
public final int maxOopMapStackOffset = getFieldValue("CompilerToVM::Data::_max_oop_map_stack_offset", Integer.class, "int");
public final int heapWordSize = getConstant("HeapWordSize", Integer.class);
public final boolean ropProtection;
}

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, Arm Limited. All rights reserved.
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2022, Arm Limited. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -254,6 +254,9 @@ public class AArch64TestAssembler extends TestAssembler {
public void emitPrologue() {
// Must be patchable by NativeJump::patch_verified_entry
emitNop();
if (config.ropProtection) {
code.emitInt(0xdac103be); // pacia x30, x29
}
code.emitInt(0xa9be7bfd); // stp x29, x30, [sp, #-32]!
code.emitInt(0x910003fd); // mov x29, sp
@ -469,6 +472,9 @@ public class AArch64TestAssembler extends TestAssembler {
emitMov(AArch64.r0, a);
code.emitInt(0x910003bf); // mov sp, x29
code.emitInt(0xa8c27bfd); // ldp x29, x30, [sp], #32
if (config.ropProtection) {
code.emitInt(0xdac113be); // autia x30, x29
}
code.emitInt(0xd65f03c0); // ret
}
@ -477,6 +483,9 @@ public class AArch64TestAssembler extends TestAssembler {
assert a == AArch64.v0 : "Unimplemented move " + a;
code.emitInt(0x910003bf); // mov sp, x29
code.emitInt(0xa8c27bfd); // ldp x29, x30, [sp], #32
if (config.ropProtection) {
code.emitInt(0xdac113be); // autia x30, x29
}
code.emitInt(0xd65f03c0); // ret
}