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