xref: /linux/security/landlock/task.c (revision 67f8bc848ee31831336bd478e57d2f993551902e)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Landlock - Ptrace and scope hooks
4  *
5  * Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
6  * Copyright © 2019-2020 ANSSI
7  * Copyright © 2024-2025 Microsoft Corporation
8  */
9 
10 #include <asm/current.h>
11 #include <linux/cleanup.h>
12 #include <linux/cred.h>
13 #include <linux/errno.h>
14 #include <linux/kernel.h>
15 #include <linux/lsm_audit.h>
16 #include <linux/lsm_hooks.h>
17 #include <linux/rcupdate.h>
18 #include <linux/sched.h>
19 #include <linux/sched/signal.h>
20 #include <net/af_unix.h>
21 #include <net/sock.h>
22 
23 #include "common.h"
24 #include "cred.h"
25 #include "domain.h"
26 #include "fs.h"
27 #include "log.h"
28 #include "ruleset.h"
29 #include "setup.h"
30 #include "task.h"
31 
32 /**
33  * domain_scope_le - Checks domain ordering for scoped ptrace
34  *
35  * @parent: Parent domain.
36  * @child: Potential child of @parent.
37  *
38  * Checks if the @parent domain is less or equal to (i.e. an ancestor, which
39  * means a subset of) the @child domain.
40  *
41  * Return: True if @parent is an ancestor of or equal to @child, false
42  * otherwise.
43  */
44 static bool domain_scope_le(const struct landlock_domain *const parent,
45 			    const struct landlock_domain *const child)
46 {
47 	const struct landlock_hierarchy *walker;
48 
49 	/* Quick return for non-landlocked tasks. */
50 	if (!parent)
51 		return true;
52 
53 	if (!child)
54 		return false;
55 
56 	for (walker = child->hierarchy; walker; walker = walker->parent) {
57 		if (walker == parent->hierarchy)
58 			/* @parent is in the scoped hierarchy of @child. */
59 			return true;
60 	}
61 
62 	/* There is no relationship between @parent and @child. */
63 	return false;
64 }
65 
66 static int domain_ptrace(const struct landlock_domain *const parent,
67 			 const struct landlock_domain *const child)
68 {
69 	if (domain_scope_le(parent, child))
70 		return 0;
71 
72 	return -EPERM;
73 }
74 
75 /**
76  * hook_ptrace_access_check - Determines whether the current process may access
77  *			      another
78  *
79  * @child: Process to be accessed.
80  * @mode: Mode of attachment.
81  *
82  * If the current task has Landlock rules, then the child must have at least
83  * the same rules.  Else denied.
84  *
85  * Return: 0 if permission is granted, -errno if denied.
86  */
87 static int hook_ptrace_access_check(struct task_struct *const child,
88 				    const unsigned int mode)
89 {
90 	const struct landlock_cred_security *parent_subject;
91 	u64 tracee_domain_id = 0;
92 	int err;
93 
94 	/* Quick return for non-landlocked tasks. */
95 	parent_subject = landlock_cred(current_cred());
96 	if (!parent_subject)
97 		return 0;
98 
99 	scoped_guard(rcu) {
100 		const struct landlock_domain *const child_dom =
101 			landlock_get_task_domain(child);
102 		err = domain_ptrace(parent_subject->domain, child_dom);
103 #ifdef CONFIG_SECURITY_LANDLOCK_LOG
104 		if (child_dom)
105 			tracee_domain_id = child_dom->hierarchy->id;
106 #endif /* CONFIG_SECURITY_LANDLOCK_LOG */
107 	}
108 
109 	if (!err)
110 		return 0;
111 
112 	/*
113 	 * For the ptrace_access_check case, we log the current/parent domain
114 	 * and the child task.
115 	 */
116 	if (!(mode & PTRACE_MODE_NOAUDIT))
117 		landlock_log_denial(parent_subject, &(struct landlock_request) {
118 			.type = LANDLOCK_REQUEST_PTRACE,
119 			.audit = {
120 				.type = LSM_AUDIT_DATA_TASK,
121 				.u.tsk = child,
122 			},
123 			.layer_plus_one = parent_subject->domain->num_layers,
124 			.other_domain_id = tracee_domain_id,
125 		});
126 
127 	return err;
128 }
129 
130 /**
131  * hook_ptrace_traceme - Determines whether another process may trace the
132  *			 current one
133  *
134  * @parent: Task proposed to be the tracer.
135  *
136  * If the parent has Landlock rules, then the current task must have the same
137  * or more rules.  Else denied.
138  *
139  * Return: 0 if permission is granted, -errno if denied.
140  */
141 static int hook_ptrace_traceme(struct task_struct *const parent)
142 {
143 	const struct landlock_cred_security *parent_subject;
144 	const struct landlock_domain *child_dom;
145 	u64 tracee_domain_id = 0;
146 	int err;
147 
148 	child_dom = landlock_get_current_domain();
149 
150 	guard(rcu)();
151 	parent_subject = landlock_cred(__task_cred(parent));
152 	err = domain_ptrace(parent_subject->domain, child_dom);
153 
154 	if (!err)
155 		return 0;
156 
157 #ifdef CONFIG_SECURITY_LANDLOCK_LOG
158 	/* The tracee is the current task; its domain is stable here. */
159 	if (child_dom)
160 		tracee_domain_id = child_dom->hierarchy->id;
161 #endif /* CONFIG_SECURITY_LANDLOCK_LOG */
162 
163 	/*
164 	 * For the ptrace_traceme case, we log the domain which is the cause of
165 	 * the denial, which means the parent domain instead of the current
166 	 * domain.  This may look unusual because the ptrace_traceme action is a
167 	 * request to be traced, but the semantic is consistent with
168 	 * hook_ptrace_access_check().
169 	 */
170 	landlock_log_denial(parent_subject, &(struct landlock_request) {
171 		.type = LANDLOCK_REQUEST_PTRACE,
172 		.audit = {
173 			.type = LSM_AUDIT_DATA_TASK,
174 			.u.tsk = current,
175 		},
176 		.layer_plus_one = parent_subject->domain->num_layers,
177 		.other_domain_id = tracee_domain_id,
178 	});
179 	return err;
180 }
181 
182 /**
183  * domain_is_scoped - Check if an interaction from a client/sender to a
184  *		      server/receiver should be restricted based on scope controls.
185  *
186  * @client: IPC sender domain.
187  * @server: IPC receiver domain.
188  * @scope: The scope restriction criteria.
189  *
190  * Return: True if @server is in a different domain from @client and @client
191  * is scoped to access @server (i.e. access should be denied), false otherwise.
192  */
193 static bool domain_is_scoped(const struct landlock_domain *const client,
194 			     const struct landlock_domain *const server,
195 			     access_mask_t scope)
196 {
197 	int client_layer, server_layer;
198 	const struct landlock_hierarchy *client_walker, *server_walker;
199 
200 	/* Quick return if client has no domain */
201 	if (WARN_ON_ONCE(!client))
202 		return false;
203 
204 	client_layer = client->num_layers - 1;
205 	client_walker = client->hierarchy;
206 	/*
207 	 * client_layer must be able to represent all numbers from
208 	 * LANDLOCK_MAX_NUM_LAYERS - 1 to -1 for the loop below to terminate.
209 	 * (It must be large enough, and it must be signed.)
210 	 */
211 	BUILD_BUG_ON(!is_signed_type(typeof(client_layer)));
212 	BUILD_BUG_ON(LANDLOCK_MAX_NUM_LAYERS - 1 >
213 		     type_max(typeof(client_layer)));
214 
215 	server_layer = server ? (server->num_layers - 1) : -1;
216 	server_walker = server ? server->hierarchy : NULL;
217 
218 	/*
219 	 * Walks client's parent domains down to the same hierarchy level
220 	 * as the server's domain, and checks that none of these client's
221 	 * parent domains are scoped.
222 	 */
223 	for (; client_layer > server_layer; client_layer--) {
224 		if (landlock_get_scope_mask(client, client_layer) & scope)
225 			return true;
226 
227 		client_walker = client_walker->parent;
228 	}
229 	/*
230 	 * Walks server's parent domains down to the same hierarchy level as
231 	 * the client's domain.
232 	 */
233 	for (; server_layer > client_layer; server_layer--)
234 		server_walker = server_walker->parent;
235 
236 	for (; client_layer >= 0; client_layer--) {
237 		if (landlock_get_scope_mask(client, client_layer) & scope) {
238 			/*
239 			 * Client and server are at the same level in the
240 			 * hierarchy. If the client is scoped, the request is
241 			 * only allowed if this domain is also a server's
242 			 * ancestor.
243 			 */
244 			return server_walker != client_walker;
245 		}
246 		client_walker = client_walker->parent;
247 		server_walker = server_walker->parent;
248 	}
249 	return false;
250 }
251 
252 static bool sock_is_scoped(struct sock *const other,
253 			   const struct landlock_domain *const domain,
254 			   u64 *const peer_domain_id)
255 {
256 	const struct landlock_domain *dom_other;
257 
258 	/* The credentials will not change. */
259 	lockdep_assert_held(&unix_sk(other)->lock);
260 
261 	/*
262 	 * A live kernel socket (e.g. from sock_create_kern()) has no backing
263 	 * file, hence no Landlock domain, so treat it as unscoped.  The
264 	 * sk_socket check only guards that dereference; sk_socket is NULL
265 	 * solely for a dead peer, which the caller already excludes under the
266 	 * held lock, so no separate SOCK_DEAD check is needed.
267 	 */
268 	if (unlikely(!other->sk_socket || !other->sk_socket->file))
269 		return false;
270 
271 	dom_other = landlock_cred(other->sk_socket->file->f_cred)->domain;
272 #ifdef CONFIG_SECURITY_LANDLOCK_LOG
273 	*peer_domain_id = dom_other ? dom_other->hierarchy->id : 0;
274 #endif /* CONFIG_SECURITY_LANDLOCK_LOG */
275 	return domain_is_scoped(domain, dom_other,
276 				LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
277 }
278 
279 static bool is_abstract_socket(struct sock *const sock)
280 {
281 	struct unix_address *addr = unix_sk(sock)->addr;
282 
283 	if (!addr)
284 		return false;
285 
286 	if (addr->len >= offsetof(struct sockaddr_un, sun_path) + 1 &&
287 	    addr->name->sun_path[0] == '\0')
288 		return true;
289 
290 	return false;
291 }
292 
293 static const struct access_masks unix_scope = {
294 	.scope = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET,
295 };
296 
297 static int hook_unix_stream_connect(struct sock *const sock,
298 				    struct sock *const other,
299 				    struct sock *const newsk)
300 {
301 	size_t handle_layer;
302 	u64 peer_domain_id = 0;
303 	const struct landlock_cred_security *const subject =
304 		landlock_get_applicable_subject(current_cred(), unix_scope,
305 						&handle_layer);
306 
307 	/* Quick return for non-landlocked tasks. */
308 	if (!subject)
309 		return 0;
310 
311 	if (!is_abstract_socket(other))
312 		return 0;
313 
314 	if (!sock_is_scoped(other, subject->domain, &peer_domain_id))
315 		return 0;
316 
317 	landlock_log_denial(subject, &(struct landlock_request) {
318 		.type = LANDLOCK_REQUEST_SCOPE_ABSTRACT_UNIX_SOCKET,
319 		.audit = {
320 			.type = LSM_AUDIT_DATA_NET,
321 			.u.net = &(struct lsm_network_audit) {
322 				.sk = other,
323 			},
324 		},
325 		.layer_plus_one = handle_layer + 1,
326 		.other_domain_id = peer_domain_id,
327 	});
328 	return -EPERM;
329 }
330 
331 static int hook_unix_may_send(struct socket *const sock,
332 			      struct socket *const other)
333 {
334 	size_t handle_layer;
335 	u64 peer_domain_id = 0;
336 	const struct landlock_cred_security *const subject =
337 		landlock_get_applicable_subject(current_cred(), unix_scope,
338 						&handle_layer);
339 
340 	if (!subject)
341 		return 0;
342 
343 	/*
344 	 * Checks if this datagram socket was already allowed to be connected
345 	 * to other.
346 	 */
347 	if (unix_peer(sock->sk) == other->sk)
348 		return 0;
349 
350 	if (!is_abstract_socket(other->sk))
351 		return 0;
352 
353 	if (!sock_is_scoped(other->sk, subject->domain, &peer_domain_id))
354 		return 0;
355 
356 	landlock_log_denial(subject, &(struct landlock_request) {
357 		.type = LANDLOCK_REQUEST_SCOPE_ABSTRACT_UNIX_SOCKET,
358 		.audit = {
359 			.type = LSM_AUDIT_DATA_NET,
360 			.u.net = &(struct lsm_network_audit) {
361 				.sk = other->sk,
362 			},
363 		},
364 		.layer_plus_one = handle_layer + 1,
365 		.other_domain_id = peer_domain_id,
366 	});
367 	return -EPERM;
368 }
369 
370 static const struct access_masks signal_scope = {
371 	.scope = LANDLOCK_SCOPE_SIGNAL,
372 };
373 
374 static int hook_task_kill(struct task_struct *const p,
375 			  struct kernel_siginfo *const info, const int sig,
376 			  const struct cred *cred)
377 {
378 	bool is_scoped;
379 	size_t handle_layer;
380 	u64 target_domain_id = 0;
381 	const struct landlock_cred_security *subject;
382 
383 	if (!cred) {
384 		/*
385 		 * Always allow sending signals between threads of the same process.
386 		 * This is required for process credential changes by the Native POSIX
387 		 * Threads Library and implemented by the set*id(2) wrappers and
388 		 * libcap(3) with tgkill(2).  See nptl(7) and libpsx(3).
389 		 *
390 		 * This exception is similar to the __ptrace_may_access() one.
391 		 */
392 		if (same_thread_group(p, current))
393 			return 0;
394 
395 		/* Not dealing with USB IO. */
396 		cred = current_cred();
397 	}
398 
399 	subject = landlock_get_applicable_subject(cred, signal_scope,
400 						  &handle_layer);
401 
402 	/* Quick return for non-landlocked tasks. */
403 	if (!subject)
404 		return 0;
405 
406 	scoped_guard(rcu) {
407 		const struct landlock_domain *const other =
408 			landlock_get_task_domain(p);
409 
410 		is_scoped = domain_is_scoped(subject->domain, other,
411 					     signal_scope.scope);
412 #ifdef CONFIG_SECURITY_LANDLOCK_LOG
413 		if (other)
414 			target_domain_id = other->hierarchy->id;
415 #endif /* CONFIG_SECURITY_LANDLOCK_LOG */
416 	}
417 
418 	if (!is_scoped)
419 		return 0;
420 
421 	landlock_log_denial(subject, &(struct landlock_request) {
422 		.type = LANDLOCK_REQUEST_SCOPE_SIGNAL,
423 		.audit = {
424 			.type = LSM_AUDIT_DATA_TASK,
425 			.u.tsk = p,
426 		},
427 		.layer_plus_one = handle_layer + 1,
428 		.other_domain_id = target_domain_id,
429 	});
430 	return -EPERM;
431 }
432 
433 static int hook_file_send_sigiotask(struct task_struct *tsk,
434 				    struct fown_struct *fown, int signum)
435 {
436 	const struct landlock_cred_security *subject;
437 	bool is_scoped = false;
438 	u64 target_domain_id = 0;
439 
440 	/* Lock already held by send_sigio() and send_sigurg(). */
441 	lockdep_assert_held(&fown->lock);
442 	subject = &landlock_file(fown->file)->fown_subject;
443 
444 	/*
445 	 * Quick return for unowned socket.
446 	 *
447 	 * subject->domain has already been filtered when saved by
448 	 * hook_file_set_fowner(), so there is no need to call
449 	 * landlock_get_applicable_subject() here.
450 	 */
451 	if (!subject->domain)
452 		return 0;
453 
454 	/*
455 	 * Always allow delivery to the file owner's own process, including a
456 	 * thread-group leader reached through a process-group owner.  This
457 	 * mirrors hook_task_kill()'s same-process exemption and preserves the
458 	 * guarantee of commit 18eb75f3af40 ("landlock: Always allow signals
459 	 * between threads of the same process"), which the registration-time
460 	 * check cannot honor for a process-group target.
461 	 */
462 	if (task_tgid(tsk) == landlock_file(fown->file)->fown_tg)
463 		return 0;
464 
465 	scoped_guard(rcu) {
466 		const struct landlock_domain *const other =
467 			landlock_get_task_domain(tsk);
468 
469 		is_scoped = domain_is_scoped(subject->domain, other,
470 					     signal_scope.scope);
471 #ifdef CONFIG_SECURITY_LANDLOCK_LOG
472 		if (other)
473 			target_domain_id = other->hierarchy->id;
474 #endif /* CONFIG_SECURITY_LANDLOCK_LOG */
475 	}
476 
477 	if (!is_scoped)
478 		return 0;
479 
480 	landlock_log_denial(subject, &(struct landlock_request) {
481 		.type = LANDLOCK_REQUEST_SCOPE_SIGNAL,
482 		.audit = {
483 			.type = LSM_AUDIT_DATA_TASK,
484 			.u.tsk = tsk,
485 		},
486 #ifdef CONFIG_SECURITY_LANDLOCK_LOG
487 		.layer_plus_one = landlock_file(fown->file)->fown_layer + 1,
488 #endif /* CONFIG_SECURITY_LANDLOCK_LOG */
489 		.other_domain_id = target_domain_id,
490 	});
491 	return -EPERM;
492 }
493 
494 static struct security_hook_list landlock_hooks[] __ro_after_init = {
495 	LSM_HOOK_INIT(ptrace_access_check, hook_ptrace_access_check),
496 	LSM_HOOK_INIT(ptrace_traceme, hook_ptrace_traceme),
497 
498 	LSM_HOOK_INIT(unix_stream_connect, hook_unix_stream_connect),
499 	LSM_HOOK_INIT(unix_may_send, hook_unix_may_send),
500 
501 	LSM_HOOK_INIT(task_kill, hook_task_kill),
502 	LSM_HOOK_INIT(file_send_sigiotask, hook_file_send_sigiotask),
503 };
504 
505 __init void landlock_add_task_hooks(void)
506 {
507 	security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks),
508 			   &landlock_lsmid);
509 }
510