Arm64: [PAC-RET] Add Pointer Authentication support for Arm64#125436
Arm64: [PAC-RET] Add Pointer Authentication support for Arm64#125436SwapnilGaikwad wants to merge 150 commits into
Conversation
This PR adds support for Pointer Authentication (PAC) on Arm64. Pointer Authentication (PAC) is an Armv8.3+ security feature designed to mitigate Return-Oriented Programming (ROP) attacks by cryptographically signing return addresses. While using PAC, we store a signed return address, instead of the plain address, on the stack and later authenticate it before returning from a function. It ensures control flow returns to the intended caller. More details on PAC and its role in software security can be found ([here](https://llsoftsec.github.io/llsoftsecbook/#sec:pointer-authentication)). - The current implementation of PAC is turned off by default, but can be turned on by setting DOTNET_JitPacEnabled=1. - PAC protects link register (LR) by signing it in the prolog (using `paciasp`) before it is split, using the current SP as the modifier. It then authenticates the LR in the epilog (using `autiasp`) before the function returns. If the signature is invalid, the execution fails with `SIGILL`. - - When the runtime needs to read or overwrite a return address during hijacking for GC, it now strips the PAC (using `xpaclri`) and re-signs the new target address before storing it back. - To simply tracking the SP in return address hijacking, we avoid using the pre-indexed variant of storing FP/LR on stack (e.g., `stp fp,lr,[sp,-#framesz]! `) to simply tracking the SP in return address hijacking. We obtain the value of SP at the time of signing the LR from the location of the current FP. We can't use this approach when the pre-indexed `stp` is used because we don't know the`#framesz`. - The updated prolog/epilog sequences generated by the JIT now look like: // Prolog sub sp, sp, #framesz paciasp ; sign LR with A-key + SP stp fp, lr, [sp] // Epilog ldp fp, lr, [sp] autiasp ; authenticate LR add sp, sp, #framesz ret ToDos: [] Restore the original frame layout that used pre-indexed variant of `stp` to store FP/LR. [] Authenticate the return address instead of stripping in return address hijacking and unwinding. [] Identify increased binary size for System.*.dll [] Determine performance regressions using benchmarks such as OrchirdCMS.
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
| } | ||
| CodeBlockHandle? IExecutionManager.GetCodeBlockHandle(TargetCodePointer ip) | ||
| { | ||
| ip = StripArm64PacForCodeLookup(ip); |
There was a problem hiding this comment.
This is not the right fix. The PAC bits should be stripped close to stackwalking. Once we start passing code addressed around. they should always be without the PAC bits
| @@ -42,9 +43,10 @@ internal static TargetPointer AddressFromCodePointer(TargetCodePointer code, Tar | |||
| } | |||
| else if (flags.HasFlag(CodePointerFlags.HasArm64PtrAuth)) | |||
There was a problem hiding this comment.
This method is not coupled with stackwalking.
I am not sure whether CodePointerFlags.HasArm64PtrAuth check should be in this method at all.
There was a problem hiding this comment.
Agreed, I'll take a closer look. Initially had a separate method centrally accessible in CodePointerUtils.cs for stripping PAC . During refactoring thought it might seem equivalent to removing thumb bit change so moved it in AddressFromCodePointer and CodePointerFromAddress methods. However, as you had pointed out it might make more sense to strip return addresses in/around stackwalking.
| @@ -96,7 +97,7 @@ public static TargetPointer ToAddress(this TargetCodePointer code, Target target | |||
| } | |||
| else if (flags.HasFlag(CodePointerFlags.HasArm64PtrAuth)) | |||
There was a problem hiding this comment.
(I am not commenting on all places.)
There was a problem hiding this comment.
Right. I don't understand cdac well so not quite sure yet about an approach to handle PAC. I assumed that whether we have HasArm64PtrAuth check, we need to implement some sort of handling for PAC. I'll take a closer look again 👍
Add assert to ensure PAC is being emitted before stack adjustment
|
/azp run runtime-nativeaot-outerloop |
|
Azure Pipelines successfully started running 1 pipeline(s). |
This PR adds support for Pointer Authentication (PAC) on Arm64. Pointer Authentication (PAC) is an Armv8.3+ security feature designed to mitigate Return-Oriented Programming (ROP) attacks by cryptographically signing return addresses. While using PAC, we store a signed return address, instead of the plain address, on the stack and later authenticate it before returning from a function. It ensures control flow returns to the intended caller.
More details on PAC and its role in software security can be found (here).
paciasp) before it is split, using the current SP as the modifier. It then authenticates the LR in the epilog (usingautiasp) before the function returns. If the signature is invalid, the execution fails withSIGILL.xpaclri) and re-signs the new target address before storing it back.ToDos
stpto store FP/LR.Contributes to #109457