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

Reply via email to