github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/rseq.cc (about)

     1  // Copyright 2019 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  #include <errno.h>
    16  #include <signal.h>
    17  #include <sys/syscall.h>
    18  #include <sys/types.h>
    19  #include <sys/wait.h>
    20  #include <unistd.h>
    21  
    22  #include "gtest/gtest.h"
    23  #include "test/syscalls/linux/rseq/test.h"
    24  #include "test/syscalls/linux/rseq/uapi.h"
    25  #include "test/util/logging.h"
    26  #include "test/util/multiprocess_util.h"
    27  #include "test/util/posix_error.h"
    28  #include "test/util/test_util.h"
    29  
    30  namespace gvisor {
    31  namespace testing {
    32  
    33  namespace {
    34  
    35  using ::testing::AnyOf;
    36  using ::testing::Eq;
    37  
    38  // Syscall test for rseq (restartable sequences).
    39  //
    40  // We must be very careful about how these tests are written. Each thread may
    41  // only have one struct rseq registration, which may be done automatically at
    42  // thread start (as of 2019-11-13, glibc does *not* support rseq and thus does
    43  // not do so, but other libraries do).
    44  //
    45  // Testing of rseq is thus done primarily in a child process with no
    46  // registration. This means exec'ing a nostdlib binary, as rseq registration can
    47  // only be cleared by execve (or knowing the old rseq address), and glibc (based
    48  // on the current unmerged patches) register rseq before calling main()).
    49  
    50  int RSeq(struct rseq* rseq, uint32_t rseq_len, int flags, uint32_t sig) {
    51    return syscall(kRseqSyscall, rseq, rseq_len, flags, sig);
    52  }
    53  
    54  // Returns true if this kernel supports the rseq syscall.
    55  PosixErrorOr<bool> RSeqSupported() {
    56    // We have to be careful here, there are three possible cases:
    57    //
    58    // 1. rseq is not supported -> ENOSYS
    59    // 2. rseq is supported and not registered -> success, but we should
    60    //    unregister.
    61    // 3. rseq is supported and registered -> EINVAL (most likely).
    62  
    63    // The only validation done on new registrations is that rseq is aligned and
    64    // writable.
    65    rseq rseq = {};
    66    int ret = RSeq(&rseq, sizeof(rseq), 0, 0);
    67    if (ret == 0) {
    68      // Successfully registered, rseq is supported. Unregister.
    69      ret = RSeq(&rseq, sizeof(rseq), kRseqFlagUnregister, 0);
    70      if (ret != 0) {
    71        return PosixError(errno);
    72      }
    73      return true;
    74    }
    75  
    76    switch (errno) {
    77      case ENOSYS:
    78        // Not supported.
    79        return false;
    80      case EINVAL:
    81        // Supported, but already registered. EINVAL returned because we provided
    82        // a different address.
    83        return true;
    84      default:
    85        // Unknown error.
    86        return PosixError(errno);
    87    }
    88  }
    89  
    90  constexpr char kRseqBinary[] = "test/syscalls/linux/rseq/rseq";
    91  
    92  void RunChildTest(std::string test_case, int want_status) {
    93    std::string path = RunfilePath(kRseqBinary);
    94  
    95    pid_t child_pid = -1;
    96    int execve_errno = 0;
    97    auto cleanup = ASSERT_NO_ERRNO_AND_VALUE(
    98        ForkAndExec(path, {path, test_case}, {}, &child_pid, &execve_errno));
    99  
   100    ASSERT_GT(child_pid, 0);
   101    ASSERT_EQ(execve_errno, 0);
   102  
   103    int status = 0;
   104    ASSERT_THAT(RetryEINTR(waitpid)(child_pid, &status, 0), SyscallSucceeds());
   105    ASSERT_THAT(status, AnyOf(Eq(want_status), Eq(128 + want_status)));
   106  }
   107  
   108  // Test that rseq must be aligned.
   109  TEST(RseqTest, Unaligned) {
   110    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported()));
   111  
   112    RunChildTest(kRseqTestUnaligned, 0);
   113  }
   114  
   115  // Sanity test that registration works.
   116  TEST(RseqTest, Register) {
   117    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported()));
   118  
   119    RunChildTest(kRseqTestRegister, 0);
   120  }
   121  
   122  // Registration can't be done twice.
   123  TEST(RseqTest, DoubleRegister) {
   124    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported()));
   125  
   126    RunChildTest(kRseqTestDoubleRegister, 0);
   127  }
   128  
   129  // Registration can be done again after unregister.
   130  TEST(RseqTest, RegisterUnregister) {
   131    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported()));
   132  
   133    RunChildTest(kRseqTestRegisterUnregister, 0);
   134  }
   135  
   136  // The pointer to rseq must match on register/unregister.
   137  TEST(RseqTest, UnregisterDifferentPtr) {
   138    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported()));
   139  
   140    RunChildTest(kRseqTestUnregisterDifferentPtr, 0);
   141  }
   142  
   143  // The signature must match on register/unregister.
   144  TEST(RseqTest, UnregisterDifferentSignature) {
   145    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported()));
   146  
   147    RunChildTest(kRseqTestUnregisterDifferentSignature, 0);
   148  }
   149  
   150  // The CPU ID is initialized.
   151  TEST(RseqTest, CPU) {
   152    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported()));
   153  
   154    RunChildTest(kRseqTestCPU, 0);
   155  }
   156  
   157  // Critical section is eventually aborted.
   158  TEST(RseqTest, Abort) {
   159    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported()));
   160  
   161    RunChildTest(kRseqTestAbort, 0);
   162  }
   163  
   164  // Abort may be before the critical section.
   165  TEST(RseqTest, AbortBefore) {
   166    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported()));
   167  
   168    RunChildTest(kRseqTestAbortBefore, 0);
   169  }
   170  
   171  // Signature must match.
   172  TEST(RseqTest, AbortSignature) {
   173    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported()));
   174  
   175    RunChildTest(kRseqTestAbortSignature, SIGSEGV);
   176  }
   177  
   178  // Abort must not be in the critical section.
   179  TEST(RseqTest, AbortPreCommit) {
   180    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported()));
   181  
   182    RunChildTest(kRseqTestAbortPreCommit, SIGSEGV);
   183  }
   184  
   185  // rseq.rseq_cs is cleared on abort.
   186  TEST(RseqTest, AbortClearsCS) {
   187    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported()));
   188  
   189    RunChildTest(kRseqTestAbortClearsCS, 0);
   190  }
   191  
   192  // rseq.rseq_cs is cleared on abort outside of critical section.
   193  TEST(RseqTest, InvalidAbortClearsCS) {
   194    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported()));
   195  
   196    RunChildTest(kRseqTestInvalidAbortClearsCS, 0);
   197  }
   198  
   199  }  // namespace
   200  
   201  }  // namespace testing
   202  }  // namespace gvisor