[llvm] [llvm-exegesis][AArch64] Check for PAC keys before disabling them (PR #138643)
Anatoly Trosinenko via llvm-commits
llvm-commits at lists.llvm.org
Wed May 7 13:05:56 PDT 2025
https://github.com/atrosinenko requested changes to this pull request.
If my understanding is correct, the problem is that llvm-exegesis may fail with an error like "AUTIA: Failed to disable PAC keys", depending on the CPU features. It looks like I have managed to reproduce this issue in QEMU (in full-system emulation mode), the results are below.
As far as I see, PAuth-related `prctl`s are not documented in man pages well, but thankfully the kernel sources are quite readable on themselves:
* `prctl` entry point is in [kernel/sys.c](https://github.com/torvalds/linux/blob/d76bb1ebb5587f66b0f8b8099bfbb44722bc08b3/kernel/sys.c#L2473), and [here](https://github.com/torvalds/linux/blob/d76bb1ebb5587f66b0f8b8099bfbb44722bc08b3/kernel/sys.c#L2698) are relevant operations
* the requests are ultimately processed in [arch/arm64/kernel/pointer_auth.c](https://github.com/torvalds/linux/blob/d76bb1ebb5587f66b0f8b8099bfbb44722bc08b3/arch/arm64/kernel/pointer_auth.c#L67)
* according to the Caveats section of [`man prctl`](https://man7.org/linux/man-pages/man2/prctl.2.html), as well as to [`man PR_PAC_RESET_KEYS`](https://man7.org/linux/man-pages/man2/PR_PAC_RESET_KEYS.2const.html), it is probably better to pass `prctl` arguments as `long`
Each configuration was tested by running
```bash
strace -f -e prctl \
/path/to/llvm-project/build-aarch64/bin/llvm-exegesis \
-mtriple=aarch64-linux-gnu \
-mcpu=neoverse-v2 \
-mode=latency \
--opcode-name=AUTIA \
--use-dummy-perf-counters
```
On the main branch (commit cd6c4b61034850fffcb221a449a8ee1fdd8ada8a), with emulated CPU set to `neoverse-v1,pauth-impdef=on` (Neoverse-V2 is not supported in QEMU 9.2.1, but Neoverse-V1 seems to be enough to reproduce the issue. Similarly, `pauth-impdef=on` should not affect the issue, but makes emulation faster) I got
```
prctl(PR_PAC_SET_ENABLED_KEYS, PR_PAC_APIAKEY|PR_PAC_APIBKEY|PR_PAC_APDAKEY|PR_PAC_APDBKEY, 0, 0, 0) = 0
---
mode: latency
key:
instructions:
- 'AUTIA X23 X23 X15'
config: ''
register_initial_values:
- 'X23=0x0'
- 'X15=0x0'
cpu_name: neoverse-v2
llvm_triple: aarch64-unknown-linux-gnu
min_instructions: 10000
measurements: []
error: ''
info: Repeating a single implicitly serial instruction
assembled_snippet: F70F1FF8170080D20F0080D2F711C1DAF711C1DAF711C1DAF711C1DAF70741F8C0035FD6
...
+++ exited with 0 +++
```
and setting CPU to `cortex-a72` gives this output:
```
prctl(PR_PAC_SET_ENABLED_KEYS, PR_PAC_APIAKEY|PR_PAC_APIBKEY|PR_PAC_APDAKEY|PR_PAC_APDBKEY, 0, 0, 0) = -1 EINVAL (Invalid argument)
AUTIA: Failed to disable PAC keys
+++ exited with 0 +++
```
(by the way, return code is 0, which is a bit surprising...). This is probably because of `if (!system_supports_address_auth()) return -EINVAL;` check in the kernel, assuming `system_supports_address_auth()` means "FEAT_PAUTH was detected at run-time" (instead of "the kernel was compiled with PAuth support" or something like this).
This PR (commit 2a9af0f62741e43dd3d6f760a47c0a60833a04bd) produces an error like the following with both CPU models:
```
prctl(PR_PAC_GET_ENABLED_KEYS, 0x7ff2234598, 0, 0, 0) = -1 EINVAL (Invalid argument)
AUTIA: Failed to get PAC key status
+++ exited with 0 +++
```
Turned out, all arguments should be set to 0 and the bitmask is returned as the return value of `prctl`.
I applied a quick fix:
```diff
diff --git a/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp b/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp
index 7e6382693c3e..3d59955177cb 100644
--- a/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp
@@ -213,8 +213,8 @@ private:
// For systems without PAC, this is a No-op but with PAC, it is
// safer to check the existing key state and then disable/enable them.
// Hence the guard for switching.
- unsigned long PacKeys = 0;
- if (prctl(PR_PAC_GET_ENABLED_KEYS, &PacKeys, 0, 0, 0) < 0) {
+ unsigned long PacKeys = prctl(PR_PAC_GET_ENABLED_KEYS, 0, 0, 0, 0);
+ if ((long)PacKeys < 0) {
return "Failed to get PAC key status";
}
```
With CPU set to `neoverse-v1,pauth-impdef=on` the following output is produced:
```
prctl(PR_PAC_GET_ENABLED_KEYS, 0, 0, 0, 0) = 0xf (PR_PAC_APIAKEY|PR_PAC_APIBKEY|PR_PAC_APDAKEY|PR_PAC_APDBKEY)
prctl(PR_PAC_SET_ENABLED_KEYS, PR_PAC_APIAKEY|PR_PAC_APIBKEY|PR_PAC_APDAKEY|PR_PAC_APDBKEY, 0, 0, 0) = 0
---
mode: latency
key:
instructions:
- 'AUTIA X23 X23 X0'
config: ''
register_initial_values:
- 'X23=0x0'
- 'X0=0x0'
cpu_name: neoverse-v2
llvm_triple: aarch64-unknown-linux-gnu
min_instructions: 10000
measurements: []
error: ''
info: Repeating a single implicitly serial instruction
assembled_snippet: F70F1FF8170080D2000080D21710C1DA1710C1DA1710C1DA1710C1DAF70741F8C0035FD6
...
+++ exited with 0 +++
```
but with `cortex-a72` it fails with:
```
prctl(PR_PAC_GET_ENABLED_KEYS, 0, 0, 0, 0) = -1 EINVAL (Invalid argument)
AUTIA: Failed to get PAC key status
+++ exited with 0 +++
```
Probably, `EINVAL` is always returned when FEAT_PAUTH is not supported by the CPU.
https://github.com/llvm/llvm-project/pull/138643
More information about the llvm-commits
mailing list