Skip to content

Conversation

atrosinenko
Copy link
Contributor

A generic authentication instruction may crash the process on failure. Furthermore, it can be executed conditionally and/or its signing schema can be chosen dynamically. For this reason, while it may be beneficial to permit DCE to remove AUTx16x17 or AUTxMxN instructions unless their results have any uses (at least fake ones, if we just want to check the
signature), AUT instructions are not safe to be executed speculatively.

As a quick fix for miscompilation possibility, this patch marks AUTxMxN pseudo instruction as having unmodelled side effects.

A generic authentication instruction may crash the process on failure.
Furthermore, it can be executed conditionally and/or its signing schema
can be chosen dynamically. For this reason, while it may be beneficial
to permit DCE to remove AUTx16x17 or AUTxMxN instructions unless their
results have any uses (at least fake ones, if we just want to check the
signature), AUT instructions are not safe to be executed speculatively.

As a quick fix for miscompilation possibility, this patch marks AUTxMxN
pseudo instruction as having unmodelled side effects.
@atrosinenko atrosinenko marked this pull request as ready for review August 26, 2025 10:06
@llvmbot
Copy link
Member

llvmbot commented Aug 26, 2025

@llvm/pr-subscribers-backend-aarch64

Author: Anatoly Trosinenko (atrosinenko)

Changes

A generic authentication instruction may crash the process on failure. Furthermore, it can be executed conditionally and/or its signing schema can be chosen dynamically. For this reason, while it may be beneficial to permit DCE to remove AUTx16x17 or AUTxMxN instructions unless their results have any uses (at least fake ones, if we just want to check the
signature), AUT instructions are not safe to be executed speculatively.

As a quick fix for miscompilation possibility, this patch marks AUTxMxN pseudo instruction as having unmodelled side effects.


Full diff: https://github.com/llvm/llvm-project/pull/155372.diff

2 Files Affected:

  • (modified) llvm/lib/Target/AArch64/AArch64InstrInfo.td (+1-1)
  • (modified) llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign.ll (+123)
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 89f88776d832c..ad8556b824cda 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -2155,7 +2155,7 @@ let Predicates = [HasPAuth] in {
                             i64imm:$Disc, GPR64:$AddrDisc),
                        [], "$AuthVal = $Val">, Sched<[WriteI, ReadI]> {
     let isCodeGenOnly = 1;
-    let hasSideEffects = 0;
+    let hasSideEffects = 1;
     let mayStore = 0;
     let mayLoad = 0;
     let Size = 32;
diff --git a/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign.ll b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign.ll
index 2634beb4e3591..52b38a5632005 100644
--- a/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign.ll
+++ b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign.ll
@@ -755,5 +755,128 @@ define i64 @test_auth_ia_swapped(i64 %arg, i64 %arg1) {
   ret i64 %tmp
 }
 
+; Authentications should not be speculated, as they crash on failure and it is
+; perfectly correct to dynamically choose the signing schema or whether to
+; perform authentication at all.
+define ptr @auth_speculation(i64 %signed, i1 %cond) {
+; UNCHECKED-LABEL:        auth_speculation:
+; UNCHECKED:                  %bb.0:
+; UNCHECKED-DARWIN-NEXT:        mov     x16, x0
+; UNCHECKED-DARWIN-NEXT:        tbz     w1, #0, [[BB_ELSE:[A-Za-z0-9_.]+]]
+; UNCHECKED-DARWIN-NEXT:      %bb.1:
+; UNCHECKED-DARWIN-NEXT:        autdza  x16
+; UNCHECKED-DARWIN-NEXT:        b       [[BB_RETURN:[A-Za-z0-9_.]+]]
+; UNCHECKED-DARWIN-NEXT:      [[BB_ELSE]]:
+; UNCHECKED-DARWIN-NEXT:        autdzb  x16
+; UNCHECKED-DARWIN-NEXT:      [[BB_RETURN]]:
+; UNCHECKED-DARWIN-NEXT:        ldr     x8, [x16]
+; UNCHECKED-ELF-NEXT:           tbz     w1, #0, [[BB_ELSE:[A-Za-z0-9_.]+]]
+; UNCHECKED-ELF-NEXT:         %bb.1:
+; UNCHECKED-ELF-NEXT:           autdza  x0
+; UNCHECKED-ELF-NEXT:           b       [[BB_RETURN:[A-Za-z0-9_.]+]]
+; UNCHECKED-ELF-NEXT:         [[BB_ELSE]]:
+; UNCHECKED-ELF-NEXT:           autdzb  x0
+; UNCHECKED-ELF-NEXT:         [[BB_RETURN]]:
+; UNCHECKED-ELF-NEXT:           ldr     x8, [x0]
+; UNCHECKED-NEXT:               ldr     x8, [x8]
+; UNCHECKED-NEXT:               ldr     x8, [x8]
+; UNCHECKED-NEXT:               ldr     x0, [x8]
+; UNCHECKED-NEXT:               ret
+;
+; CHECKED-LABEL:        auth_speculation:
+; CHECKED:                  %bb.0:
+; CHECKED-DARWIN-NEXT:        mov     x16, x0
+; CHECKED-DARWIN-NEXT:        tbz     w1, #0, [[BB_ELSE:[A-Za-z0-9_.]+]]
+; CHECKED-DARWIN-NEXT:      %bb.1:
+; CHECKED-DARWIN-NEXT:        autdza  x16
+; CHECKED-DARWIN-NEXT:        b       [[BB_RETURN:[A-Za-z0-9_.]+]]
+; CHECKED-DARWIN-NEXT:      [[BB_ELSE]]:
+; CHECKED-DARWIN-NEXT:        autdzb  x16
+; CHECKED-DARWIN-NEXT:      [[BB_RETURN]]:
+; CHECKED-DARWIN-NEXT:        ldr     x8, [x16]
+; CHECKED-ELF-NEXT:           tbz     w1, #0, [[BB_ELSE:[A-Za-z0-9_.]+]]
+; CHECKED-ELF-NEXT:         %bb.1:
+; CHECKED-ELF-NEXT:           autdza  x0
+; CHECKED-ELF-NEXT:           b       [[BB_RETURN:[A-Za-z0-9_.]+]]
+; CHECKED-ELF-NEXT:         [[BB_ELSE]]:
+; CHECKED-ELF-NEXT:           autdzb  x0
+; CHECKED-ELF-NEXT:         [[BB_RETURN]]:
+; CHECKED-ELF-NEXT:           ldr     x8, [x0]
+; CHECKED-NEXT:               ldr     x8, [x8]
+; CHECKED-NEXT:               ldr     x8, [x8]
+; CHECKED-NEXT:               ldr     x0, [x8]
+; CHECKED-NEXT:               ret
+;
+; TRAP-LABEL:        auth_speculation:
+; TRAP:                  %bb.0:
+; TRAP-DARWIN-NEXT:        mov     x16, x0
+; TRAP-DARWIN-NEXT:        tbz     w1, #0, [[BB_ELSE:[A-Za-z0-9_.]+]]
+; TRAP-DARWIN-NEXT:      %bb.1:
+; TRAP-DARWIN-NEXT:        autdza  x16
+; TRAP-DARWIN-NEXT:        mov     x17, x16
+; TRAP-DARWIN-NEXT:        xpacd   x17
+; TRAP-DARWIN-NEXT:        cmp     x16, x17
+; TRAP-DARWIN-NEXT:        b.eq    [[L]]auth_success_18
+; TRAP-DARWIN-NEXT:        brk     #0xc472
+; TRAP-DARWIN-NEXT:      [[L]]auth_success_18:
+; TRAP-DARWIN-NEXT:        b       [[BB_RETURN:[A-Za-z0-9_.]+]]
+; TRAP-DARWIN-NEXT:      [[BB_ELSE]]:
+; TRAP-DARWIN-NEXT:        autdzb  x16
+; TRAP-DARWIN-NEXT:        mov     x17, x16
+; TRAP-DARWIN-NEXT:        xpacd   x17
+; TRAP-DARWIN-NEXT:        cmp     x16, x17
+; TRAP-DARWIN-NEXT:        b.eq    [[L]]auth_success_19
+; TRAP-DARWIN-NEXT:        brk     #0xc473
+; TRAP-DARWIN-NEXT:      [[L]]auth_success_19:
+; TRAP-DARWIN-NEXT:      [[BB_RETURN]]:
+; TRAP-DARWIN-NEXT:        ldr     x8, [x16]
+; TRAP-ELF-NEXT:           tbz     w1, #0, [[BB_ELSE:[A-Za-z0-9_.]+]]
+; TRAP-ELF-NEXT:         %bb.1:
+; TRAP-ELF-NEXT:           autdza  x0
+; TRAP-ELF-NEXT:           mov     x8, x0
+; TRAP-ELF-NEXT:           xpacd   x8
+; TRAP-ELF-NEXT:           cmp     x0, x8
+; TRAP-ELF-NEXT:           b.eq    [[L]]auth_success_18
+; TRAP-ELF-NEXT:           brk     #0xc472
+; TRAP-ELF-NEXT:         [[L]]auth_success_18:
+; TRAP-ELF-NEXT:           b       [[BB_RETURN:[A-Za-z0-9_.]+]]
+; TRAP-ELF-NEXT:         [[BB_ELSE]]:
+; TRAP-ELF-NEXT:           autdzb  x0
+; TRAP-ELF-NEXT:           mov     x8, x0
+; TRAP-ELF-NEXT:           xpacd   x8
+; TRAP-ELF-NEXT:           cmp     x0, x8
+; TRAP-ELF-NEXT:           b.eq    [[L]]auth_success_19
+; TRAP-ELF-NEXT:           brk     #0xc473
+; TRAP-ELF-NEXT:         [[L]]auth_success_19:
+; TRAP-ELF-NEXT:         [[BB_RETURN]]:
+; TRAP-ELF-NEXT:           ldr     x8, [x0]
+; TRAP-NEXT:               ldr     x8, [x8]
+; TRAP-NEXT:               ldr     x8, [x8]
+; TRAP-NEXT:               ldr     x0, [x8]
+; TRAP-NEXT:               ret
+entry:
+  br i1 %cond, label %if.then, label %if.else
+
+if.then:
+  %auted.then = tail call i64 @llvm.ptrauth.auth(i64 %signed, i32 2, i64 0)
+  br label %return
+
+if.else:
+  %auted.else = tail call i64 @llvm.ptrauth.auth(i64 %signed, i32 3, i64 0)
+  br label %return
+
+return:
+  %auted = phi i64 [ %auted.then, %if.then ], [ %auted.else, %if.else ]
+
+  ; A sequence of instructions that is common to both "then" and "else"
+  ; branches and is expensive to duplicate.
+  %ptr.0 = inttoptr i64 %auted to ptr
+  %ptr.1 = load ptr, ptr %ptr.0
+  %ptr.2 = load ptr, ptr %ptr.1
+  %ptr.3 = load ptr, ptr %ptr.2
+  %ptr.4 = load ptr, ptr %ptr.3
+  ret ptr %ptr.4
+}
+
 declare i64 @llvm.ptrauth.auth(i64, i32, i64)
 declare i64 @llvm.ptrauth.resign(i64, i32, i64, i32, i64)

@atrosinenko atrosinenko merged commit ab3c0ca into main Aug 27, 2025
13 checks passed
@atrosinenko atrosinenko deleted the users/atrosinenko/aut-speculation branch August 27, 2025 13:46
@atrosinenko atrosinenko added this to the LLVM 21.x Release milestone Aug 28, 2025
@github-project-automation github-project-automation bot moved this to Needs Triage in LLVM Release Status Aug 28, 2025
@atrosinenko
Copy link
Contributor Author

/cherry-pick ab3c0ca

@llvmbot
Copy link
Member

llvmbot commented Aug 28, 2025

/pull-request #155874

@llvmbot llvmbot moved this from Needs Triage to Done in LLVM Release Status Aug 28, 2025
tru pushed a commit to llvmbot/llvm-project that referenced this pull request Sep 3, 2025
…5372)

A generic authentication instruction may crash the process on failure.
Furthermore, it can be executed conditionally and/or its signing schema
can be chosen dynamically. For this reason, while it may be beneficial
to permit DCE to remove AUTx16x17 or AUTxMxN instructions unless their
results have any uses (at least fake ones, if we just want to check the
signature), AUT instructions are not safe to be executed speculatively.

As a quick fix for miscompilation possibility, this patch marks AUTxMxN
pseudo instruction as having unmodelled side effects.

(cherry picked from commit ab3c0ca)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

Successfully merging this pull request may close these issues.

3 participants