Switch to the new kernel API for obtaining fault address tag bits.

The discussion on LKML is converging on v16 of the fault address tag
bits patch [1]. In this version of the patch the presence of the tag
bits in si_addr is controlled by a sa_flags bit, and a protocol is
introduced to allow userspace to detect kernel support for sa_flags
bits. Update the tombstone signal handler to use this API to read
the tag bits, update the interceptors in libsigchain to implement
the flag support detection protocol and hide the tag bits in si_addr
from chained signal handlers that did not request them to match the
kernel behavior.

[1] https://lore.kernel.org/linux-arm-kernel/cover.1605235762.git.pcc@google.com/

Change-Id: I57f24c07c01ceb3e5b81cfc15edf559ef7dfc740
diff --git a/sigchainlib/sigchain_test.cc b/sigchainlib/sigchain_test.cc
index bb99787..4ef98c2 100644
--- a/sigchainlib/sigchain_test.cc
+++ b/sigchainlib/sigchain_test.cc
@@ -238,3 +238,32 @@
   ASSERT_EQ(1, called);
   called = 0;
 }
+
+TEST_F(SigchainTest, fault_address_tag) {
+#define SA_EXPOSE_TAGBITS 0x00000800
+#if defined(__aarch64__)
+  struct sigaction action = {};
+  action.sa_flags = SA_SIGINFO;
+  action.sa_sigaction = [](int, siginfo_t* siginfo, void*) {
+    _exit(reinterpret_cast<uintptr_t>(siginfo->si_addr) >> 56);
+  };
+  ASSERT_EQ(0, sigaction(SIGSEGV, &action, nullptr));
+
+  auto* tagged_null = reinterpret_cast<int*>(0x2bULL << 56);
+  EXPECT_EXIT({ volatile int load __attribute__((unused)) = *tagged_null; },
+              testing::ExitedWithCode(0), "");
+
+  // Our sigaction implementation always implements the "clear unknown bits"
+  // semantics for oldact.sa_flags regardless of kernel version so we rely on it
+  // here to test for kernel support for SA_EXPOSE_TAGBITS.
+  action.sa_flags = SA_SIGINFO | SA_EXPOSE_TAGBITS;
+  ASSERT_EQ(0, sigaction(SIGSEGV, &action, nullptr));
+  ASSERT_EQ(0, sigaction(SIGSEGV, nullptr, &action));
+  if (action.sa_flags & SA_EXPOSE_TAGBITS) {
+    EXPECT_EXIT({ volatile int load __attribute__((unused)) = *tagged_null; },
+                testing::ExitedWithCode(0x2b), "");
+  }
+#else
+  GTEST_SKIP() << "arm64 only";
+#endif
+}