gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/pty_root.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  #include <sys/ioctl.h>
    16  #include <termios.h>
    17  
    18  #include "gtest/gtest.h"
    19  #include "absl/base/macros.h"
    20  #include "test/util/capability_util.h"
    21  #include "test/util/file_descriptor.h"
    22  #include "test/util/posix_error.h"
    23  #include "test/util/pty_util.h"
    24  
    25  namespace gvisor {
    26  namespace testing {
    27  
    28  namespace {
    29  
    30  // StealTTY tests whether privileged processes can steal controlling terminals.
    31  // If the stealing process has CAP_SYS_ADMIN in the root user namespace, the
    32  // test ensures that stealing works. If it has non-root CAP_SYS_ADMIN, it
    33  // ensures stealing fails.
    34  TEST(JobControlRootTest, StealTTY) {
    35    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
    36  
    37    bool true_root = true;
    38    if (!IsRunningOnGvisor()) {
    39      // If running in Linux, we may only have CAP_SYS_ADMIN in a non-root user
    40      // namespace (i.e. we are not truly root). We use init_module as a proxy for
    41      // whether we are true root, as it returns EPERM immediately.
    42      ASSERT_THAT(syscall(SYS_init_module, nullptr, 0, nullptr), SyscallFails());
    43      true_root = errno != EPERM;
    44  
    45      // Make this a session leader, which also drops the controlling terminal.
    46      // In the gVisor test environment, this test will be run as the session
    47      // leader already (as the sentry init process).
    48      ASSERT_THAT(setsid(), SyscallSucceeds());
    49    }
    50  
    51    FileDescriptor master =
    52        ASSERT_NO_ERRNO_AND_VALUE(Open("/dev/ptmx", O_RDWR | O_NONBLOCK));
    53    FileDescriptor replica = ASSERT_NO_ERRNO_AND_VALUE(OpenReplica(master));
    54  
    55    // Make replica the controlling terminal.
    56    ASSERT_THAT(ioctl(replica.get(), TIOCSCTTY, 0), SyscallSucceeds());
    57  
    58    // Fork, join a new session, and try to steal the parent's controlling
    59    // terminal, which should succeed when we have CAP_SYS_ADMIN and pass an arg
    60    // of 1.
    61    pid_t child = fork();
    62    if (!child) {
    63      ASSERT_THAT(setsid(), SyscallSucceeds());
    64      // We shouldn't be able to steal the terminal with the wrong arg value.
    65      TEST_PCHECK(ioctl(replica.get(), TIOCSCTTY, 0));
    66      // We should be able to steal it if we are true root.
    67      TEST_PCHECK(true_root == !ioctl(replica.get(), TIOCSCTTY, 1));
    68      _exit(0);
    69    }
    70  
    71    int wstatus;
    72    ASSERT_THAT(waitpid(child, &wstatus, 0), SyscallSucceedsWithValue(child));
    73    ASSERT_EQ(wstatus, 0);
    74  }
    75  
    76  }  // namespace
    77  }  // namespace testing
    78  }  // namespace gvisor