xref: /linux/security/landlock/task.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Landlock LSM - Ptrace hooks
4  *
5  * Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
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  */
domain_scope_le(const struct landlock_ruleset * const parent,const struct landlock_ruleset * const child)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 
task_is_scoped(const struct task_struct * const parent,const struct task_struct * const child)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 
task_ptrace(const struct task_struct * const parent,const struct task_struct * const child)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  */
hook_ptrace_access_check(struct task_struct * const child,const unsigned int mode)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  */
hook_ptrace_traceme(struct task_struct * const parent)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  */
domain_is_scoped(const struct landlock_ruleset * const client,const struct landlock_ruleset * const server,access_mask_t scope)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 
sock_is_scoped(struct sock * const other,const struct landlock_ruleset * const domain)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 
is_abstract_socket(struct sock * const sock)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 
hook_unix_stream_connect(struct sock * const sock,struct sock * const other,struct sock * const newsk)207 static int hook_unix_stream_connect(struct sock *const sock,
208 				    struct sock *const other,
209 				    struct sock *const newsk)
210 {
211 	const struct landlock_ruleset *const dom =
212 		landlock_get_current_domain();
213 
214 	/* Quick return for non-landlocked tasks. */
215 	if (!dom)
216 		return 0;
217 
218 	if (is_abstract_socket(other) && sock_is_scoped(other, dom))
219 		return -EPERM;
220 
221 	return 0;
222 }
223 
hook_unix_may_send(struct socket * const sock,struct socket * const other)224 static int hook_unix_may_send(struct socket *const sock,
225 			      struct socket *const other)
226 {
227 	const struct landlock_ruleset *const dom =
228 		landlock_get_current_domain();
229 
230 	if (!dom)
231 		return 0;
232 
233 	/*
234 	 * Checks if this datagram socket was already allowed to be connected
235 	 * to other.
236 	 */
237 	if (unix_peer(sock->sk) == other->sk)
238 		return 0;
239 
240 	if (is_abstract_socket(other->sk) && sock_is_scoped(other->sk, dom))
241 		return -EPERM;
242 
243 	return 0;
244 }
245 
hook_task_kill(struct task_struct * const p,struct kernel_siginfo * const info,const int sig,const struct cred * const cred)246 static int hook_task_kill(struct task_struct *const p,
247 			  struct kernel_siginfo *const info, const int sig,
248 			  const struct cred *const cred)
249 {
250 	bool is_scoped;
251 	const struct landlock_ruleset *dom;
252 
253 	if (cred) {
254 		/* Dealing with USB IO. */
255 		dom = landlock_cred(cred)->domain;
256 	} else {
257 		dom = landlock_get_current_domain();
258 	}
259 
260 	/* Quick return for non-landlocked tasks. */
261 	if (!dom)
262 		return 0;
263 
264 	rcu_read_lock();
265 	is_scoped = domain_is_scoped(dom, landlock_get_task_domain(p),
266 				     LANDLOCK_SCOPE_SIGNAL);
267 	rcu_read_unlock();
268 	if (is_scoped)
269 		return -EPERM;
270 
271 	return 0;
272 }
273 
hook_file_send_sigiotask(struct task_struct * tsk,struct fown_struct * fown,int signum)274 static int hook_file_send_sigiotask(struct task_struct *tsk,
275 				    struct fown_struct *fown, int signum)
276 {
277 	const struct landlock_ruleset *dom;
278 	bool is_scoped = false;
279 
280 	/* Lock already held by send_sigio() and send_sigurg(). */
281 	lockdep_assert_held(&fown->lock);
282 	dom = landlock_file(fown->file)->fown_domain;
283 
284 	/* Quick return for unowned socket. */
285 	if (!dom)
286 		return 0;
287 
288 	rcu_read_lock();
289 	is_scoped = domain_is_scoped(dom, landlock_get_task_domain(tsk),
290 				     LANDLOCK_SCOPE_SIGNAL);
291 	rcu_read_unlock();
292 	if (is_scoped)
293 		return -EPERM;
294 
295 	return 0;
296 }
297 
298 static struct security_hook_list landlock_hooks[] __ro_after_init = {
299 	LSM_HOOK_INIT(ptrace_access_check, hook_ptrace_access_check),
300 	LSM_HOOK_INIT(ptrace_traceme, hook_ptrace_traceme),
301 
302 	LSM_HOOK_INIT(unix_stream_connect, hook_unix_stream_connect),
303 	LSM_HOOK_INIT(unix_may_send, hook_unix_may_send),
304 
305 	LSM_HOOK_INIT(task_kill, hook_task_kill),
306 	LSM_HOOK_INIT(file_send_sigiotask, hook_file_send_sigiotask),
307 };
308 
landlock_add_task_hooks(void)309 __init void landlock_add_task_hooks(void)
310 {
311 	security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks),
312 			   &landlock_lsmid);
313 }
314