Linux sandbox: Allow rseq(2)

Glibc 2.32 (development version) registers rseq on thread
startup. Because libraries' ELF constructors may see that
rseq is registered, and it is unclear that libraries should
have to deal with rseq deregistration, just allow it globally.
Otherwise rseq registration status will be out of sync
between threads which could cause unexpected issues.

Hopefully different parts of Chrome will leverage it for
fast per-cpu data.

Bug: 1104160
Change-Id: I3f93ee598004910ffde46ee782ba60b6201ae8ca
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2298525
Commit-Queue: Matthew Denton <mpdenton@chromium.org>
Reviewed-by: Robert Sesek <rsesek@chromium.org>
Cr-Commit-Position: refs/heads/master@{#792128}
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
index a6d2c0d..3c67b124 100644
--- a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
@@ -148,6 +148,15 @@
     return Allow();
 #endif
 
+#if defined(__NR_rseq) && !defined(OS_ANDROID)
+  // See https://crbug.com/1104160. Rseq can only be disabled right before an
+  // execve, because glibc registers it with the kernel and so far it's unclear
+  // whether shared libraries (which, during initialization, may observe that
+  // rseq is already registered) should have to deal with deregistration.
+  if (sysno == __NR_rseq)
+    return Allow();
+#endif
+
   if (sysno == __NR_clock_gettime || sysno == __NR_clock_nanosleep) {
     return RestrictClockID();
   }
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
index fc36187c..64ec1ce0 100644
--- a/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
@@ -166,6 +166,19 @@
   BPF_ASSERT(thread.Start());
 }
 
+// Rseq should be enabled if it exists (i.e. shouldn't receive EPERM).
+#if !defined(OS_ANDROID)
+BPF_TEST_C(BaselinePolicy, RseqEnabled, BaselinePolicy) {
+  errno = 0;
+  int res = syscall(__NR_rseq, 0, 0, 0, 0);
+
+  BPF_ASSERT_EQ(-1, res);
+  // The parameters above are invalid so the system call should fail with
+  // EINVAL, or ENOSYS if the kernel is too old to recognize the system call.
+  BPF_ASSERT(EINVAL == errno || ENOSYS == errno);
+}
+#endif  // !defined(OS_ANDROID)
+
 BPF_DEATH_TEST_C(BaselinePolicy,
                  DisallowedCloneFlagCrashes,
                  DEATH_SEGV_MESSAGE(GetCloneErrorMessageContentForTests()),