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 "audit.h"
24 #include "common.h"
25 #include "cred.h"
26 #include "domain.h"
27 #include "fs.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 */
domain_scope_le(const struct landlock_ruleset * const parent,const struct landlock_ruleset * const child)44 static bool domain_scope_le(const struct landlock_ruleset *const parent,
45 const struct landlock_ruleset *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
domain_ptrace(const struct landlock_ruleset * const parent,const struct landlock_ruleset * const child)66 static int domain_ptrace(const struct landlock_ruleset *const parent,
67 const struct landlock_ruleset *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 */
hook_ptrace_access_check(struct task_struct * const child,const unsigned int mode)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 int err;
92
93 /* Quick return for non-landlocked tasks. */
94 parent_subject = landlock_cred(current_cred());
95 if (!parent_subject)
96 return 0;
97
98 scoped_guard(rcu)
99 {
100 const struct landlock_ruleset *const child_dom =
101 landlock_get_task_domain(child);
102 err = domain_ptrace(parent_subject->domain, child_dom);
103 }
104
105 if (!err)
106 return 0;
107
108 /*
109 * For the ptrace_access_check case, we log the current/parent domain
110 * and the child task.
111 */
112 if (!(mode & PTRACE_MODE_NOAUDIT))
113 landlock_log_denial(parent_subject, &(struct landlock_request) {
114 .type = LANDLOCK_REQUEST_PTRACE,
115 .audit = {
116 .type = LSM_AUDIT_DATA_TASK,
117 .u.tsk = child,
118 },
119 .layer_plus_one = parent_subject->domain->num_layers,
120 });
121
122 return err;
123 }
124
125 /**
126 * hook_ptrace_traceme - Determines whether another process may trace the
127 * current one
128 *
129 * @parent: Task proposed to be the tracer.
130 *
131 * If the parent has Landlock rules, then the current task must have the same
132 * or more rules. Else denied.
133 *
134 * Return: 0 if permission is granted, -errno if denied.
135 */
hook_ptrace_traceme(struct task_struct * const parent)136 static int hook_ptrace_traceme(struct task_struct *const parent)
137 {
138 const struct landlock_cred_security *parent_subject;
139 const struct landlock_ruleset *child_dom;
140 int err;
141
142 child_dom = landlock_get_current_domain();
143
144 guard(rcu)();
145 parent_subject = landlock_cred(__task_cred(parent));
146 err = domain_ptrace(parent_subject->domain, child_dom);
147
148 if (!err)
149 return 0;
150
151 /*
152 * For the ptrace_traceme case, we log the domain which is the cause of
153 * the denial, which means the parent domain instead of the current
154 * domain. This may look unusual because the ptrace_traceme action is a
155 * request to be traced, but the semantic is consistent with
156 * hook_ptrace_access_check().
157 */
158 landlock_log_denial(parent_subject, &(struct landlock_request) {
159 .type = LANDLOCK_REQUEST_PTRACE,
160 .audit = {
161 .type = LSM_AUDIT_DATA_TASK,
162 .u.tsk = current,
163 },
164 .layer_plus_one = parent_subject->domain->num_layers,
165 });
166 return err;
167 }
168
169 /**
170 * domain_is_scoped - Check if an interaction from a client/sender to a
171 * server/receiver should be restricted based on scope controls.
172 *
173 * @client: IPC sender domain.
174 * @server: IPC receiver domain.
175 * @scope: The scope restriction criteria.
176 *
177 * Return: True if @server is in a different domain from @client and @client
178 * is scoped to access @server (i.e. access should be denied), false otherwise.
179 */
domain_is_scoped(const struct landlock_ruleset * const client,const struct landlock_ruleset * const server,access_mask_t scope)180 static bool domain_is_scoped(const struct landlock_ruleset *const client,
181 const struct landlock_ruleset *const server,
182 access_mask_t scope)
183 {
184 int client_layer, server_layer;
185 const struct landlock_hierarchy *client_walker, *server_walker;
186
187 /* Quick return if client has no domain */
188 if (WARN_ON_ONCE(!client))
189 return false;
190
191 client_layer = client->num_layers - 1;
192 client_walker = client->hierarchy;
193 /*
194 * client_layer must be able to represent all numbers from
195 * LANDLOCK_MAX_NUM_LAYERS - 1 to -1 for the loop below to terminate.
196 * (It must be large enough, and it must be signed.)
197 */
198 BUILD_BUG_ON(!is_signed_type(typeof(client_layer)));
199 BUILD_BUG_ON(LANDLOCK_MAX_NUM_LAYERS - 1 >
200 type_max(typeof(client_layer)));
201
202 server_layer = server ? (server->num_layers - 1) : -1;
203 server_walker = server ? server->hierarchy : NULL;
204
205 /*
206 * Walks client's parent domains down to the same hierarchy level
207 * as the server's domain, and checks that none of these client's
208 * parent domains are scoped.
209 */
210 for (; client_layer > server_layer; client_layer--) {
211 if (landlock_get_scope_mask(client, client_layer) & scope)
212 return true;
213
214 client_walker = client_walker->parent;
215 }
216 /*
217 * Walks server's parent domains down to the same hierarchy level as
218 * the client's domain.
219 */
220 for (; server_layer > client_layer; server_layer--)
221 server_walker = server_walker->parent;
222
223 for (; client_layer >= 0; client_layer--) {
224 if (landlock_get_scope_mask(client, client_layer) & scope) {
225 /*
226 * Client and server are at the same level in the
227 * hierarchy. If the client is scoped, the request is
228 * only allowed if this domain is also a server's
229 * ancestor.
230 */
231 return server_walker != client_walker;
232 }
233 client_walker = client_walker->parent;
234 server_walker = server_walker->parent;
235 }
236 return false;
237 }
238
sock_is_scoped(struct sock * const other,const struct landlock_ruleset * const domain)239 static bool sock_is_scoped(struct sock *const other,
240 const struct landlock_ruleset *const domain)
241 {
242 const struct landlock_ruleset *dom_other;
243
244 /* The credentials will not change. */
245 lockdep_assert_held(&unix_sk(other)->lock);
246 dom_other = landlock_cred(other->sk_socket->file->f_cred)->domain;
247 return domain_is_scoped(domain, dom_other,
248 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
249 }
250
is_abstract_socket(struct sock * const sock)251 static bool is_abstract_socket(struct sock *const sock)
252 {
253 struct unix_address *addr = unix_sk(sock)->addr;
254
255 if (!addr)
256 return false;
257
258 if (addr->len >= offsetof(struct sockaddr_un, sun_path) + 1 &&
259 addr->name->sun_path[0] == '\0')
260 return true;
261
262 return false;
263 }
264
265 static const struct access_masks unix_scope = {
266 .scope = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET,
267 };
268
hook_unix_stream_connect(struct sock * const sock,struct sock * const other,struct sock * const newsk)269 static int hook_unix_stream_connect(struct sock *const sock,
270 struct sock *const other,
271 struct sock *const newsk)
272 {
273 size_t handle_layer;
274 const struct landlock_cred_security *const subject =
275 landlock_get_applicable_subject(current_cred(), unix_scope,
276 &handle_layer);
277
278 /* Quick return for non-landlocked tasks. */
279 if (!subject)
280 return 0;
281
282 if (!is_abstract_socket(other))
283 return 0;
284
285 if (!sock_is_scoped(other, subject->domain))
286 return 0;
287
288 landlock_log_denial(subject, &(struct landlock_request) {
289 .type = LANDLOCK_REQUEST_SCOPE_ABSTRACT_UNIX_SOCKET,
290 .audit = {
291 .type = LSM_AUDIT_DATA_NET,
292 .u.net = &(struct lsm_network_audit) {
293 .sk = other,
294 },
295 },
296 .layer_plus_one = handle_layer + 1,
297 });
298 return -EPERM;
299 }
300
hook_unix_may_send(struct socket * const sock,struct socket * const other)301 static int hook_unix_may_send(struct socket *const sock,
302 struct socket *const other)
303 {
304 size_t handle_layer;
305 const struct landlock_cred_security *const subject =
306 landlock_get_applicable_subject(current_cred(), unix_scope,
307 &handle_layer);
308
309 if (!subject)
310 return 0;
311
312 /*
313 * Checks if this datagram socket was already allowed to be connected
314 * to other.
315 */
316 if (unix_peer(sock->sk) == other->sk)
317 return 0;
318
319 if (!is_abstract_socket(other->sk))
320 return 0;
321
322 if (!sock_is_scoped(other->sk, subject->domain))
323 return 0;
324
325 landlock_log_denial(subject, &(struct landlock_request) {
326 .type = LANDLOCK_REQUEST_SCOPE_ABSTRACT_UNIX_SOCKET,
327 .audit = {
328 .type = LSM_AUDIT_DATA_NET,
329 .u.net = &(struct lsm_network_audit) {
330 .sk = other->sk,
331 },
332 },
333 .layer_plus_one = handle_layer + 1,
334 });
335 return -EPERM;
336 }
337
338 static const struct access_masks signal_scope = {
339 .scope = LANDLOCK_SCOPE_SIGNAL,
340 };
341
hook_task_kill(struct task_struct * const p,struct kernel_siginfo * const info,const int sig,const struct cred * cred)342 static int hook_task_kill(struct task_struct *const p,
343 struct kernel_siginfo *const info, const int sig,
344 const struct cred *cred)
345 {
346 bool is_scoped;
347 size_t handle_layer;
348 const struct landlock_cred_security *subject;
349
350 if (!cred) {
351 /*
352 * Always allow sending signals between threads of the same process.
353 * This is required for process credential changes by the Native POSIX
354 * Threads Library and implemented by the set*id(2) wrappers and
355 * libcap(3) with tgkill(2). See nptl(7) and libpsx(3).
356 *
357 * This exception is similar to the __ptrace_may_access() one.
358 */
359 if (same_thread_group(p, current))
360 return 0;
361
362 /* Not dealing with USB IO. */
363 cred = current_cred();
364 }
365
366 subject = landlock_get_applicable_subject(cred, signal_scope,
367 &handle_layer);
368
369 /* Quick return for non-landlocked tasks. */
370 if (!subject)
371 return 0;
372
373 scoped_guard(rcu)
374 {
375 is_scoped = domain_is_scoped(subject->domain,
376 landlock_get_task_domain(p),
377 signal_scope.scope);
378 }
379
380 if (!is_scoped)
381 return 0;
382
383 landlock_log_denial(subject, &(struct landlock_request) {
384 .type = LANDLOCK_REQUEST_SCOPE_SIGNAL,
385 .audit = {
386 .type = LSM_AUDIT_DATA_TASK,
387 .u.tsk = p,
388 },
389 .layer_plus_one = handle_layer + 1,
390 });
391 return -EPERM;
392 }
393
hook_file_send_sigiotask(struct task_struct * tsk,struct fown_struct * fown,int signum)394 static int hook_file_send_sigiotask(struct task_struct *tsk,
395 struct fown_struct *fown, int signum)
396 {
397 const struct landlock_cred_security *subject;
398 bool is_scoped = false;
399
400 /* Lock already held by send_sigio() and send_sigurg(). */
401 lockdep_assert_held(&fown->lock);
402 subject = &landlock_file(fown->file)->fown_subject;
403
404 /*
405 * Quick return for unowned socket.
406 *
407 * subject->domain has already been filtered when saved by
408 * hook_file_set_fowner(), so there is no need to call
409 * landlock_get_applicable_subject() here.
410 */
411 if (!subject->domain)
412 return 0;
413
414 scoped_guard(rcu)
415 {
416 is_scoped = domain_is_scoped(subject->domain,
417 landlock_get_task_domain(tsk),
418 signal_scope.scope);
419 }
420
421 if (!is_scoped)
422 return 0;
423
424 landlock_log_denial(subject, &(struct landlock_request) {
425 .type = LANDLOCK_REQUEST_SCOPE_SIGNAL,
426 .audit = {
427 .type = LSM_AUDIT_DATA_TASK,
428 .u.tsk = tsk,
429 },
430 #ifdef CONFIG_AUDIT
431 .layer_plus_one = landlock_file(fown->file)->fown_layer + 1,
432 #endif /* CONFIG_AUDIT */
433 });
434 return -EPERM;
435 }
436
437 static struct security_hook_list landlock_hooks[] __ro_after_init = {
438 LSM_HOOK_INIT(ptrace_access_check, hook_ptrace_access_check),
439 LSM_HOOK_INIT(ptrace_traceme, hook_ptrace_traceme),
440
441 LSM_HOOK_INIT(unix_stream_connect, hook_unix_stream_connect),
442 LSM_HOOK_INIT(unix_may_send, hook_unix_may_send),
443
444 LSM_HOOK_INIT(task_kill, hook_task_kill),
445 LSM_HOOK_INIT(file_send_sigiotask, hook_file_send_sigiotask),
446 };
447
landlock_add_task_hooks(void)448 __init void landlock_add_task_hooks(void)
449 {
450 security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks),
451 &landlock_lsmid);
452 }
453