Serenity Operating System
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}