This is an archive of the discontinued LLVM Phabricator instance.

[AArch64] Move PAuth codegen down the machine pipeline
ClosedPublic

Authored by atrosinenko on Sep 1 2023, 6:50 AM.

Details

Summary

To simplify handling PAuth in the machine outliner, introduce a
separate AArch64PointerAuth pass that is executed after both
Prologue/Epilogue Inserter and Machine Outliner passes.

After moving to AArch64PointerAuth, signLR and authenticateLR are
not used outside of their class anymore, so make them private and
simplify accordingly.

The new pass is added via AArch64PassConfig::addPostBBSections(),
so that it can change the code size before branch relaxation occurs.
AArch64BranchTargets is placed there too, so it can take into account
any PACI(A|B)SP instructions and not excessively add BTIs at the start
of functions.

Diff Detail

Event Timeline

atrosinenko created this revision.Sep 1 2023, 6:50 AM
Herald added a project: Restricted Project. · View Herald TranscriptSep 1 2023, 6:50 AM
Herald added a subscriber: hiraditya. · View Herald Transcript
atrosinenko requested review of this revision.Sep 1 2023, 6:50 AM
Herald added a project: Restricted Project. · View Herald TranscriptSep 1 2023, 6:50 AM
pratlucas added inline comments.
llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
1421–1426

Why do we need these to be added as pseudo-instructions during frame lowering? Is there any chance the criteria for making the decision is lost before the new pass is executed?

llvm/lib/Target/AArch64/AArch64PointerAuth.cpp
33–42

I feel those member variables could be removed to make the class less stateful.
A single instantiation of this pass will be used over multiple machine functions and most of those members are specific to each of the functions. Removing them would also allow the private methods below to be made freestanding static functions instead.

I don't understand the motivation here. This moves PAuth's instruction insertion later down the pipeline, but why? The handling in the machine outliner isn't made any simpler IMO.

tmatheson added inline comments.Sep 5 2023, 5:35 AM
llvm/lib/Target/AArch64/AArch64PointerAuth.cpp
157

Looks like HasWinCFI is not used for anything but the asserts below, it could be removed. It has always been a confusing part of this code.

atrosinenko added inline comments.Sep 18 2023, 7:51 AM
llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
1421–1426

One reason is that the insertion points computed by the shrink-wrapping pass are actually lost after PEI. Though, inserting PAC on entry and AUT before every return may be considered both as a bug (from the performance point of view) or as a feature (from the security point of view as it makes things easier to observe).

Another reason (mostly for the PAUTH_EPILOGUE instruction) is that the naive approach would wrap the Shadow Call Stack code inside PAuth one, but now it is explicitly checked in tests that the LR value is actually restored by SCS if both are enabled. I wonder if it is meaningful at all to sign and authenticate LR when SCS is enabled for the particular function, though.

I don't understand the motivation here. This moves PAuth's instruction insertion later down the pipeline, but why? The handling in the machine outliner isn't made any simpler IMO.

The original motivation was to implement checking the LR value in tail calls (D156716) at some point after both PEI and machine outliner - the outliner doesn't seem to handle checker code well now. It seems that inserting PAuth-related hardening code is generally "the later the better" (IIRC, in the Ahmed's branch it was done even later, at the AsmPrinter phase), so I moved the existing code down the pipeline to handle everything PAuth-related at a single place.

Addressed the review comments, rebased.

atrosinenko added inline comments.Sep 19 2023, 8:45 AM
llvm/lib/Target/AArch64/AArch64PointerAuth.cpp
33–42

Not sure if it is necessary to expose signLR and authenticateLR as public static methods right now, so kept Subtarget and TII fields (this seems to be done by some other passes as well). Dropped other "cached" fields. Though, I don't mind making signLR and authenticateLR methods static if needed.

157

Agree, dropped the assertions.

Here are some relevant patches that I found when investigating how WinCFI is handled:

  • D61960 (correctness) computes the actual presence of WinCFI directives
  • D88641 (binary size) optimizes emitEpilogue to not emit WinCFI directives if prologue doesn't have any.
tmatheson accepted this revision.Sep 20 2023, 5:29 AM
This revision is now accepted and ready to land.Sep 20 2023, 5:29 AM