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