Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
wants to merge 34 commits into from
Closed
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9b05854
Build with branch protection
a74nh Oct 12, 2020
66b05a6
Add AArch64 ROP protection runtime flag
a74nh Oct 14, 2020
2c7e273
Add PAC assembly instructions
a74nh Nov 25, 2020
e0e3f66
8264130: PAC-RET protection for Linux/AArch64
a74nh Oct 19, 2020
29471d3
Simplify branch protection configure check
a74nh Nov 10, 2021
cfad2fe
Update UseROPProtection description
a74nh Nov 12, 2021
25e6249
Document pauth functions && remove OS split
a74nh Nov 11, 2021
2c27eb5
Merge master
a74nh Nov 15, 2021
a810ea7
Don't keep LR live across restore_live_registers
a74nh Nov 15, 2021
6f501e6
Fix windows aarch64 by restoring pauth file split
a74nh Nov 15, 2021
dbd6bda
Rename pauth_authenticate_or_strip_return_address
a74nh Nov 15, 2021
deb17a5
Merge master
a74nh Nov 16, 2021
280abc4
Merge master
a74nh Nov 22, 2021
995d8aa
Fix up UseROPProtection flag
a74nh Dec 1, 2021
38c08ef
Default to building without branch-protection
a74nh Dec 10, 2021
63f7515
Remove BSD/Apple specific code
a74nh Dec 10, 2021
9c4f349
Change UseROPProtection to UseBranchProtection
a74nh Dec 13, 2021
3cc2c5e
Fix assembler for post-merge
a74nh Jan 19, 2022
f6f8041
Merge master
a74nh Jan 20, 2022
83d2167
Fix GC issues
a74nh Jan 6, 2022
1479942
Fix jvmci tests
a74nh Jan 18, 2022
0b47654
Fix popframe failures
a74nh Jan 20, 2022
b792561
Fix up nits
a74nh Feb 1, 2022
78da1bd
Change pac-ret defaults on non PAC machines
a74nh Feb 2, 2022
6255d4c
Update copyrights to 2022
a74nh Feb 2, 2022
d97883b
Documentation updates
a74nh Feb 3, 2022
614a326
Review fixups
a74nh Feb 7, 2022
f779513
Merge enter_subframe into enter
a74nh Feb 8, 2022
001a8f1
Set PreserveFramePointer if use_rop_protection is set
a74nh Feb 7, 2022
2062cce
Add comments to enter calls
a74nh Feb 10, 2022
7f80f28
Error on -XX:-PreserveFramePointer -XX:UseBranchProtection=pac-ret
a74nh Feb 11, 2022
f9882ff
Merge master
a74nh Feb 21, 2022
97ae934
Merge master
a74nh Feb 22, 2022
c4e0ee3
Merge master
a74nh Feb 22, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
27 changes: 25 additions & 2 deletions make/autoconf/flags-cflags.m4
Expand Up @@ -805,17 +805,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
Expand Down Expand Up @@ -881,3 +883,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: auto,
RESULT: USE_BRANCH_PROTECTION, AVAILABLE: $BRANCH_PROTECTION_AVAILABLE,
a74nh marked this conversation as resolved.
Show resolved Hide resolved
DESC: [enable branch protection when compiling C/C++],
IF_ENABLED: [ BRANCH_PROTECTION_CFLAGS=${BRANCH_PROTECTION_FLAG}])
AC_SUBST(BRANCH_PROTECTION_CFLAGS)
])
1 change: 1 addition & 0 deletions make/autoconf/spec.gmk.in
Expand Up @@ -403,6 +403,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@

Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/cpu/aarch64/aarch64.ad
Expand Up @@ -1366,8 +1366,8 @@ source %{
_NO_SPECIAL_PTR_REG_mask.SUBTRACT(_HEAPBASE_REG_mask);
}

// r29 is not allocatable when PreserveFramePointer is on
if (PreserveFramePointer) {
// r29 is not allocatable when PreserveFramePointer or UseROPProtection is on
if (PreserveFramePointer || UseROPProtection) {
_NO_SPECIAL_REG32_mask.Remove(OptoReg::as_OptoReg(r29->as_VMReg()));
_NO_SPECIAL_REG_mask.SUBTRACT(_FP_REG_mask);
_NO_SPECIAL_PTR_REG_mask.SUBTRACT(_FP_REG_mask);
Expand Down
140 changes: 107 additions & 33 deletions src/hotspot/cpu/aarch64/assembler_aarch64.hpp
Expand Up @@ -990,33 +990,36 @@ class Assembler : public AbstractAssembler {
rf(rt, 0);
}

void hint(int imm) {
system(0b00, 0b011, 0b0010, 0b0000, imm);
}

void nop() {
hint(0);
}

void yield() {
hint(1);
}
// Hint instructions

void wfe() {
hint(2);
#define INSN(NAME, crm, op2) \
void NAME() { \
system(0b00, 0b011, 0b0010, crm, op2); \
}

void wfi() {
hint(3);
}
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 sev() {
hint(4);
}
// PAC instructions
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 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
Expand Down Expand Up @@ -1102,18 +1105,20 @@ class Assembler : public AbstractAssembler {
}

// 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, 0); \
}

INSN(br, 0b0000);
Expand All @@ -1124,16 +1129,54 @@ class Assembler : public AbstractAssembler {

#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, 0); \
}

INSN(eret, 0b0100);
INSN(drps, 0b0101);

#undef INSN

// PAC return instructions
#define INSN(NAME, M) \
void NAME() { \
branch_reg(0b0010, 1, M, dummy_reg, dummy_reg); \
}

INSN(retaa, 0);
INSN(retab, 1);

#undef INSN

// PAC branch instructions (with zero modifier)
#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

// PAC branch instructions (with register modifier)
a74nh marked this conversation as resolved.
Show resolved Hide resolved
#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
enum operand_size { byte, halfword, word, xword };

Expand Down Expand Up @@ -1793,6 +1836,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)
Expand Down
8 changes: 7 additions & 1 deletion src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp
Expand Up @@ -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()));
Expand Down Expand Up @@ -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.
Expand All @@ -448,6 +450,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) {
__ invalidate_registers(false, true, true, true, true, true);
a74nh marked this conversation as resolved.
Show resolved Hide resolved

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

a74nh marked this conversation as resolved.
Show resolved Hide resolved
switch (id) {
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand Down
28 changes: 17 additions & 11 deletions src/hotspot/cpu/aarch64/frame_aarch64.cpp
Expand Up @@ -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
Expand All @@ -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);
}


Expand Down Expand Up @@ -268,17 +268,18 @@ 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);
if (TracePcPatching) {
tty->print_cr("patch_pc at address " INTPTR_FORMAT " [" INTPTR_FORMAT " -> " INTPTR_FORMAT "]",
p2i(pc_addr), p2i(*pc_addr), p2i(pc));
p2i(pc_addr), p2i(*pc_addr), p2i(signed_pc));
a74nh marked this conversation as resolved.
Show resolved Hide resolved
}

// 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;
address pc_old = pauth_strip_verifiable(*pc_addr, (address)signing_sp);
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");
Expand Down Expand Up @@ -454,12 +455,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 {
Expand All @@ -472,7 +473,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);

Expand Down Expand Up @@ -520,6 +523,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());
}

Expand Down
4 changes: 3 additions & 1 deletion src/hotspot/cpu/aarch64/globals_aarch64.hpp
Expand Up @@ -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(bool, UseROPProtection, false, \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: this is called "UseROPProtection", the configure option is called "enable-branch-protection", and GCC option is called "-mbranch-protection". This is confusing. I would have thought we would want the same name, and use it for all branch protection. So why is this not "UseBranchProtection"?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-mbranch-protection switches on both PAC-RET and BTI. This PR only covers a use of PAC that looks very ROP-focused to me.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, because we don't (yet) support BTI. Is there any point having two separate flags for BTI and PAC-RET? If someone wants one, they'll very likely want the other, won't they?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can support one without the other.
The architecture allows you to have one without the other.
The GCC flag is an enum of "none|standard|pac-ret[+leaf]|bti", with some of them changing depending on which cpu you specify to -mcpu (8.0,8.3,8.5 etc).
Clang has the same flags. Interestingly, on MacOS Clang, -mbranch-protection is available but it'll give incorrect code. Instead you build with -arch arm64e.

If your system had both, the only scenario I could see for only wanting just one would be for test/dev purposes. In a real production scenario you would want everything the system supports or nothing.

An earlier version of my code had a UseBranchProtection="pac|bti|pac+bti|all|none" style option

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can support one without the other. The architecture allows you to have one without the other. The GCC flag is an enum of "none|standard|pac-ret[+leaf]|bti", with some of them changing depending on which cpu you specify to -mcpu (8.0,8.3,8.5 etc). Clang has the same flags.

OK, so we have a precedent.

If your system had both, the only scenario I could see for only wanting just one would be for test/dev purposes. In a real production scenario you would want everything the system supports or nothing.

Yes.

An earlier version of my code had a UseBranchProtection="pac|bti|pac+bti|all|none" style option

That sounds great.

It seems to me that following the GCC/Clang precedent is the wisest thing we could do. I can see no possible advantage in diverging: it only confuses programmers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That gives us:

A new flag -XX:UseBranchProtection

With the options:
none - no PAC support. (Default)
standard - PAC support if the system supports it and the java binary was compiled with PAC. Otherwise off.
pac-ret - PAC support, regardless if the system supports it or the java binary was compiled with PAC.

A later BTI patch would add:
standard - also adds BTI if the system supports it and the java binary was compiled with BTI.
bti - BTI support, regardless if the system supports it or the java binary was compiled with BTI.
Also, concat the flags with "+". Eg: standard+bti. No need to do this until BTI is added.

For MacOS, you can only use PAC functionality when compiled for arm64e. Therefore arm64e would be supported by compiling the java binary for the arm64e and would always be enabled in that scenario. UseBranchProtection on MacoOS will only support the none option.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to the above. The CSR will need an update too.

"Protect branches against ROP attacks.") \

// end of ARCH_FLAGS

Expand Down