]> Git Repo - linux.git/blob - security/landlock/task.c
Linux 6.14-rc3
[linux.git] / security / landlock / task.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Landlock LSM - Ptrace hooks
4  *
5  * Copyright © 2017-2020 Mickaël Salaün <[email protected]>
6  * Copyright © 2019-2020 ANSSI
7  */
8
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>
18
19 #include "common.h"
20 #include "cred.h"
21 #include "fs.h"
22 #include "ruleset.h"
23 #include "setup.h"
24 #include "task.h"
25
26 /**
27  * domain_scope_le - Checks domain ordering for scoped ptrace
28  *
29  * @parent: Parent domain.
30  * @child: Potential child of @parent.
31  *
32  * Checks if the @parent domain is less or equal to (i.e. an ancestor, which
33  * means a subset of) the @child domain.
34  */
35 static bool domain_scope_le(const struct landlock_ruleset *const parent,
36                             const struct landlock_ruleset *const child)
37 {
38         const struct landlock_hierarchy *walker;
39
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;
48         }
49         /* There is no relationship between @parent and @child. */
50         return false;
51 }
52
53 static bool task_is_scoped(const struct task_struct *const parent,
54                            const struct task_struct *const child)
55 {
56         bool is_scoped;
57         const struct landlock_ruleset *dom_parent, *dom_child;
58
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;
65 }
66
67 static int task_ptrace(const struct task_struct *const parent,
68                        const struct task_struct *const child)
69 {
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;
76 }
77
78 /**
79  * hook_ptrace_access_check - Determines whether the current process may access
80  *                            another
81  *
82  * @child: Process to be accessed.
83  * @mode: Mode of attachment.
84  *
85  * If the current task has Landlock rules, then the child must have at least
86  * the same rules.  Else denied.
87  *
88  * Determines whether a process may access another, returning 0 if permission
89  * granted, -errno if denied.
90  */
91 static int hook_ptrace_access_check(struct task_struct *const child,
92                                     const unsigned int mode)
93 {
94         return task_ptrace(current, child);
95 }
96
97 /**
98  * hook_ptrace_traceme - Determines whether another process may trace the
99  *                       current one
100  *
101  * @parent: Task proposed to be the tracer.
102  *
103  * If the parent has Landlock rules, then the current task must have the same
104  * or more rules.  Else denied.
105  *
106  * Determines whether the nominated task is permitted to trace the current
107  * process, returning 0 if permission is granted, -errno if denied.
108  */
109 static int hook_ptrace_traceme(struct task_struct *const parent)
110 {
111         return task_ptrace(parent, current);
112 }
113
114 /**
115  * domain_is_scoped - Checks if the client domain is scoped in the same
116  *                    domain as the server.
117  *
118  * @client: IPC sender domain.
119  * @server: IPC receiver domain.
120  * @scope: The scope restriction criteria.
121  *
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.
124  */
125 static bool domain_is_scoped(const struct landlock_ruleset *const client,
126                              const struct landlock_ruleset *const server,
127                              access_mask_t scope)
128 {
129         int client_layer, server_layer;
130         struct landlock_hierarchy *client_walker, *server_walker;
131
132         /* Quick return if client has no domain */
133         if (WARN_ON_ONCE(!client))
134                 return false;
135
136         client_layer = client->num_layers - 1;
137         client_walker = client->hierarchy;
138         /*
139          * client_layer must be a signed integer with greater capacity
140          * than client->num_layers to ensure the following loop stops.
141          */
142         BUILD_BUG_ON(sizeof(client_layer) > sizeof(client->num_layers));
143
144         server_layer = server ? (server->num_layers - 1) : -1;
145         server_walker = server ? server->hierarchy : NULL;
146
147         /*
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.
151          */
152         for (; client_layer > server_layer; client_layer--) {
153                 if (landlock_get_scope_mask(client, client_layer) & scope)
154                         return true;
155
156                 client_walker = client_walker->parent;
157         }
158         /*
159          * Walks server's parent domains down to the same hierarchy level as
160          * the client's domain.
161          */
162         for (; server_layer > client_layer; server_layer--)
163                 server_walker = server_walker->parent;
164
165         for (; client_layer >= 0; client_layer--) {
166                 if (landlock_get_scope_mask(client, client_layer) & scope) {
167                         /*
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.
172                          */
173                         return server_walker != client_walker;
174                 }
175                 client_walker = client_walker->parent;
176                 server_walker = server_walker->parent;
177         }
178         return false;
179 }
180
181 static bool sock_is_scoped(struct sock *const other,
182                            const struct landlock_ruleset *const domain)
183 {
184         const struct landlock_ruleset *dom_other;
185
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);
191 }
192
193 static bool is_abstract_socket(struct sock *const sock)
194 {
195         struct unix_address *addr = unix_sk(sock)->addr;
196
197         if (!addr)
198                 return false;
199
200         if (addr->len >= offsetof(struct sockaddr_un, sun_path) + 1 &&
201             addr->name->sun_path[0] == '\0')
202                 return true;
203
204         return false;
205 }
206
207 static const struct access_masks unix_scope = {
208         .scope = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET,
209 };
210
211 static int hook_unix_stream_connect(struct sock *const sock,
212                                     struct sock *const other,
213                                     struct sock *const newsk)
214 {
215         const struct landlock_ruleset *const dom =
216                 landlock_get_applicable_domain(landlock_get_current_domain(),
217                                                unix_scope);
218
219         /* Quick return for non-landlocked tasks. */
220         if (!dom)
221                 return 0;
222
223         if (is_abstract_socket(other) && sock_is_scoped(other, dom))
224                 return -EPERM;
225
226         return 0;
227 }
228
229 static int hook_unix_may_send(struct socket *const sock,
230                               struct socket *const other)
231 {
232         const struct landlock_ruleset *const dom =
233                 landlock_get_applicable_domain(landlock_get_current_domain(),
234                                                unix_scope);
235
236         if (!dom)
237                 return 0;
238
239         /*
240          * Checks if this datagram socket was already allowed to be connected
241          * to other.
242          */
243         if (unix_peer(sock->sk) == other->sk)
244                 return 0;
245
246         if (is_abstract_socket(other->sk) && sock_is_scoped(other->sk, dom))
247                 return -EPERM;
248
249         return 0;
250 }
251
252 static const struct access_masks signal_scope = {
253         .scope = LANDLOCK_SCOPE_SIGNAL,
254 };
255
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)
259 {
260         bool is_scoped;
261         const struct landlock_ruleset *dom;
262
263         if (cred) {
264                 /* Dealing with USB IO. */
265                 dom = landlock_cred(cred)->domain;
266         } else {
267                 dom = landlock_get_current_domain();
268         }
269         dom = landlock_get_applicable_domain(dom, signal_scope);
270
271         /* Quick return for non-landlocked tasks. */
272         if (!dom)
273                 return 0;
274
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;
281
282         return 0;
283 }
284
285 static int hook_file_send_sigiotask(struct task_struct *tsk,
286                                     struct fown_struct *fown, int signum)
287 {
288         const struct landlock_ruleset *dom;
289         bool is_scoped = false;
290
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);
295
296         /* Quick return for unowned socket. */
297         if (!dom)
298                 return 0;
299
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;
306
307         return 0;
308 }
309
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),
313
314         LSM_HOOK_INIT(unix_stream_connect, hook_unix_stream_connect),
315         LSM_HOOK_INIT(unix_may_send, hook_unix_may_send),
316
317         LSM_HOOK_INIT(task_kill, hook_task_kill),
318         LSM_HOOK_INIT(file_send_sigiotask, hook_file_send_sigiotask),
319 };
320
321 __init void landlock_add_task_hooks(void)
322 {
323         security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks),
324                            &landlock_lsmid);
325 }
This page took 0.052091 seconds and 4 git commands to generate.