Arm64: [PAC-RET] Add Pointer Authentication support for Arm64 (Part 1/3): JIT changes#127838
Arm64: [PAC-RET] Add Pointer Authentication support for Arm64 (Part 1/3): JIT changes#127838SwapnilGaikwad wants to merge 1 commit intodotnet:mainfrom
Conversation
…/3: JIT changes) As suggested in [comment](dotnet#125436 (comment)), this PR covers subset of changes from dotnet#125436 related to the JIT. 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`. - Changes are limited to JIT.
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
| } | ||
| #endif // FEATURE_CFI_SUPPORT | ||
|
|
||
| // pac_sign_lr: 11111100: sign the return address in lr with paciasp |
There was a problem hiding this comment.
Docs call out pacibsp not paciasp, is that an issue at all?
https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling?view=msvc-170#unwind-codes
There was a problem hiding this comment.
Are the Windows vs. Unix conventions for signing key different?
There was a problem hiding this comment.
AFAIK, Windows uses B key while the rest use A key for signing. The execption handling documentation and this dev blog on suggest the same.
This could potentially be a problem if an unwinder assumes the use of key. Jan mentioned here, Windows OS unwinder is used on Windows for execution. It might assume use of B key in that case. I'm not sure why it's not being flagged up by any Windows CI workflows.
Would you recommend switching to B key on Windows?
There was a problem hiding this comment.
Yes, I would recommend following platform conventions.
Also, this is worth mentioning in https://github.com/dotnet/runtime/blob/main/docs/design/coreclr/botr/clr-abi.md
There was a problem hiding this comment.
Thanks for the link, yeah Swapnil and I talked offline he's going to try to switch to B-key signing for windows
also for reference here's msvc emitting sign/auth instructions if it matters
https://godbolt.org/z/dMdo7sqod
There was a problem hiding this comment.
Thank you both. I'll update to use B keys on Windows. It makes more sense and is consistent.
I'll update the original PR (#125436) first with B key changes to ensure everything passes on Windows. Then I'll port these changes here. We don't have encodings for B key instructions. I'll put them in the original PR for testing but 'll open a separate PR just to add encodings.
| // Tier0 signed LR with the Tier0 caller SP before allocating its frame. | ||
| // Recreate that SP from the current Tier0 body SP so we can authenticate | ||
| // LR before the OSR prolog later re-signs it with the OSR SP via PACIASP. | ||
| genInstrWithConstant(INS_add, EA_PTRSIZE, REG_IP0, REG_SPBASE, patchpointInfo->TotalFrameSize(), REG_IP0, |
There was a problem hiding this comment.
@AndyAyersMS FYI if we want a second set of eyes on the OSR change here
There was a problem hiding this comment.
nit - anyway if you're in here again Swapnil I'd change "authenticate LR" to "authenticate and strip LR" even though the latter is still implied, reads a little clearer to me
There was a problem hiding this comment.
If I understand correctly the tier0 code will have signed LR with the SP as it is on entry, while the OSR method will now sign LR with the value of SP after the tier0 adjustment.
Would it make more sense to just skip signing in the OSR method and then authenticate after both SP adjustments have been done in the epilog?
There was a problem hiding this comment.
It might be possible to avoid authenticating and re-signing with the help of phantom unwind code representing stack allocation. However, it deviates from the simple model to use signing SP from current frame. I'm happy to explore this possibility in the follow-up PR as the current one is getting trickier to maintain 🙂
There was a problem hiding this comment.
The OSR function inherits the frame from the tier0 function, it is part of its frame. What we have now effectively is making OSR functions deviate from all other functions since it is signing with an SP that points into the middle of its frame. I am ok with it, but you may want to make sure the OSR case is well tested.
Also we may want to eventually do some perf testing for runtime async since these prologs can be very hot for runtime async.
help of phantom unwind code representing stack allocation
I think we would emit a phantom pac_sign_lr code, before we emitted the phantom SP adjustment.
As suggested in comment, this PR covers subset of changes from #125436 related to the JIT.
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.NOTE: This PR adds part of the changes for PAC support to simply review process as discussed here. However it cannot pass the tests without the remaining parts. Kindly take a look at the CI status of #125436 to ensure correctness.