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