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#include <Kernel/TTY/TTY.h>
10
11namespace Kernel {
12
13ErrorOr<FlatPtr> Process::sys$getsid(pid_t pid)
14{
15 VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
16 TRY(require_promise(Pledge::stdio));
17 if (pid == 0)
18 return sid().value();
19 auto process = Process::from_pid_in_same_jail(pid);
20 if (!process)
21 return ESRCH;
22 if (sid() != process->sid())
23 return EPERM;
24 return process->sid().value();
25}
26
27ErrorOr<FlatPtr> Process::sys$setsid()
28{
29 VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
30 TRY(require_promise(Pledge::proc));
31 InterruptDisabler disabler;
32 bool found_process_with_same_pgid_as_my_pid = false;
33 TRY(Process::for_each_in_pgrp_in_same_jail(pid().value(), [&](auto&) -> ErrorOr<void> {
34 found_process_with_same_pgid_as_my_pid = true;
35 return {};
36 }));
37 if (found_process_with_same_pgid_as_my_pid)
38 return EPERM;
39 // Create a new Session and a new ProcessGroup.
40
41 m_pg = TRY(ProcessGroup::try_create(ProcessGroupID(pid().value())));
42 m_tty = nullptr;
43 return with_mutable_protected_data([&](auto& protected_data) -> ErrorOr<FlatPtr> {
44 protected_data.sid = pid().value();
45 return protected_data.sid.value();
46 });
47}
48
49ErrorOr<FlatPtr> Process::sys$getpgid(pid_t pid)
50{
51 VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
52 TRY(require_promise(Pledge::stdio));
53 if (pid == 0)
54 return pgid().value();
55 auto process = Process::from_pid_in_same_jail(pid);
56 if (!process)
57 return ESRCH;
58 return process->pgid().value();
59}
60
61ErrorOr<FlatPtr> Process::sys$getpgrp()
62{
63 VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
64 TRY(require_promise(Pledge::stdio));
65 return pgid().value();
66}
67
68SessionID Process::get_sid_from_pgid(ProcessGroupID pgid)
69{
70 // FIXME: This xor sys$setsid() uses the wrong locking mechanism.
71
72 SessionID sid { -1 };
73 MUST(Process::current().for_each_in_pgrp_in_same_jail(pgid, [&](auto& process) -> ErrorOr<void> {
74 sid = process.sid();
75 return {};
76 }));
77
78 return sid;
79}
80
81ErrorOr<FlatPtr> Process::sys$setpgid(pid_t specified_pid, pid_t specified_pgid)
82{
83 VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
84 TRY(require_promise(Pledge::proc));
85 ProcessID pid = specified_pid ? ProcessID(specified_pid) : this->pid();
86 if (specified_pgid < 0) {
87 // The value of the pgid argument is less than 0, or is not a value supported by the implementation.
88 return EINVAL;
89 }
90 auto process = Process::from_pid_in_same_jail(pid);
91 if (!process)
92 return ESRCH;
93 if (process != this && process->ppid() != this->pid()) {
94 // The value of the pid argument does not match the process ID
95 // of the calling process or of a child process of the calling process.
96 return ESRCH;
97 }
98 if (process->is_session_leader()) {
99 // The process indicated by the pid argument is a session leader.
100 return EPERM;
101 }
102 if (process->ppid() == this->pid() && process->sid() != sid()) {
103 // The value of the pid argument matches the process ID of a child
104 // process of the calling process and the child process is not in
105 // the same session as the calling process.
106 return EPERM;
107 }
108
109 ProcessGroupID new_pgid = specified_pgid ? ProcessGroupID(specified_pgid) : process->pid().value();
110 SessionID current_sid = sid();
111 SessionID new_sid = get_sid_from_pgid(new_pgid);
112 if (new_sid != -1 && current_sid != new_sid) {
113 // Can't move a process between sessions.
114 return EPERM;
115 }
116 if (new_sid == -1 && new_pgid != process->pid().value()) {
117 // The value of the pgid argument is valid, but is not
118 // the calling pid, and is not an existing process group.
119 return EPERM;
120 }
121 // FIXME: There are more EPERM conditions to check for here..
122 process->m_pg = TRY(ProcessGroup::try_find_or_create(new_pgid));
123 return with_mutable_protected_data([&](auto& protected_data) -> ErrorOr<FlatPtr> {
124 auto credentials = this->credentials();
125
126 auto new_credentials = TRY(Credentials::create(
127 credentials->uid(),
128 credentials->gid(),
129 credentials->euid(),
130 credentials->egid(),
131 credentials->suid(),
132 credentials->sgid(),
133 credentials->extra_gids(),
134 new_sid,
135 new_pgid));
136
137 protected_data.credentials = move(new_credentials);
138 return 0;
139 });
140}
141
142ErrorOr<FlatPtr> Process::sys$get_root_session_id(pid_t force_sid)
143{
144 TRY(require_promise(Pledge::stdio));
145 pid_t sid = (force_sid == -1) ? this->sid().value() : force_sid;
146 if (sid == 0)
147 return 0;
148 while (true) {
149 auto sid_process = Process::from_pid_in_same_jail(sid);
150 if (!sid_process)
151 return ESRCH;
152 auto parent_pid = sid_process->ppid().value();
153 auto parent_process = Process::from_pid_in_same_jail(parent_pid);
154 if (!parent_process)
155 return ESRCH;
156 pid_t parent_sid = parent_process->sid().value();
157 if (parent_sid == 0)
158 break;
159 sid = parent_sid;
160 }
161 return sid;
162}
163
164}