llvm / llvm/llvm-project

[AArch64][PAC] Fix indirect call promotion for authenticated calls

Open
#192,093 1 comment 0 reactions 1 assignee Claimed by @atrosinenko View on GitHub
new issue
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

Several years ago, there was a patch posted on Phabricator for review: [D134999: AArch64: PAC: Do not attempt ICP on authenticating calls](https://reviews.llvm.org/D134999). To the best of my knowledge, it was never re-posted after migration to Github. Recently, I tried to check if this patch is still relevant - this issue is intended to provide an overview of the related subtasks.

Debugging of the original issue yielded slightly surprising results: on one hand, the mainline LLVM still produces an invalid IR (and doesn't pass the IR verifier) if Clang is fed with the correct `*.profdata` and asked to perform indirect call promotion. On the other hand, this optimization seems to be effectively disabled by the fact that the profiler run-time cannot collect such profile correctly.

I plan sending several PRs soon.

## Support of authenticated call promotion in the optimizer

Turning an indirect authenticated call instruction into a direct one by replacing a `ptr`-typed callee value with a direct `@global_function` reference would produce a direct call with a `"ptrauth"` operand bundle which is explicitly rejected by the IR verifier. This is the reason for the original patch D134999 to disable promotion of authenticated calls to prevent forming an invalid LLVM IR.

`CallBase::removeOperandBundle` method should provide a safe way to drop `"ptrauth"` bundles:

```cpp
/// Create a clone of \p CB with operand bundle \p ID removed.
LLVM_ABI static CallBase *
removeOperandBundle(CallBase *CB, uint32_t ID,
InsertPosition InsertPt = nullptr);
```

As nowadays there should be no risk of accidentally forgetting to copy any instruction's metanformation in a PGO-specific ad-hoc implementation, it should be trivial to provide a full-fledged fix instead of just disabling a mis-behaving optimization.

## Value profile collection

The mainline implementation of `libclang_rt.profile` library receives signed pointers as call targets and records them to the raw profile as-is. Later, at the post-processing time, `llvm-profdata merge` is unable to match these pointers with non-zero PAC field against the "reference" addresses that are written without signing, resulting in a zero "placeholders" written to the resulting `*.profdata` file.

## Crashes of instrumented executables

Running `check-profile` cmake target in a build of compiler-rt for `aarch64-linux-pauthtest` resulted in a few crashes in run-time library code.

`GCOVProfiler` pass adds a non-signed pointer to `__llvm_gcov_init` function to `@llvm.global_ctors` array, whether pointers to init/fini functions are expected to be signed or not. As far as I can see, presently only the frontend-generated IR can contribute properly-signed `ptrauth` constants to `@llvm.global_ctors`, as `0xd9d4` constant doesn't seem to be directly or indirectly (such as through `__ptrauth_init_fini_discriminator`) mentioned in the LLVM core. This should probably affect other instrumentations that register init/fini functions.

Furthermore, the run-time library may crash when processing `writeout_fn_list` and `reset_fn_list`. These are linked lists containing pointers to callback functions which are generated by instrumenter pass in the LLVM core (without any AUTH relocations for now). The most simple solution would probably be to agree on some custom signing schema for these specific function pointers, so that the mid-end doesn't have to mimic the discriminator computation when `-fptrauth-function-pointer-type-discrimination` is in effect.

Tagging @ahmedbougacha, @asl, @kbeyls, @kovdan01, @pcc.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.