gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/select.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 <fcntl.h> 16 #include <sys/resource.h> 17 #include <sys/select.h> 18 #include <sys/time.h> 19 20 #include <climits> 21 #include <csignal> 22 #include <cstdio> 23 24 #include "gtest/gtest.h" 25 #include "absl/time/time.h" 26 #include "test/syscalls/linux/base_poll_test.h" 27 #include "test/util/file_descriptor.h" 28 #include "test/util/multiprocess_util.h" 29 #include "test/util/posix_error.h" 30 #include "test/util/rlimit_util.h" 31 #include "test/util/temp_path.h" 32 #include "test/util/test_util.h" 33 34 namespace gvisor { 35 namespace testing { 36 namespace { 37 38 class SelectTest : public BasePollTest { 39 protected: 40 void SetUp() override { BasePollTest::SetUp(); } 41 void TearDown() override { BasePollTest::TearDown(); } 42 }; 43 44 // See that when there are no FD sets, select behaves like sleep. 45 TEST_F(SelectTest, NullFds) { 46 struct timeval timeout = absl::ToTimeval(absl::Milliseconds(10)); 47 ASSERT_THAT(select(0, nullptr, nullptr, nullptr, &timeout), 48 SyscallSucceeds()); 49 EXPECT_EQ(timeout.tv_sec, 0); 50 EXPECT_EQ(timeout.tv_usec, 0); 51 52 timeout = absl::ToTimeval(absl::Milliseconds(10)); 53 ASSERT_THAT(select(1, nullptr, nullptr, nullptr, &timeout), 54 SyscallSucceeds()); 55 EXPECT_EQ(timeout.tv_sec, 0); 56 EXPECT_EQ(timeout.tv_usec, 0); 57 } 58 59 TEST_F(SelectTest, NegativeNfds) { 60 EXPECT_THAT(select(-1, nullptr, nullptr, nullptr, nullptr), 61 SyscallFailsWithErrno(EINVAL)); 62 EXPECT_THAT(select(-100000, nullptr, nullptr, nullptr, nullptr), 63 SyscallFailsWithErrno(EINVAL)); 64 EXPECT_THAT(select(INT_MIN, nullptr, nullptr, nullptr, nullptr), 65 SyscallFailsWithErrno(EINVAL)); 66 } 67 68 TEST_F(SelectTest, ClosedFds) { 69 auto temp_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 70 FileDescriptor fd = 71 ASSERT_NO_ERRNO_AND_VALUE(Open(temp_file.path(), O_RDONLY)); 72 73 // We can't rely on a file descriptor being closed in a multi threaded 74 // application so fork to get a clean process. 75 EXPECT_THAT(InForkedProcess([&] { 76 int fd_num = fd.get(); 77 fd.reset(); 78 79 fd_set read_set; 80 FD_ZERO(&read_set); 81 FD_SET(fd_num, &read_set); 82 83 struct timeval timeout = 84 absl::ToTimeval(absl::Milliseconds(10)); 85 TEST_PCHECK(select(fd_num + 1, &read_set, nullptr, nullptr, 86 &timeout) != 0); 87 TEST_PCHECK(errno == EBADF); 88 }), 89 IsPosixErrorOkAndHolds(0)); 90 } 91 92 TEST_F(SelectTest, ZeroTimeout) { 93 struct timeval timeout = {}; 94 EXPECT_THAT(select(1, nullptr, nullptr, nullptr, &timeout), 95 SyscallSucceeds()); 96 // Ignore timeout as its value is now undefined. 97 } 98 99 // If random S/R interrupts the select, SIGALRM may be delivered before select 100 // restarts, causing the select to hang forever. 101 TEST_F(SelectTest, NoTimeout) { 102 // When there's no timeout, select may never return so set a timer. 103 SetTimer(absl::Milliseconds(100)); 104 // See that we get interrupted by the timer. 105 ASSERT_THAT(select(1, nullptr, nullptr, nullptr, nullptr), 106 SyscallFailsWithErrno(EINTR)); 107 EXPECT_TRUE(TimerFired()); 108 } 109 110 TEST_F(SelectTest, InvalidTimeoutNegative) { 111 struct timeval timeout = absl::ToTimeval(absl::Microseconds(-1)); 112 EXPECT_THAT(select(1, nullptr, nullptr, nullptr, &timeout), 113 SyscallFailsWithErrno(EINVAL)); 114 // Ignore timeout as its value is now undefined. 115 } 116 117 // Verify that a signal interrupts select. 118 // 119 // If random S/R interrupts the select, SIGALRM may be delivered before select 120 // restarts, causing the select to hang forever. 121 TEST_F(SelectTest, InterruptedBySignal) { 122 absl::Duration duration(absl::Seconds(5)); 123 struct timeval timeout = absl::ToTimeval(duration); 124 SetTimer(absl::Milliseconds(100)); 125 ASSERT_FALSE(TimerFired()); 126 ASSERT_THAT(select(1, nullptr, nullptr, nullptr, &timeout), 127 SyscallFailsWithErrno(EINTR)); 128 EXPECT_TRUE(TimerFired()); 129 // Ignore timeout as its value is now undefined. 130 } 131 132 TEST_F(SelectTest, IgnoreBitsAboveNfds) { 133 // fd_set is a bit array with at least FD_SETSIZE bits. Test that bits 134 // corresponding to file descriptors above nfds are ignored. 135 fd_set read_set; 136 FD_ZERO(&read_set); 137 constexpr int kNfds = 1; 138 for (int fd = kNfds; fd < FD_SETSIZE; fd++) { 139 FD_SET(fd, &read_set); 140 } 141 // Pass a zero timeout so that select returns immediately. 142 struct timeval timeout = {}; 143 EXPECT_THAT(select(kNfds, &read_set, nullptr, nullptr, &timeout), 144 SyscallSucceedsWithValue(0)); 145 } 146 147 // This test illustrates Linux's behavior of 'select' calls passing after 148 // setrlimit RLIMIT_NOFILE is called. In particular, versions of sshd rely on 149 // this behavior. See b/122318458. 150 TEST_F(SelectTest, SetrlimitCallNOFILE) { 151 fd_set read_set; 152 FD_ZERO(&read_set); 153 timeval timeout = {}; 154 const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE( 155 Open(NewTempAbsPath(), O_RDONLY | O_CREAT, S_IRUSR)); 156 157 Cleanup reset_rlimit = 158 ASSERT_NO_ERRNO_AND_VALUE(ScopedSetSoftRlimit(RLIMIT_NOFILE, 0)); 159 160 FD_SET(fd.get(), &read_set); 161 // this call with zero timeout should return immediately 162 EXPECT_THAT(select(fd.get() + 1, &read_set, nullptr, nullptr, &timeout), 163 SyscallSucceeds()); 164 } 165 166 } // namespace 167 } // namespace testing 168 } // namespace gvisor