https://github.com/atrosinenko commented:
It would be probably useful to explicitly list the configurations that we would like to support at the end of the day. Some combinations are probably unsupported or not planned for the first version of the patch. I have already left similar comments before, but let me summarize them in a more structured fashion. Corrections are welcome :) There seems to be three different aspects independent from each other. The first aspect is pac-ret hardening mode the calling code was built with. If my understanding is correct, pac-ret is largely considered as not affecting the ABI (because signing and authentication code belongs to the same function) and thus the mode can be arbitrarily chosen per shared object, per-library or technically even per-function. Thus, this mode should probably be inferred not from the preprocessor macroses observed at libunwind build time, but from the DWARF information (which raises the question of when we can or cannot trust this information under Pointer Authentication threat model). See [`aadwarf64` document](https://github.com/ARM-software/abi-aa/releases/tag/2025Q1) for the description of CFA operations controlling `RA_SIGN_STATE` pseudo register. Furthermore, the *key* being used by the particular stack frame is communicated via optional character `B` in the CIE augmentation string (described in the same document). There already exist significant amount of code in [`DwarfInstructions<A, R>::stepWithDwarf`](https://github.com/llvm/llvm-project/blob/47c1b650626043f0a8f8e32851617201751f9439/libunwind/src/DwarfInstructions.hpp#L210) - I wonder if it could be reused in a secure manner. The second aspect is ABI-affecting variations of unwind information format. One thing I do know about is signing of the pointer to the personality function, but I don't have the complete list of structs and fields in my mind. It would probably be useful to explicitly enumerate the minimal set of "public" fields whose signing schemas we should choose in accordance with the ABI. After all, these details should probably end up being documented in some specification sooner or later. The third aspect is which internal fields are signed and when. This is more a matter of the targeted ISA version and best-effort guess of the desired "protection mode" of the affected libraries. According to https://github.com/llvm/llvm-project/pull/143230#discussion_r2173023794, this could probably be as simple as "if `__has_feature(ptrauth_calls)` is true, then assume we target at least Armv8.3-a and enable signing of all the affected internal fields". (I don't remember, but maybe some rudimentary v8.2-compatible hardening of PC exists in DwarfInstructions as well.) By the way, the separation of purely internal fields should also help to simplify the code: while ABI-defined signing schemas have to be described explicitly, for the internal struct fields and local variables it should be possible to define macroses like ```cpp #define PTRAUTH_INTPTR(type, name) \ type __ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, \ 1, ptrauth_string_discriminator("__gcc_personality_v0'" #name)) name ``` or maybe embed the type into the macro name like `PTRAUTH_UINTPTR_T(name)`. Then it can be used along these lines: ```cpp PTRAUTH_INTPTR(uintptr_t, start) = readEncodedPointer(&p, callSiteEncoding); ``` This would additionally clarify the distinction between ABI-defined and arbitrarily chosen schemas. I wonder if this approach has its own important downsides that I don't see. https://github.com/llvm/llvm-project/pull/143230 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits