Skip to content

Conversation

@airpfei
Copy link
Contributor

@airpfei airpfei commented Aug 11, 2025

The root cause of this crash is that prctl(PR_PAC_RESET_KEYS) generates a new PAC key. As a result, paciasp and autiasp use different keys, leading to the crash.

The solution is: if prctl's option is PR_PAC_RESET_KEYS, call real_prctl directly. This is implemented in assembly, so there are no PAC instructions involved.

Related issue: android/ndk#1848

0000000000095468 <__interceptor_prctl>:
   95468: d503233f     	paciasp
   9546c: d10183ff     	sub	sp, sp, #0x60
   95470: a90267fe     	stp	x30, x25, [sp, #0x20]
   95474: a9035ff8     	stp	x24, x23, [sp, #0x30]
   95478: a90457f6     	stp	x22, x21, [sp, #0x40]
   9547c: a9054ff4     	stp	x20, x19, [sp, #0x50]
   95480: aa1e03f4     	mov	x20, x30
   95484: aa0403f3     	mov	x19, x4
   95488: aa0303f6     	mov	x22, x3
   9548c: aa0203f7     	mov	x23, x2
   95490: aa0103f5     	mov	x21, x1
   95494: 2a0003f8     	mov	w24, w0
   95498: 940172ec     	bl	0xf2048 <_ZN6__tsan10cur_threadEv>
   9549c: 4f05e540     	movi	v0.16b, #0xaa
   954a0: 52801548     	mov	w8, #0xaa               // =170
   954a4: aa1403fe     	mov	x30, x20
   954a8: 39007fe8     	strb	w8, [sp, #0x1f]
   954ac: aa0003f4     	mov	x20, x0
   954b0: 910043e0     	add	x0, sp, #0x10
   954b4: aa1403e1     	mov	x1, x20
   954b8: bc01b3e0     	stur	s0, [sp, #0x1b]
   954bc: d50320ff     	xpaclri
   954c0: aa1e03e3     	mov	x3, x30
   954c4: 97ffb461     	bl	0x82648 <_ZN6__tsan17ScopedInterceptorC2EPNS_11ThreadStateEPKcm>
   954c8: 97ff75ea     	bl	0x72c70 <_ZN11__sanitizer10StackTrace12GetCurrentPcEv>
   954cc: 394c2688     	ldrb	w8, [x20, #0x309]
   954d0: 7100051f     	cmp	w8, #0x1
   954d4: 540000c1     	b.ne	0x954ec <__interceptor_prctl+0x84>
   954d8: b9400a88     	ldr	w8, [x20, #0x8]
   954dc: 35000088     	cbnz	w8, 0x954ec <__interceptor_prctl+0x84>
   954e0: 394c2288     	ldrb	w8, [x20, #0x308]
   954e4: 7100051f     	cmp	w8, #0x1
   954e8: 54000501     	b.ne	0x95588 <__interceptor_prctl+0x120>
   954ec: f0001128     	adrp	x8, 0x2bc000 <_ZN6__tsanL23interceptor_placeholderE+0xcac0>
   954f0: 2a1803e0     	mov	w0, w24
   954f4: aa1503e1     	mov	x1, x21
   954f8: f9452508     	ldr	x8, [x8, #0xa48]
   954fc: aa1703e2     	mov	x2, x23
   95500: aa1603e3     	mov	x3, x22
   95504: aa1303e4     	mov	x4, x19
   95508: d63f0100     	blr	x8
   9550c: f9400bf3     	ldr	x19, [sp, #0x10]
   95510: 394c2668     	ldrb	w8, [x19, #0x309]
   95514: 7100051f     	cmp	w8, #0x1
   95518: 540002a1     	b.ne	0x9556c <__interceptor_prctl+0x104>
   9551c: 39406be8     	ldrb	w8, [sp, #0x1a]
   95520: 7100051f     	cmp	w8, #0x1
   95524: 54000d60     	b.eq	0x956d0 <__interceptor_prctl+0x268>
   95528: 394067e8     	ldrb	w8, [sp, #0x19]
   9552c: 7100051f     	cmp	w8, #0x1
   95530: 54000de0     	b.eq	0x956ec <__interceptor_prctl+0x284>
   95534: b9400a68     	ldr	w8, [x19, #0x8]
   95538: 350001a8     	cbnz	w8, 0x9556c <__interceptor_prctl+0x104>
   9553c: b9403268     	ldr	w8, [x19, #0x30]
   95540: 35000e48     	cbnz	w8, 0x95708 <__interceptor_prctl+0x2a0>
   95544: f9400e68     	ldr	x8, [x19, #0x18]
   95548: 91002109     	add	x9, x8, #0x8
   9554c: f27c1d3f     	tst	x9, #0xff0
   95550: 54000ec0     	b.eq	0x95728 <__interceptor_prctl+0x2c0>
   95554: 5280004a     	mov	w10, #0x2               // =2
   95558: f900010a     	str	x10, [x8]
   9555c: f9000e69     	str	x9, [x19, #0x18]
   95560: f9400a68     	ldr	x8, [x19, #0x10]
   95564: d1002108     	sub	x8, x8, #0x8
   95568: f9000a68     	str	x8, [x19, #0x10]
   9556c: a9454ff4     	ldp	x20, x19, [sp, #0x50]
   95570: a94457f6     	ldp	x22, x21, [sp, #0x40]
   95574: a9435ff8     	ldp	x24, x23, [sp, #0x30]
   95578: a94267fe     	ldp	x30, x25, [sp, #0x20]
   9557c: 910183ff     	add	sp, sp, #0x60
   95580: d50323bf     	autiasp
   95584: d65f03c0     	ret
   ...

@github-actions
Copy link

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot
Copy link
Member

llvmbot commented Aug 11, 2025

@llvm/pr-subscribers-compiler-rt-sanitizer

Author: Fei Peng (airpfei)

Changes

The root cause of this crash is that prctl(PR_PAC_RESET_KEYS) generates a new PAC key. As a result, paciasp and autiasp use different keys, leading to the crash.

The solution is: if prctl's option is PR_PAC_RESET_KEYS, call real_prctl directly. This is implemented in assembly, so there are no PAC instructions involved.

Related issue: android/ndk#1848

0000000000095468 &lt;__interceptor_prctl&gt;:
   95468: d503233f     	paciasp
   9546c: d10183ff     	sub	sp, sp, #<!-- -->0x60
   95470: a90267fe     	stp	x30, x25, [sp, #<!-- -->0x20]
   95474: a9035ff8     	stp	x24, x23, [sp, #<!-- -->0x30]
   95478: a90457f6     	stp	x22, x21, [sp, #<!-- -->0x40]
   9547c: a9054ff4     	stp	x20, x19, [sp, #<!-- -->0x50]
   95480: aa1e03f4     	mov	x20, x30
   95484: aa0403f3     	mov	x19, x4
   95488: aa0303f6     	mov	x22, x3
   9548c: aa0203f7     	mov	x23, x2
   95490: aa0103f5     	mov	x21, x1
   95494: 2a0003f8     	mov	w24, w0
   95498: 940172ec     	bl	0xf2048 &lt;_ZN6__tsan10cur_threadEv&gt;
   9549c: 4f05e540     	movi	v0.16b, #<!-- -->0xaa
   954a0: 52801548     	mov	w8, #<!-- -->0xaa               // =170
   954a4: aa1403fe     	mov	x30, x20
   954a8: 39007fe8     	strb	w8, [sp, #<!-- -->0x1f]
   954ac: aa0003f4     	mov	x20, x0
   954b0: 910043e0     	add	x0, sp, #<!-- -->0x10
   954b4: aa1403e1     	mov	x1, x20
   954b8: bc01b3e0     	stur	s0, [sp, #<!-- -->0x1b]
   954bc: d50320ff     	xpaclri
   954c0: aa1e03e3     	mov	x3, x30
   954c4: 97ffb461     	bl	0x82648 &lt;_ZN6__tsan17ScopedInterceptorC2EPNS_11ThreadStateEPKcm&gt;
   954c8: 97ff75ea     	bl	0x72c70 &lt;_ZN11__sanitizer10StackTrace12GetCurrentPcEv&gt;
   954cc: 394c2688     	ldrb	w8, [x20, #<!-- -->0x309]
   954d0: 7100051f     	cmp	w8, #<!-- -->0x1
   954d4: 540000c1     	b.ne	0x954ec &lt;__interceptor_prctl+0x84&gt;
   954d8: b9400a88     	ldr	w8, [x20, #<!-- -->0x8]
   954dc: 35000088     	cbnz	w8, 0x954ec &lt;__interceptor_prctl+0x84&gt;
   954e0: 394c2288     	ldrb	w8, [x20, #<!-- -->0x308]
   954e4: 7100051f     	cmp	w8, #<!-- -->0x1
   954e8: 54000501     	b.ne	0x95588 &lt;__interceptor_prctl+0x120&gt;
   954ec: f0001128     	adrp	x8, 0x2bc000 &lt;_ZN6__tsanL23interceptor_placeholderE+0xcac0&gt;
   954f0: 2a1803e0     	mov	w0, w24
   954f4: aa1503e1     	mov	x1, x21
   954f8: f9452508     	ldr	x8, [x8, #<!-- -->0xa48]
   954fc: aa1703e2     	mov	x2, x23
   95500: aa1603e3     	mov	x3, x22
   95504: aa1303e4     	mov	x4, x19
   95508: d63f0100     	blr	x8
   9550c: f9400bf3     	ldr	x19, [sp, #<!-- -->0x10]
   95510: 394c2668     	ldrb	w8, [x19, #<!-- -->0x309]
   95514: 7100051f     	cmp	w8, #<!-- -->0x1
   95518: 540002a1     	b.ne	0x9556c &lt;__interceptor_prctl+0x104&gt;
   9551c: 39406be8     	ldrb	w8, [sp, #<!-- -->0x1a]
   95520: 7100051f     	cmp	w8, #<!-- -->0x1
   95524: 54000d60     	b.eq	0x956d0 &lt;__interceptor_prctl+0x268&gt;
   95528: 394067e8     	ldrb	w8, [sp, #<!-- -->0x19]
   9552c: 7100051f     	cmp	w8, #<!-- -->0x1
   95530: 54000de0     	b.eq	0x956ec &lt;__interceptor_prctl+0x284&gt;
   95534: b9400a68     	ldr	w8, [x19, #<!-- -->0x8]
   95538: 350001a8     	cbnz	w8, 0x9556c &lt;__interceptor_prctl+0x104&gt;
   9553c: b9403268     	ldr	w8, [x19, #<!-- -->0x30]
   95540: 35000e48     	cbnz	w8, 0x95708 &lt;__interceptor_prctl+0x2a0&gt;
   95544: f9400e68     	ldr	x8, [x19, #<!-- -->0x18]
   95548: 91002109     	add	x9, x8, #<!-- -->0x8
   9554c: f27c1d3f     	tst	x9, #<!-- -->0xff0
   95550: 54000ec0     	b.eq	0x95728 &lt;__interceptor_prctl+0x2c0&gt;
   95554: 5280004a     	mov	w10, #<!-- -->0x2               // =2
   95558: f900010a     	str	x10, [x8]
   9555c: f9000e69     	str	x9, [x19, #<!-- -->0x18]
   95560: f9400a68     	ldr	x8, [x19, #<!-- -->0x10]
   95564: d1002108     	sub	x8, x8, #<!-- -->0x8
   95568: f9000a68     	str	x8, [x19, #<!-- -->0x10]
   9556c: a9454ff4     	ldp	x20, x19, [sp, #<!-- -->0x50]
   95570: a94457f6     	ldp	x22, x21, [sp, #<!-- -->0x40]
   95574: a9435ff8     	ldp	x24, x23, [sp, #<!-- -->0x30]
   95578: a94267fe     	ldp	x30, x25, [sp, #<!-- -->0x20]
   9557c: 910183ff     	add	sp, sp, #<!-- -->0x60
   95580: d50323bf     	autiasp
   95584: d65f03c0     	ret
   ...

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

1 Files Affected:

  • (modified) compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc (+48-1)
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
index 2d6cf7fc3282f..b177fdc62293f 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -1285,7 +1285,54 @@ INTERCEPTOR(int, puts, char *s) {
 #endif
 
 #if SANITIZER_INTERCEPT_PRCTL
-INTERCEPTOR(int, prctl, int option, unsigned long arg2, unsigned long arg3,
+
+#if defined(__aarch64__)
+// https://llvm.org/docs/PointerAuth.html
+// AArch64 is currently the only architecture with full support for PAC. If
+// other architectures add support for PAC, similar logic should be implemented.
+// Because after resetting the PAC key, WRAP(prctl) will continue to perform
+// authentication using the old key, the authentication will fail. The solution
+// is to call REAL(prctl) directly when the prctl option is PR_PAC_RESET_KEYS.
+
+#define PR_PAC_RESET_KEYS 54
+
+#define PRCTL_INTERCEPTOR(ret_type, func, ...)                              \
+  DEFINE_REAL(ret_type, func, __VA_ARGS__)                                  \
+  extern "C" ret_type func(__VA_ARGS__);                                    \
+  extern "C" ret_type TRAMPOLINE(func)(__VA_ARGS__);                        \
+  extern "C" ret_type __interceptor_##func(__VA_ARGS__)                     \
+  INTERCEPTOR_ATTRIBUTE __attribute__((weak)) ALIAS(WRAP(func));            \
+  extern "C" INTERCEPTOR_ATTRIBUTE ret_type WRAP(func)(__VA_ARGS__)
+
+asm(
+  ".text\n"
+  ".weak prctl\n"
+  ".set prctl, " SANITIZER_STRINGIFY(TRAMPOLINE(prctl)) "\n"
+  ".global " SANITIZER_STRINGIFY(TRAMPOLINE(prctl)) "\n"
+  ".type " SANITIZER_STRINGIFY(TRAMPOLINE(prctl)) ", "
+      ASM_TYPE_FUNCTION_STR "\n"
+  SANITIZER_STRINGIFY(TRAMPOLINE(prctl)) ":\n"
+  C_ASM_STARTPROC "\n"
+    "cmp w0, #" SANITIZER_STRINGIFY(PR_PAC_RESET_KEYS) "\n"
+    "bne .L_wrap_prctl\n"
+    // tail jump to libc prctl
+    "adrp x6, :got:_ZN14__interception10real_prctlE\n"
+    "ldr x6, [x6, #:got_lo12:_ZN14__interception10real_prctlE]\n"
+    "ldr x6, [x6]\n"
+    "br x6\n"
+  ".L_wrap_prctl:"
+    C_ASM_TAIL_CALL(SANITIZER_STRINGIFY(TRAMPOLINE(prctl)),
+        "__interceptor_"
+        SANITIZER_STRINGIFY(ASM_PREEMPTIBLE_SYM(prctl))) "\n"
+  C_ASM_ENDPROC "\n"
+  ".size  " SANITIZER_STRINGIFY(TRAMPOLINE(prctl)) ", "
+      ".-" SANITIZER_STRINGIFY(TRAMPOLINE(prctl)) "\n"
+);
+#else
+#define PRCTL_INTERCEPTOR INTERCEPTOR
+#endif
+
+PRCTL_INTERCEPTOR(int, prctl, int option, unsigned long arg2, unsigned long arg3,
             unsigned long arg4, unsigned long arg5) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, prctl, option, arg2, arg3, arg4, arg5);

@DanielKristofKiss
Copy link
Member

We could avoid adding PAC instructions by just adding some function attributes.

#ifdef __ARM_FEATURE_BTI_DEFAULT
__attribute__((target("branch-protection=bti")))
#else
__attribute__((target("branch-protection=none")))
#endif

@airpfei airpfei force-pushed the fix_prctl_interceptor branch 2 times, most recently from 77b2232 to 5a22b88 Compare August 26, 2025 20:08
@airpfei
Copy link
Contributor Author

airpfei commented Aug 26, 2025

We could avoid adding PAC instructions by just adding some function attributes.

#ifdef __ARM_FEATURE_BTI_DEFAULT
__attribute__((target("branch-protection=bti")))
#else
__attribute__((target("branch-protection=none")))
#endif

@DanielKristofKiss just updated the change following this suggestion

Copy link
Member

@DanielKristofKiss DanielKristofKiss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! LGTM

@airpfei
Copy link
Contributor Author

airpfei commented Aug 28, 2025

@pcc Could you please review this change when you have time?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: reformat

@airpfei airpfei force-pushed the fix_prctl_interceptor branch from ba4e966 to 96db681 Compare September 2, 2025 02:06
@airpfei
Copy link
Contributor Author

airpfei commented Sep 2, 2025

Hi @pcc, I reformatted the code as suggested. Could you please approve the workflows Build and Test Linux and Build and Test Windows?

@github-actions
Copy link

github-actions bot commented Sep 2, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@airpfei airpfei force-pushed the fix_prctl_interceptor branch from 96db681 to f54025d Compare September 3, 2025 01:51
@airpfei
Copy link
Contributor Author

airpfei commented Sep 3, 2025

Hi @pcc, could you please approve the workflows again? I fixed the format issues.

@airpfei
Copy link
Contributor Author

airpfei commented Sep 3, 2025

@pcc @DanielKristofKiss
All checks has passed.
Would you mind helping to merge this patch? Thanks a lot!

@DanielKristofKiss DanielKristofKiss merged commit 6bbf0c3 into llvm:main Sep 3, 2025
9 checks passed
@github-actions
Copy link

github-actions bot commented Sep 3, 2025

@airpfei Congratulations on having your first Pull Request (PR) merged into the LLVM Project!

Your changes will be combined with recent changes from other authors, then tested by our build bots. If there is a problem with a build, you may receive a report in an email or a comment on this PR.

Please check whether problems have been caused by your change specifically, as the builds can include changes from many authors. It is not uncommon for your change to be included in a build that fails due to someone else's changes, or infrastructure issues.

How to do this, and the rest of the post-merge process, is covered in detail here.

If your change does cause a problem, it may be reverted, or you can revert it yourself. This is a normal part of LLVM development. You can fix your changes and open a new PR to merge them again.

If you don't get any reports, no action is required from you. Your changes are working as expected, well done!

@airpfei airpfei deleted the fix_prctl_interceptor branch September 3, 2025 13:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants