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

     1  // Copyright 2018 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  // Tests to verify that the behavior of linux and gvisor matches when
    16  // 'sysret' returns to bad (aka non-canonical) %rip or %rsp.
    17  
    18  #include <linux/elf.h>
    19  #include <sys/ptrace.h>
    20  #include <sys/user.h>
    21  
    22  #include "gtest/gtest.h"
    23  #include "test/util/logging.h"
    24  #include "test/util/test_util.h"
    25  
    26  namespace gvisor {
    27  namespace testing {
    28  
    29  namespace {
    30  
    31  constexpr uint64_t kNonCanonicalRip = 0xCCCC000000000000;
    32  constexpr uint64_t kNonCanonicalRsp = 0xFFFF000000000000;
    33  
    34  class SysretTest : public ::testing::Test {
    35   protected:
    36    struct user_regs_struct regs_;
    37    struct iovec iov;
    38    pid_t child_;
    39  
    40    void SetUp() override {
    41      pid_t pid = fork();
    42  
    43      // Child.
    44      if (pid == 0) {
    45        TEST_PCHECK(ptrace(PTRACE_TRACEME, 0, 0, 0) == 0);
    46        MaybeSave();
    47        TEST_PCHECK(raise(SIGSTOP) == 0);
    48        MaybeSave();
    49        _exit(0);
    50      }
    51  
    52      // Parent.
    53      int status;
    54      memset(&iov, 0, sizeof(iov));
    55      ASSERT_THAT(pid, SyscallSucceeds());  // Might still be < 0.
    56      ASSERT_THAT(waitpid(pid, &status, 0), SyscallSucceedsWithValue(pid));
    57      EXPECT_TRUE(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP);
    58  
    59      iov.iov_base = &regs_;
    60      iov.iov_len = sizeof(regs_);
    61      ASSERT_THAT(ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov),
    62                  SyscallSucceeds());
    63  
    64      child_ = pid;
    65    }
    66  
    67    void Detach() {
    68      ASSERT_THAT(ptrace(PTRACE_DETACH, child_, 0, 0), SyscallSucceeds());
    69    }
    70  
    71    void SetRip(uint64_t newrip) {
    72  #if defined(__x86_64__)
    73      regs_.rip = newrip;
    74  #elif defined(__aarch64__)
    75      regs_.pc = newrip;
    76  #else
    77  #error "Unknown architecture"
    78  #endif
    79      ASSERT_THAT(ptrace(PTRACE_SETREGSET, child_, NT_PRSTATUS, &iov),
    80                  SyscallSucceeds());
    81    }
    82  
    83    void SetRsp(uint64_t newrsp) {
    84  #if defined(__x86_64__)
    85      regs_.rsp = newrsp;
    86  #elif defined(__aarch64__)
    87      regs_.sp = newrsp;
    88  #else
    89  #error "Unknown architecture"
    90  #endif
    91      ASSERT_THAT(ptrace(PTRACE_SETREGSET, child_, NT_PRSTATUS, &iov),
    92                  SyscallSucceeds());
    93    }
    94  
    95    // Wait waits for the child pid and returns the exit status.
    96    int Wait() {
    97      int status;
    98      while (true) {
    99        int rval = wait4(child_, &status, 0, NULL);
   100        if (rval < 0) {
   101          return rval;
   102        }
   103        if (rval == child_) {
   104          return status;
   105        }
   106      }
   107    }
   108  };
   109  
   110  TEST_F(SysretTest, JustDetach) {
   111    Detach();
   112    int status = Wait();
   113    EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0)
   114        << "status = " << status;
   115  }
   116  
   117  TEST_F(SysretTest, BadRip) {
   118    SetRip(kNonCanonicalRip);
   119    Detach();
   120    int status = Wait();
   121    EXPECT_TRUE(WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV)
   122        << "status = " << status;
   123  }
   124  
   125  TEST_F(SysretTest, BadRsp) {
   126    SetRsp(kNonCanonicalRsp);
   127    Detach();
   128    int status = Wait();
   129  #if defined(__x86_64__)
   130    EXPECT_TRUE(WIFSIGNALED(status) && WTERMSIG(status) == SIGBUS)
   131        << "status = " << status;
   132  #elif defined(__aarch64__)
   133    EXPECT_TRUE(WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV)
   134        << "status = " << status;
   135  #else
   136  #error "Unknown architecture"
   137  #endif
   138  }
   139  }  // namespace
   140  
   141  }  // namespace testing
   142  }  // namespace gvisor