Disable pointer authentication in app processes.

Unfortunately we have discovered that some applications in the wild
are using PAC instructions incorrectly. To keep those applications
working on PAC enabled devices, disable PAC in application processes
for now.

Bug: 212660282
Change-Id: I3030c47be9d02a27505bd4775c1982a20755758c
diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
index 121b26f..08fb187 100644
--- a/libc/bionic/pthread_create.cpp
+++ b/libc/bionic/pthread_create.cpp
@@ -45,6 +45,7 @@
 #include "private/bionic_defs.h"
 #include "private/bionic_globals.h"
 #include "platform/bionic/macros.h"
+#include "platform/bionic/pac.h"
 #include "private/bionic_ssp.h"
 #include "private/bionic_systrace.h"
 #include "private/bionic_tls.h"
@@ -331,11 +332,9 @@
 extern "C" int __rt_sigprocmask(int, const sigset64_t*, sigset64_t*, size_t);
 
 __attribute__((no_sanitize("hwaddress")))
-#ifdef __aarch64__
 // This function doesn't return, but it does appear in stack traces. Avoid using return PAC in this
 // function because we may end up resetting IA, which may confuse unwinders due to mismatching keys.
-__attribute__((target("branch-protection=bti")))
-#endif
+__BIONIC_DISABLE_PAUTH
 static int __pthread_start(void* arg) {
   pthread_internal_t* thread = reinterpret_cast<pthread_internal_t*>(arg);
 
diff --git a/libc/platform/bionic/pac.h b/libc/platform/bionic/pac.h
index 34efc48..c311651 100644
--- a/libc/platform/bionic/pac.h
+++ b/libc/platform/bionic/pac.h
@@ -29,6 +29,7 @@
 #pragma once
 
 #include <stddef.h>
+#include <sys/prctl.h>
 
 inline uintptr_t __bionic_clear_pac_bits(uintptr_t ptr) {
 #if defined(__aarch64__)
@@ -40,3 +41,39 @@
   return ptr;
 #endif
 }
+
+#ifdef __aarch64__
+// The default setting for branch-protection enables both PAC and BTI, so by
+// overriding it to only enable BTI we disable PAC.
+#define __BIONIC_DISABLE_PAUTH __attribute__((target("branch-protection=bti")))
+#else
+#define __BIONIC_DISABLE_PAUTH
+#endif
+
+#ifdef __aarch64__
+// Disable PAC (i.e. make the signing and authentication instructions into no-ops) for the lifetime
+// of this object.
+class ScopedDisablePAC {
+  int prev_enabled_keys_;
+
+ public:
+  // Disabling IA will invalidate the return address in this function if it is signed, so we need to
+  // make sure that this function does not sign its return address. Likewise for the destructor.
+  __BIONIC_DISABLE_PAUTH
+  ScopedDisablePAC() {
+    // These prctls will fail (resulting in a no-op, the intended behavior) if PAC is not supported.
+    prev_enabled_keys_ = prctl(PR_PAC_GET_ENABLED_KEYS, 0, 0, 0, 0);
+    prctl(PR_PAC_SET_ENABLED_KEYS, prev_enabled_keys_, 0, 0, 0);
+  }
+
+  __BIONIC_DISABLE_PAUTH
+  ~ScopedDisablePAC() {
+    prctl(PR_PAC_SET_ENABLED_KEYS, prev_enabled_keys_, prev_enabled_keys_, 0, 0);
+  }
+};
+#else
+struct ScopedDisablePAC {
+  // Silence unused variable warnings in non-aarch64 builds.
+  ScopedDisablePAC() {}
+};
+#endif