gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/kill.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 <errno.h> 16 #include <sys/syscall.h> 17 #include <sys/types.h> 18 #include <unistd.h> 19 20 #include <cerrno> 21 #include <csignal> 22 23 #include "gtest/gtest.h" 24 #include "absl/flags/flag.h" 25 #include "absl/synchronization/mutex.h" 26 #include "absl/time/clock.h" 27 #include "absl/time/time.h" 28 #include "test/util/capability_util.h" 29 #include "test/util/file_descriptor.h" 30 #include "test/util/logging.h" 31 #include "test/util/signal_util.h" 32 #include "test/util/test_util.h" 33 #include "test/util/thread_util.h" 34 35 ABSL_FLAG(int32_t, scratch_uid, 65534, "scratch UID"); 36 ABSL_FLAG(int32_t, scratch_gid, 65534, "scratch GID"); 37 38 using ::testing::Ge; 39 40 namespace gvisor { 41 namespace testing { 42 43 namespace { 44 45 TEST(KillTest, CanKillValidPid) { 46 // If pid is positive, then signal sig is sent to the process with the ID 47 // specified by pid. 48 EXPECT_THAT(kill(getpid(), 0), SyscallSucceeds()); 49 // If pid equals 0, then sig is sent to every process in the process group of 50 // the calling process. 51 EXPECT_THAT(kill(0, 0), SyscallSucceeds()); 52 53 ScopedThread([] { EXPECT_THAT(kill(gettid(), 0), SyscallSucceeds()); }); 54 } 55 56 void SigHandler(int sig, siginfo_t* info, void* context) { _exit(0); } 57 58 // If pid equals -1, then sig is sent to every process for which the calling 59 // process has permission to send signals, except for process 1 (init). 60 TEST(KillTest, CanKillAllPIDs) { 61 // If we're not running inside the sandbox, then we skip this test 62 // as our namespace may contain may more processes that cannot tolerate 63 // the signal below. We also cannot reliably create a new pid namespace 64 // for ourselves and test the same functionality. 65 SKIP_IF(!IsRunningOnGvisor()); 66 67 int pipe_fds[2]; 68 ASSERT_THAT(pipe(pipe_fds), SyscallSucceeds()); 69 FileDescriptor read_fd(pipe_fds[0]); 70 FileDescriptor write_fd(pipe_fds[1]); 71 72 pid_t pid = fork(); 73 if (pid == 0) { 74 read_fd.reset(); 75 76 struct sigaction sa; 77 sa.sa_sigaction = SigHandler; 78 sigfillset(&sa.sa_mask); 79 sa.sa_flags = SA_SIGINFO; 80 TEST_PCHECK(sigaction(SIGWINCH, &sa, nullptr) == 0); 81 MaybeSave(); 82 83 // Indicate to the parent that we're ready. 84 write_fd.reset(); 85 86 // Wait until we get the signal from the parent. 87 while (true) { 88 pause(); 89 } 90 } 91 92 ASSERT_THAT(pid, SyscallSucceeds()); 93 94 write_fd.reset(); 95 96 // Wait for the child to indicate that it's unmasked the signal by closing 97 // the write end. 98 char buf; 99 ASSERT_THAT(ReadFd(read_fd.get(), &buf, 1), SyscallSucceedsWithValue(0)); 100 101 // Signal the child and wait for it to die with status 0, indicating that 102 // it got the expected signal. 103 EXPECT_THAT(kill(-1, SIGWINCH), SyscallSucceeds()); 104 105 int status; 106 ASSERT_THAT(RetryEINTR(waitpid)(pid, &status, 0), 107 SyscallSucceedsWithValue(pid)); 108 EXPECT_TRUE(WIFEXITED(status)); 109 EXPECT_EQ(0, WEXITSTATUS(status)); 110 } 111 112 TEST(KillTest, CannotKillInvalidPID) { 113 // We need an unused pid to verify that kill fails when given one. 114 // 115 // There is no way to guarantee that a PID is unused, but the PID of a 116 // recently exited process likely won't be reused soon. 117 pid_t fake_pid = fork(); 118 if (fake_pid == 0) { 119 _exit(0); 120 } 121 122 ASSERT_THAT(fake_pid, SyscallSucceeds()); 123 124 int status; 125 ASSERT_THAT(RetryEINTR(waitpid)(fake_pid, &status, 0), 126 SyscallSucceedsWithValue(fake_pid)); 127 EXPECT_TRUE(WIFEXITED(status)); 128 EXPECT_EQ(0, WEXITSTATUS(status)); 129 130 EXPECT_THAT(kill(fake_pid, 0), SyscallFailsWithErrno(ESRCH)); 131 } 132 133 TEST(KillTest, CannotUseInvalidSignal) { 134 EXPECT_THAT(kill(getpid(), 200), SyscallFailsWithErrno(EINVAL)); 135 } 136 137 TEST(KillTest, CanKillRemoteProcess) { 138 pid_t pid = fork(); 139 if (pid == 0) { 140 while (true) { 141 pause(); 142 } 143 } 144 145 ASSERT_THAT(pid, SyscallSucceeds()); 146 147 EXPECT_THAT(kill(pid, SIGKILL), SyscallSucceeds()); 148 149 int status; 150 ASSERT_THAT(RetryEINTR(waitpid)(pid, &status, 0), 151 SyscallSucceedsWithValue(pid)); 152 EXPECT_TRUE(WIFSIGNALED(status)); 153 EXPECT_EQ(SIGKILL, WTERMSIG(status)); 154 } 155 156 TEST(KillTest, CanKillOwnProcess) { 157 EXPECT_THAT(kill(getpid(), 0), SyscallSucceeds()); 158 } 159 160 // Verify that you can kill a process even using a tid from a thread other than 161 // the group leader. 162 TEST(KillTest, CannotKillTid) { 163 pid_t tid; 164 bool tid_available = false; 165 bool finished = false; 166 absl::Mutex mu; 167 ScopedThread t([&] { 168 mu.Lock(); 169 tid = gettid(); 170 tid_available = true; 171 mu.Await(absl::Condition(&finished)); 172 mu.Unlock(); 173 }); 174 mu.LockWhen(absl::Condition(&tid_available)); 175 EXPECT_THAT(kill(tid, 0), SyscallSucceeds()); 176 finished = true; 177 mu.Unlock(); 178 } 179 180 TEST(KillTest, SetPgid) { 181 for (int i = 0; i < 10; i++) { 182 // The following in the normal pattern for creating a new process group. 183 // Both the parent and child process will call setpgid in order to avoid any 184 // race conditions. We do this ten times to catch races. 185 pid_t pid = fork(); 186 if (pid == 0) { 187 setpgid(0, 0); 188 while (true) { 189 pause(); 190 } 191 } 192 193 ASSERT_THAT(pid, SyscallSucceeds()); 194 195 // Set the child's group and exit. 196 ASSERT_THAT(setpgid(pid, pid), SyscallSucceeds()); 197 EXPECT_THAT(kill(pid, SIGKILL), SyscallSucceeds()); 198 199 int status; 200 EXPECT_THAT(RetryEINTR(waitpid)(-pid, &status, 0), 201 SyscallSucceedsWithValue(pid)); 202 EXPECT_TRUE(WIFSIGNALED(status)); 203 EXPECT_EQ(SIGKILL, WTERMSIG(status)); 204 } 205 } 206 207 TEST(KillTest, ProcessGroups) { 208 // Fork a new child. 209 // 210 // other_child is used as a placeholder process. We use this PID as our "does 211 // not exist" process group to ensure some amount of safety. (It is still 212 // possible to violate this assumption, but extremely unlikely.) 213 pid_t child = fork(); 214 if (child == 0) { 215 while (true) { 216 pause(); 217 } 218 } 219 ASSERT_THAT(child, SyscallSucceeds()); 220 221 pid_t other_child = fork(); 222 if (other_child == 0) { 223 while (true) { 224 pause(); 225 } 226 } 227 ASSERT_THAT(other_child, SyscallSucceeds()); 228 229 // Ensure the kill does not succeed without the new group. 230 EXPECT_THAT(kill(-child, SIGKILL), SyscallFailsWithErrno(ESRCH)); 231 232 // Put the child in its own process group. 233 ASSERT_THAT(setpgid(child, child), SyscallSucceeds()); 234 235 // This should be not allowed: you can only create a new group with the same 236 // id or join an existing one. The other_child group should not exist. 237 ASSERT_THAT(setpgid(child, other_child), SyscallFailsWithErrno(EPERM)); 238 239 // Done with other_child; kill it. 240 EXPECT_THAT(kill(other_child, SIGKILL), SyscallSucceeds()); 241 int status; 242 EXPECT_THAT(RetryEINTR(waitpid)(other_child, &status, 0), SyscallSucceeds()); 243 244 // Linux returns success for the no-op call. 245 ASSERT_THAT(setpgid(child, child), SyscallSucceeds()); 246 247 // Kill the child's process group. 248 ASSERT_THAT(kill(-child, SIGKILL), SyscallSucceeds()); 249 250 // Wait on the process group; ensure that the signal was as expected. 251 EXPECT_THAT(RetryEINTR(waitpid)(-child, &status, 0), 252 SyscallSucceedsWithValue(child)); 253 EXPECT_TRUE(WIFSIGNALED(status)); 254 EXPECT_EQ(SIGKILL, WTERMSIG(status)); 255 256 // Try to kill the process group again; ensure that the wait fails. 257 EXPECT_THAT(kill(-child, SIGKILL), SyscallFailsWithErrno(ESRCH)); 258 EXPECT_THAT(RetryEINTR(waitpid)(-child, &status, 0), 259 SyscallFailsWithErrno(ECHILD)); 260 } 261 262 TEST(KillTest, ChildDropsPrivsCannotKill) { 263 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SETUID))); 264 265 const int uid = absl::GetFlag(FLAGS_scratch_uid); 266 const int gid = absl::GetFlag(FLAGS_scratch_gid); 267 268 // Create the child that drops privileges and tries to kill the parent. 269 pid_t pid = fork(); 270 if (pid == 0) { 271 TEST_PCHECK(setresgid(gid, gid, gid) == 0); 272 MaybeSave(); 273 274 TEST_PCHECK(setresuid(uid, uid, uid) == 0); 275 MaybeSave(); 276 277 // setresuid should have dropped CAP_KILL. Make sure. 278 TEST_CHECK(!HaveCapability(CAP_KILL).ValueOrDie()); 279 280 // Try to kill parent with every signal-sending syscall possible. 281 pid_t parent = getppid(); 282 283 TEST_CHECK(kill(parent, SIGKILL) < 0); 284 TEST_PCHECK_MSG(errno == EPERM, "kill failed with wrong errno"); 285 MaybeSave(); 286 287 TEST_CHECK(tgkill(parent, parent, SIGKILL) < 0); 288 TEST_PCHECK_MSG(errno == EPERM, "tgkill failed with wrong errno"); 289 MaybeSave(); 290 291 TEST_CHECK(syscall(SYS_tkill, parent, SIGKILL) < 0); 292 TEST_PCHECK_MSG(errno == EPERM, "tkill failed with wrong errno"); 293 MaybeSave(); 294 295 siginfo_t uinfo; 296 uinfo.si_code = -1; // SI_QUEUE (allowed). 297 298 TEST_CHECK(syscall(SYS_rt_sigqueueinfo, parent, SIGKILL, &uinfo) < 0); 299 TEST_PCHECK_MSG(errno == EPERM, "rt_sigqueueinfo failed with wrong errno"); 300 MaybeSave(); 301 302 TEST_CHECK(syscall(SYS_rt_tgsigqueueinfo, parent, parent, SIGKILL, &uinfo) < 303 0); 304 TEST_PCHECK_MSG(errno == EPERM, "rt_sigqueueinfo failed with wrong errno"); 305 MaybeSave(); 306 307 _exit(0); 308 } 309 310 ASSERT_THAT(pid, SyscallSucceeds()); 311 312 int status; 313 EXPECT_THAT(RetryEINTR(waitpid)(pid, &status, 0), 314 SyscallSucceedsWithValue(pid)); 315 EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0) 316 << "status = " << status; 317 } 318 319 TEST(KillTest, CanSIGCONTSameSession) { 320 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SETUID))); 321 322 pid_t stopped_child = fork(); 323 if (stopped_child == 0) { 324 raise(SIGSTOP); 325 _exit(0); 326 } 327 328 ASSERT_THAT(stopped_child, SyscallSucceeds()); 329 330 // Put the child in its own process group. The child and parent process 331 // groups also share a session. 332 ASSERT_THAT(setpgid(stopped_child, stopped_child), SyscallSucceeds()); 333 334 // Make sure child stopped. 335 int status; 336 EXPECT_THAT(RetryEINTR(waitpid)(stopped_child, &status, WUNTRACED), 337 SyscallSucceedsWithValue(stopped_child)); 338 EXPECT_TRUE(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP) 339 << "status " << status; 340 341 const int uid = absl::GetFlag(FLAGS_scratch_uid); 342 const int gid = absl::GetFlag(FLAGS_scratch_gid); 343 344 // Drop privileges only in child process, or else this parent process won't be 345 // able to open some log files after the test ends. 346 pid_t other_child = fork(); 347 if (other_child == 0) { 348 // Drop privileges. 349 TEST_PCHECK(setresgid(gid, gid, gid) == 0); 350 MaybeSave(); 351 352 TEST_PCHECK(setresuid(uid, uid, uid) == 0); 353 MaybeSave(); 354 355 // setresuid should have dropped CAP_KILL. 356 TEST_CHECK(!HaveCapability(CAP_KILL).ValueOrDie()); 357 358 // Child 2 and child should now not share a thread group and any UIDs. 359 // Child 2 should have no privileges. That means any signal other than 360 // SIGCONT should fail. 361 TEST_CHECK(kill(stopped_child, SIGKILL) < 0); 362 TEST_PCHECK_MSG(errno == EPERM, "kill failed with wrong errno"); 363 MaybeSave(); 364 365 TEST_PCHECK(kill(stopped_child, SIGCONT) == 0); 366 MaybeSave(); 367 368 _exit(0); 369 } 370 371 ASSERT_THAT(stopped_child, SyscallSucceeds()); 372 373 // Make sure child exited normally. 374 EXPECT_THAT(RetryEINTR(waitpid)(stopped_child, &status, 0), 375 SyscallSucceedsWithValue(stopped_child)); 376 EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0) 377 << "status " << status; 378 379 // Make sure other_child exited normally. 380 EXPECT_THAT(RetryEINTR(waitpid)(other_child, &status, 0), 381 SyscallSucceedsWithValue(other_child)); 382 EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0) 383 << "status " << status; 384 } 385 386 } // namespace 387 388 } // namespace testing 389 } // namespace gvisor