Serenity Operating System
at master 153 lines 4.0 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <Kernel/InterruptDisabler.h> 8#include <Kernel/Process.h> 9 10namespace Kernel { 11 12ErrorOr<void> Process::do_kill(Process& process, int signal) 13{ 14 // FIXME: Should setuid processes have some special treatment here? 15 auto credentials = this->credentials(); 16 auto kill_process_credentials = process.credentials(); 17 18 bool can_send_signal = credentials->is_superuser() 19 || credentials->euid() == kill_process_credentials->uid() 20 || credentials->uid() == kill_process_credentials->uid() 21 || (signal == SIGCONT && credentials->pgid() == kill_process_credentials->pgid()); 22 if (!can_send_signal) 23 return EPERM; 24 if (process.is_kernel_process()) { 25 process.name().with([&](auto& process_name) { 26 dbgln("Attempted to send signal {} to kernel process {} ({})", signal, process_name->view(), process.pid()); 27 }); 28 return EPERM; 29 } 30 if (signal != 0) 31 return process.send_signal(signal, this); 32 return {}; 33} 34 35ErrorOr<void> Process::do_killpg(ProcessGroupID pgrp, int signal) 36{ 37 InterruptDisabler disabler; 38 39 VERIFY(pgrp >= 0); 40 41 // Send the signal to all processes in the given group. 42 if (pgrp == 0) { 43 // Send the signal to our own pgrp. 44 pgrp = pgid(); 45 } 46 47 bool group_was_empty = true; 48 bool any_succeeded = false; 49 ErrorOr<void> error; 50 51 TRY(Process::current().for_each_in_pgrp_in_same_jail(pgrp, [&](auto& process) -> ErrorOr<void> { 52 group_was_empty = false; 53 54 ErrorOr<void> res = do_kill(process, signal); 55 if (!res.is_error()) 56 any_succeeded = true; 57 else 58 error = move(res); 59 return {}; 60 })); 61 62 if (group_was_empty) 63 return ESRCH; 64 if (any_succeeded) 65 return {}; 66 return error; 67} 68 69ErrorOr<void> Process::do_killall(int signal) 70{ 71 InterruptDisabler disabler; 72 73 bool any_succeeded = false; 74 ErrorOr<void> error; 75 76 // Send the signal to all processes we have access to for. 77 TRY(Process::for_each_in_same_jail([&](auto& process) -> ErrorOr<void> { 78 ErrorOr<void> res; 79 if (process.pid() == pid()) 80 res = do_killself(signal); 81 else 82 res = do_kill(process, signal); 83 84 if (!res.is_error()) 85 any_succeeded = true; 86 else 87 error = move(res); 88 return {}; 89 })); 90 91 if (any_succeeded) 92 return {}; 93 return error; 94} 95 96ErrorOr<void> Process::do_killself(int signal) 97{ 98 if (signal == 0) 99 return {}; 100 101 auto* current_thread = Thread::current(); 102 if (!current_thread->should_ignore_signal(signal)) 103 current_thread->send_signal(signal, this); 104 105 return {}; 106} 107 108ErrorOr<FlatPtr> Process::sys$kill(pid_t pid_or_pgid, int signal) 109{ 110 VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); 111 if (pid_or_pgid == pid().value()) 112 TRY(require_promise(Pledge::stdio)); 113 else 114 TRY(require_promise(Pledge::proc)); 115 116 if (signal < 0 || signal >= 32) 117 return EINVAL; 118 if (pid_or_pgid < -1) { 119 if (pid_or_pgid == NumericLimits<i32>::min()) 120 return EINVAL; 121 TRY(do_killpg(-pid_or_pgid, signal)); 122 return 0; 123 } 124 if (pid_or_pgid == -1) { 125 TRY(do_killall(signal)); 126 return 0; 127 } 128 if (pid_or_pgid == pid().value()) { 129 TRY(do_killself(signal)); 130 return 0; 131 } 132 VERIFY(pid_or_pgid >= 0); 133 auto peer = Process::from_pid_in_same_jail(pid_or_pgid); 134 if (!peer) 135 return ESRCH; 136 TRY(do_kill(*peer, signal)); 137 return 0; 138} 139 140ErrorOr<FlatPtr> Process::sys$killpg(pid_t pgrp, int signum) 141{ 142 VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); 143 TRY(require_promise(Pledge::proc)); 144 if (signum < 1 || signum >= 32) 145 return EINVAL; 146 if (pgrp < 0) 147 return EINVAL; 148 149 TRY(do_killpg(pgrp, signum)); 150 return 0; 151} 152 153}