Linux 6.14-rc1
[linux-stable.git] / security / landlock / task.c
blobdc7dab78392edca0dcf72cdc53d5fa188a00e9be
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Landlock LSM - Ptrace hooks
5 * Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
6 * Copyright © 2019-2020 ANSSI
7 */
9 #include <asm/current.h>
10 #include <linux/cred.h>
11 #include <linux/errno.h>
12 #include <linux/kernel.h>
13 #include <linux/lsm_hooks.h>
14 #include <linux/rcupdate.h>
15 #include <linux/sched.h>
16 #include <net/af_unix.h>
17 #include <net/sock.h>
19 #include "common.h"
20 #include "cred.h"
21 #include "fs.h"
22 #include "ruleset.h"
23 #include "setup.h"
24 #include "task.h"
26 /**
27 * domain_scope_le - Checks domain ordering for scoped ptrace
29 * @parent: Parent domain.
30 * @child: Potential child of @parent.
32 * Checks if the @parent domain is less or equal to (i.e. an ancestor, which
33 * means a subset of) the @child domain.
35 static bool domain_scope_le(const struct landlock_ruleset *const parent,
36 const struct landlock_ruleset *const child)
38 const struct landlock_hierarchy *walker;
40 if (!parent)
41 return true;
42 if (!child)
43 return false;
44 for (walker = child->hierarchy; walker; walker = walker->parent) {
45 if (walker == parent->hierarchy)
46 /* @parent is in the scoped hierarchy of @child. */
47 return true;
49 /* There is no relationship between @parent and @child. */
50 return false;
53 static bool task_is_scoped(const struct task_struct *const parent,
54 const struct task_struct *const child)
56 bool is_scoped;
57 const struct landlock_ruleset *dom_parent, *dom_child;
59 rcu_read_lock();
60 dom_parent = landlock_get_task_domain(parent);
61 dom_child = landlock_get_task_domain(child);
62 is_scoped = domain_scope_le(dom_parent, dom_child);
63 rcu_read_unlock();
64 return is_scoped;
67 static int task_ptrace(const struct task_struct *const parent,
68 const struct task_struct *const child)
70 /* Quick return for non-landlocked tasks. */
71 if (!landlocked(parent))
72 return 0;
73 if (task_is_scoped(parent, child))
74 return 0;
75 return -EPERM;
78 /**
79 * hook_ptrace_access_check - Determines whether the current process may access
80 * another
82 * @child: Process to be accessed.
83 * @mode: Mode of attachment.
85 * If the current task has Landlock rules, then the child must have at least
86 * the same rules. Else denied.
88 * Determines whether a process may access another, returning 0 if permission
89 * granted, -errno if denied.
91 static int hook_ptrace_access_check(struct task_struct *const child,
92 const unsigned int mode)
94 return task_ptrace(current, child);
97 /**
98 * hook_ptrace_traceme - Determines whether another process may trace the
99 * current one
101 * @parent: Task proposed to be the tracer.
103 * If the parent has Landlock rules, then the current task must have the same
104 * or more rules. Else denied.
106 * Determines whether the nominated task is permitted to trace the current
107 * process, returning 0 if permission is granted, -errno if denied.
109 static int hook_ptrace_traceme(struct task_struct *const parent)
111 return task_ptrace(parent, current);
115 * domain_is_scoped - Checks if the client domain is scoped in the same
116 * domain as the server.
118 * @client: IPC sender domain.
119 * @server: IPC receiver domain.
120 * @scope: The scope restriction criteria.
122 * Returns: True if the @client domain is scoped to access the @server,
123 * unless the @server is also scoped in the same domain as @client.
125 static bool domain_is_scoped(const struct landlock_ruleset *const client,
126 const struct landlock_ruleset *const server,
127 access_mask_t scope)
129 int client_layer, server_layer;
130 struct landlock_hierarchy *client_walker, *server_walker;
132 /* Quick return if client has no domain */
133 if (WARN_ON_ONCE(!client))
134 return false;
136 client_layer = client->num_layers - 1;
137 client_walker = client->hierarchy;
139 * client_layer must be a signed integer with greater capacity
140 * than client->num_layers to ensure the following loop stops.
142 BUILD_BUG_ON(sizeof(client_layer) > sizeof(client->num_layers));
144 server_layer = server ? (server->num_layers - 1) : -1;
145 server_walker = server ? server->hierarchy : NULL;
148 * Walks client's parent domains down to the same hierarchy level
149 * as the server's domain, and checks that none of these client's
150 * parent domains are scoped.
152 for (; client_layer > server_layer; client_layer--) {
153 if (landlock_get_scope_mask(client, client_layer) & scope)
154 return true;
156 client_walker = client_walker->parent;
159 * Walks server's parent domains down to the same hierarchy level as
160 * the client's domain.
162 for (; server_layer > client_layer; server_layer--)
163 server_walker = server_walker->parent;
165 for (; client_layer >= 0; client_layer--) {
166 if (landlock_get_scope_mask(client, client_layer) & scope) {
168 * Client and server are at the same level in the
169 * hierarchy. If the client is scoped, the request is
170 * only allowed if this domain is also a server's
171 * ancestor.
173 return server_walker != client_walker;
175 client_walker = client_walker->parent;
176 server_walker = server_walker->parent;
178 return false;
181 static bool sock_is_scoped(struct sock *const other,
182 const struct landlock_ruleset *const domain)
184 const struct landlock_ruleset *dom_other;
186 /* The credentials will not change. */
187 lockdep_assert_held(&unix_sk(other)->lock);
188 dom_other = landlock_cred(other->sk_socket->file->f_cred)->domain;
189 return domain_is_scoped(domain, dom_other,
190 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
193 static bool is_abstract_socket(struct sock *const sock)
195 struct unix_address *addr = unix_sk(sock)->addr;
197 if (!addr)
198 return false;
200 if (addr->len >= offsetof(struct sockaddr_un, sun_path) + 1 &&
201 addr->name->sun_path[0] == '\0')
202 return true;
204 return false;
207 static const struct access_masks unix_scope = {
208 .scope = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET,
211 static int hook_unix_stream_connect(struct sock *const sock,
212 struct sock *const other,
213 struct sock *const newsk)
215 const struct landlock_ruleset *const dom =
216 landlock_get_applicable_domain(landlock_get_current_domain(),
217 unix_scope);
219 /* Quick return for non-landlocked tasks. */
220 if (!dom)
221 return 0;
223 if (is_abstract_socket(other) && sock_is_scoped(other, dom))
224 return -EPERM;
226 return 0;
229 static int hook_unix_may_send(struct socket *const sock,
230 struct socket *const other)
232 const struct landlock_ruleset *const dom =
233 landlock_get_applicable_domain(landlock_get_current_domain(),
234 unix_scope);
236 if (!dom)
237 return 0;
240 * Checks if this datagram socket was already allowed to be connected
241 * to other.
243 if (unix_peer(sock->sk) == other->sk)
244 return 0;
246 if (is_abstract_socket(other->sk) && sock_is_scoped(other->sk, dom))
247 return -EPERM;
249 return 0;
252 static const struct access_masks signal_scope = {
253 .scope = LANDLOCK_SCOPE_SIGNAL,
256 static int hook_task_kill(struct task_struct *const p,
257 struct kernel_siginfo *const info, const int sig,
258 const struct cred *const cred)
260 bool is_scoped;
261 const struct landlock_ruleset *dom;
263 if (cred) {
264 /* Dealing with USB IO. */
265 dom = landlock_cred(cred)->domain;
266 } else {
267 dom = landlock_get_current_domain();
269 dom = landlock_get_applicable_domain(dom, signal_scope);
271 /* Quick return for non-landlocked tasks. */
272 if (!dom)
273 return 0;
275 rcu_read_lock();
276 is_scoped = domain_is_scoped(dom, landlock_get_task_domain(p),
277 LANDLOCK_SCOPE_SIGNAL);
278 rcu_read_unlock();
279 if (is_scoped)
280 return -EPERM;
282 return 0;
285 static int hook_file_send_sigiotask(struct task_struct *tsk,
286 struct fown_struct *fown, int signum)
288 const struct landlock_ruleset *dom;
289 bool is_scoped = false;
291 /* Lock already held by send_sigio() and send_sigurg(). */
292 lockdep_assert_held(&fown->lock);
293 dom = landlock_get_applicable_domain(
294 landlock_file(fown->file)->fown_domain, signal_scope);
296 /* Quick return for unowned socket. */
297 if (!dom)
298 return 0;
300 rcu_read_lock();
301 is_scoped = domain_is_scoped(dom, landlock_get_task_domain(tsk),
302 LANDLOCK_SCOPE_SIGNAL);
303 rcu_read_unlock();
304 if (is_scoped)
305 return -EPERM;
307 return 0;
310 static struct security_hook_list landlock_hooks[] __ro_after_init = {
311 LSM_HOOK_INIT(ptrace_access_check, hook_ptrace_access_check),
312 LSM_HOOK_INIT(ptrace_traceme, hook_ptrace_traceme),
314 LSM_HOOK_INIT(unix_stream_connect, hook_unix_stream_connect),
315 LSM_HOOK_INIT(unix_may_send, hook_unix_may_send),
317 LSM_HOOK_INIT(task_kill, hook_task_kill),
318 LSM_HOOK_INIT(file_send_sigiotask, hook_file_send_sigiotask),
321 __init void landlock_add_task_hooks(void)
323 security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks),
324 &landlock_lsmid);