From 5dfaca743fd9a7bab5ceb51398dfb5a6b45a3c0d Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 28 Oct 2026 10:41:28 +0100 Subject: [PATCH] fix(arm64): unwind past PAC-signed return addresses `strip_pac()` only strips with a mask, and nothing sets one. The `__bionic_clear_pac_bits()` fallback was compiled out because it is not in the NDK, so a signed return address ended the unwind. Strip with `xpaclri` like bionic does, spelled as `hint #7` for assemblers without Armv8.3-A support. It is a NOP on older CPUs. Pixel 8 Pro (Tensor G3, Android 17), `abort()` through two `-mbranch-protection=pac-ret` functions, unwound from a SIGABRT handler like sentry-native's inproc backend. Before: #00 pc 000000000007fdc0 .../libc.so (abort+160) #01 pc 006e8cdf7ce216d0 After: #00 pc 000000000007fdc0 .../libc.so (abort+160) #01 pc 000000000002867c .../pac_test (pac_crash()+12) #02 pc 000000000002868c .../pac_test (pac_caller()+12) #03 pc 0000000000028708 .../pac_test (main+120) #04 pc 000000000007183c .../libc.so (__libc_init+124) Ref: getsentry/sentry-native#2258 --- RegsArm64.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/RegsArm64.cpp b/RegsArm64.cpp index 29c3bd7..a47edf4 100644 --- a/RegsArm64.cpp +++ b/RegsArm64.cpp @@ -67,6 +67,15 @@ static uint64_t strip_pac(uint64_t pc, uint64_t mask) { pc = __bionic_clear_pac_bits(pc); #endif #endif // SENTRY_REMOVED +#ifndef SENTRY_ADDED +#if defined(__aarch64__) + // __bionic_clear_pac_bits() is not in the NDK. Use xpaclri like it does, + // spelled as hint #7 for assemblers without Armv8.3-A support. + register uint64_t x30 __asm("x30") = pc; + asm("hint #7" : "+r"(x30)); + pc = x30; +#endif +#endif // SENTRY_ADDED } return pc; }