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 <linux/sched/signal.h>
17 #include <net/af_unix.h>
18 #include <net/sock.h>
19 
20 #include "common.h"
21 #include "cred.h"
22 #include "fs.h"
23 #include "ruleset.h"
24 #include "setup.h"
25 #include "task.h"
26 
27 /**
28  * domain_scope_le - Checks domain ordering for scoped ptrace
29  *
30  * @parent: Parent domain.
31  * @child: Potential child of @parent.
32  *
33  * Checks if the @parent domain is less or equal to (i.e. an ancestor, which
34  * means a subset of) the @child domain.
35  */
domain_scope_le(const struct landlock_ruleset * const parent,const struct landlock_ruleset * const child)36 static bool domain_scope_le(const struct landlock_ruleset *const parent,
37 			    const struct landlock_ruleset *const child)
38 {
39 	const struct landlock_hierarchy *walker;
40 
41 	if (!parent)
42 		return true;
43 	if (!child)
44 		return false;
45 	for (walker = child->hierarchy; walker; walker = walker->parent) {
46 		if (walker == parent->hierarchy)
47 			/* @parent is in the scoped hierarchy of @child. */
48 			return true;
49 	}
50 	/* There is no relationship between @parent and @child. */
51 	return false;
52 }
53 
task_is_scoped(const struct task_struct * const parent,const struct task_struct * const child)54 static bool task_is_scoped(const struct task_struct *const parent,
55 			   const struct task_struct *const child)
56 {
57 	bool is_scoped;
58 	const struct landlock_ruleset *dom_parent, *dom_child;
59 
60 	rcu_read_lock();
61 	dom_parent = landlock_get_task_domain(parent);
62 	dom_child = landlock_get_task_domain(child);
63 	is_scoped = domain_scope_le(dom_parent, dom_child);
64 	rcu_read_unlock();
65 	return is_scoped;
66 }
67 
task_ptrace(const struct task_struct * const parent,const struct task_struct * const child)68 static int task_ptrace(const struct task_struct *const parent,
69 		       const struct task_struct *const child)
70 {
71 	/* Quick return for non-landlocked tasks. */
72 	if (!landlocked(parent))
73 		return 0;
74 	if (task_is_scoped(parent, child))
75 		return 0;
76 	return -EPERM;
77 }
78 
79 /**
80  * hook_ptrace_access_check - Determines whether the current process may access
81  *			      another
82  *
83  * @child: Process to be accessed.
84  * @mode: Mode of attachment.
85  *
86  * If the current task has Landlock rules, then the child must have at least
87  * the same rules.  Else denied.
88  *
89  * Determines whether a process may access another, returning 0 if permission
90  * granted, -errno if denied.
91  */
hook_ptrace_access_check(struct task_struct * const child,const unsigned int mode)92 static int hook_ptrace_access_check(struct task_struct *const child,
93 				    const unsigned int mode)
94 {
95 	return task_ptrace(current, child);
96 }
97 
98 /**
99  * hook_ptrace_traceme - Determines whether another process may trace the
100  *			 current one
101  *
102  * @parent: Task proposed to be the tracer.
103  *
104  * If the parent has Landlock rules, then the current task must have the same
105  * or more rules.  Else denied.
106  *
107  * Determines whether the nominated task is permitted to trace the current
108  * process, returning 0 if permission is granted, -errno if denied.
109  */
hook_ptrace_traceme(struct task_struct * const parent)110 static int hook_ptrace_traceme(struct task_struct *const parent)
111 {
112 	return task_ptrace(parent, current);
113 }
114 
115 /**
116  * domain_is_scoped - Checks if the client domain is scoped in the same
117  *		      domain as the server.
118  *
119  * @client: IPC sender domain.
120  * @server: IPC receiver domain.
121  * @scope: The scope restriction criteria.
122  *
123  * Returns: True if the @client domain is scoped to access the @server,
124  * unless the @server is also scoped in the same domain as @client.
125  */
domain_is_scoped(const struct landlock_ruleset * const client,const struct landlock_ruleset * const server,access_mask_t scope)126 static bool domain_is_scoped(const struct landlock_ruleset *const client,
127 			     const struct landlock_ruleset *const server,
128 			     access_mask_t scope)
129 {
130 	int client_layer, server_layer;
131 	struct landlock_hierarchy *client_walker, *server_walker;
132 
133 	/* Quick return if client has no domain */
134 	if (WARN_ON_ONCE(!client))
135 		return false;
136 
137 	client_layer = client->num_layers - 1;
138 	client_walker = client->hierarchy;
139 	/*
140 	 * client_layer must be a signed integer with greater capacity
141 	 * than client->num_layers to ensure the following loop stops.
142 	 */
143 	BUILD_BUG_ON(sizeof(client_layer) > sizeof(client->num_layers));
144 
145 	server_layer = server ? (server->num_layers - 1) : -1;
146 	server_walker = server ? server->hierarchy : NULL;
147 
148 	/*
149 	 * Walks client's parent domains down to the same hierarchy level
150 	 * as the server's domain, and checks that none of these client's
151 	 * parent domains are scoped.
152 	 */
153 	for (; client_layer > server_layer; client_layer--) {
154 		if (landlock_get_scope_mask(client, client_layer) & scope)
155 			return true;
156 
157 		client_walker = client_walker->parent;
158 	}
159 	/*
160 	 * Walks server's parent domains down to the same hierarchy level as
161 	 * the client's domain.
162 	 */
163 	for (; server_layer > client_layer; server_layer--)
164 		server_walker = server_walker->parent;
165 
166 	for (; client_layer >= 0; client_layer--) {
167 		if (landlock_get_scope_mask(client, client_layer) & scope) {
168 			/*
169 			 * Client and server are at the same level in the
170 			 * hierarchy. If the client is scoped, the request is
171 			 * only allowed if this domain is also a server's
172 			 * ancestor.
173 			 */
174 			return server_walker != client_walker;
175 		}
176 		client_walker = client_walker->parent;
177 		server_walker = server_walker->parent;
178 	}
179 	return false;
180 }
181 
sock_is_scoped(struct sock * const other,const struct landlock_ruleset * const domain)182 static bool sock_is_scoped(struct sock *const other,
183 			   const struct landlock_ruleset *const domain)
184 {
185 	const struct landlock_ruleset *dom_other;
186 
187 	/* The credentials will not change. */
188 	lockdep_assert_held(&unix_sk(other)->lock);
189 	dom_other = landlock_cred(other->sk_socket->file->f_cred)->domain;
190 	return domain_is_scoped(domain, dom_other,
191 				LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
192 }
193 
is_abstract_socket(struct sock * const sock)194 static bool is_abstract_socket(struct sock *const sock)
195 {
196 	struct unix_address *addr = unix_sk(sock)->addr;
197 
198 	if (!addr)
199 		return false;
200 
201 	if (addr->len >= offsetof(struct sockaddr_un, sun_path) + 1 &&
202 	    addr->name->sun_path[0] == '\0')
203 		return true;
204 
205 	return false;
206 }
207 
208 static const struct access_masks unix_scope = {
209 	.scope = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET,
210 };
211 
hook_unix_stream_connect(struct sock * const sock,struct sock * const other,struct sock * const newsk)212 static int hook_unix_stream_connect(struct sock *const sock,
213 				    struct sock *const other,
214 				    struct sock *const newsk)
215 {
216 	const struct landlock_ruleset *const dom =
217 		landlock_get_applicable_domain(landlock_get_current_domain(),
218 					       unix_scope);
219 
220 	/* Quick return for non-landlocked tasks. */
221 	if (!dom)
222 		return 0;
223 
224 	if (is_abstract_socket(other) && sock_is_scoped(other, dom))
225 		return -EPERM;
226 
227 	return 0;
228 }
229 
hook_unix_may_send(struct socket * const sock,struct socket * const other)230 static int hook_unix_may_send(struct socket *const sock,
231 			      struct socket *const other)
232 {
233 	const struct landlock_ruleset *const dom =
234 		landlock_get_applicable_domain(landlock_get_current_domain(),
235 					       unix_scope);
236 
237 	if (!dom)
238 		return 0;
239 
240 	/*
241 	 * Checks if this datagram socket was already allowed to be connected
242 	 * to other.
243 	 */
244 	if (unix_peer(sock->sk) == other->sk)
245 		return 0;
246 
247 	if (is_abstract_socket(other->sk) && sock_is_scoped(other->sk, dom))
248 		return -EPERM;
249 
250 	return 0;
251 }
252 
253 static const struct access_masks signal_scope = {
254 	.scope = LANDLOCK_SCOPE_SIGNAL,
255 };
256 
hook_task_kill(struct task_struct * const p,struct kernel_siginfo * const info,const int sig,const struct cred * const cred)257 static int hook_task_kill(struct task_struct *const p,
258 			  struct kernel_siginfo *const info, const int sig,
259 			  const struct cred *const cred)
260 {
261 	bool is_scoped;
262 	const struct landlock_ruleset *dom;
263 
264 	if (cred) {
265 		/* Dealing with USB IO. */
266 		dom = landlock_cred(cred)->domain;
267 	} else {
268 		/*
269 		 * Always allow sending signals between threads of the same process.
270 		 * This is required for process credential changes by the Native POSIX
271 		 * Threads Library and implemented by the set*id(2) wrappers and
272 		 * libcap(3) with tgkill(2).  See nptl(7) and libpsx(3).
273 		 *
274 		 * This exception is similar to the __ptrace_may_access() one.
275 		 */
276 		if (same_thread_group(p, current))
277 			return 0;
278 
279 		dom = landlock_get_current_domain();
280 	}
281 	dom = landlock_get_applicable_domain(dom, signal_scope);
282 
283 	/* Quick return for non-landlocked tasks. */
284 	if (!dom)
285 		return 0;
286 
287 	rcu_read_lock();
288 	is_scoped = domain_is_scoped(dom, landlock_get_task_domain(p),
289 				     LANDLOCK_SCOPE_SIGNAL);
290 	rcu_read_unlock();
291 	if (is_scoped)
292 		return -EPERM;
293 
294 	return 0;
295 }
296 
hook_file_send_sigiotask(struct task_struct * tsk,struct fown_struct * fown,int signum)297 static int hook_file_send_sigiotask(struct task_struct *tsk,
298 				    struct fown_struct *fown, int signum)
299 {
300 	const struct landlock_ruleset *dom;
301 	bool is_scoped = false;
302 
303 	/* Lock already held by send_sigio() and send_sigurg(). */
304 	lockdep_assert_held(&fown->lock);
305 	dom = landlock_get_applicable_domain(
306 		landlock_file(fown->file)->fown_domain, signal_scope);
307 
308 	/* Quick return for unowned socket. */
309 	if (!dom)
310 		return 0;
311 
312 	rcu_read_lock();
313 	is_scoped = domain_is_scoped(dom, landlock_get_task_domain(tsk),
314 				     LANDLOCK_SCOPE_SIGNAL);
315 	rcu_read_unlock();
316 	if (is_scoped)
317 		return -EPERM;
318 
319 	return 0;
320 }
321 
322 static struct security_hook_list landlock_hooks[] __ro_after_init = {
323 	LSM_HOOK_INIT(ptrace_access_check, hook_ptrace_access_check),
324 	LSM_HOOK_INIT(ptrace_traceme, hook_ptrace_traceme),
325 
326 	LSM_HOOK_INIT(unix_stream_connect, hook_unix_stream_connect),
327 	LSM_HOOK_INIT(unix_may_send, hook_unix_may_send),
328 
329 	LSM_HOOK_INIT(task_kill, hook_task_kill),
330 	LSM_HOOK_INIT(file_send_sigiotask, hook_file_send_sigiotask),
331 };
332 
landlock_add_task_hooks(void)333 __init void landlock_add_task_hooks(void)
334 {
335 	security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks),
336 			   &landlock_lsmid);
337 }
338