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 static bool domain_scope_le(const struct landlock_ruleset *const parent, 42 const struct landlock_ruleset *const child) 43 { 44 const struct landlock_hierarchy *walker; 45 46 /* Quick return for non-landlocked tasks. */ 47 if (!parent) 48 return true; 49 50 if (!child) 51 return false; 52 53 for (walker = child->hierarchy; walker; walker = walker->parent) { 54 if (walker == parent->hierarchy) 55 /* @parent is in the scoped hierarchy of @child. */ 56 return true; 57 } 58 59 /* There is no relationship between @parent and @child. */ 60 return false; 61 } 62 63 static int domain_ptrace(const struct landlock_ruleset *const parent, 64 const struct landlock_ruleset *const child) 65 { 66 if (domain_scope_le(parent, child)) 67 return 0; 68 69 return -EPERM; 70 } 71 72 /** 73 * hook_ptrace_access_check - Determines whether the current process may access 74 * another 75 * 76 * @child: Process to be accessed. 77 * @mode: Mode of attachment. 78 * 79 * If the current task has Landlock rules, then the child must have at least 80 * the same rules. Else denied. 81 * 82 * Determines whether a process may access another, returning 0 if permission 83 * granted, -errno if denied. 84 */ 85 static int hook_ptrace_access_check(struct task_struct *const child, 86 const unsigned int mode) 87 { 88 const struct landlock_cred_security *parent_subject; 89 const struct landlock_ruleset *child_dom; 90 int err; 91 92 /* Quick return for non-landlocked tasks. */ 93 parent_subject = landlock_cred(current_cred()); 94 if (!parent_subject) 95 return 0; 96 97 scoped_guard(rcu) 98 { 99 child_dom = landlock_get_task_domain(child); 100 err = domain_ptrace(parent_subject->domain, child_dom); 101 } 102 103 if (!err) 104 return 0; 105 106 /* 107 * For the ptrace_access_check case, we log the current/parent domain 108 * and the child task. 109 */ 110 if (!(mode & PTRACE_MODE_NOAUDIT)) 111 landlock_log_denial(parent_subject, &(struct landlock_request) { 112 .type = LANDLOCK_REQUEST_PTRACE, 113 .audit = { 114 .type = LSM_AUDIT_DATA_TASK, 115 .u.tsk = child, 116 }, 117 .layer_plus_one = parent_subject->domain->num_layers, 118 }); 119 120 return err; 121 } 122 123 /** 124 * hook_ptrace_traceme - Determines whether another process may trace the 125 * current one 126 * 127 * @parent: Task proposed to be the tracer. 128 * 129 * If the parent has Landlock rules, then the current task must have the same 130 * or more rules. Else denied. 131 * 132 * Determines whether the nominated task is permitted to trace the current 133 * process, returning 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 - Checks if the client domain is scoped in the same 170 * domain as the server. 171 * 172 * @client: IPC sender domain. 173 * @server: IPC receiver domain. 174 * @scope: The scope restriction criteria. 175 * 176 * Returns: True if the @client domain is scoped to access the @server, 177 * unless the @server is also scoped in the same domain as @client. 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 a signed integer with greater capacity 194 * than client->num_layers to ensure the following loop stops. 195 */ 196 BUILD_BUG_ON(sizeof(client_layer) > sizeof(client->num_layers)); 197 198 server_layer = server ? (server->num_layers - 1) : -1; 199 server_walker = server ? server->hierarchy : NULL; 200 201 /* 202 * Walks client's parent domains down to the same hierarchy level 203 * as the server's domain, and checks that none of these client's 204 * parent domains are scoped. 205 */ 206 for (; client_layer > server_layer; client_layer--) { 207 if (landlock_get_scope_mask(client, client_layer) & scope) 208 return true; 209 210 client_walker = client_walker->parent; 211 } 212 /* 213 * Walks server's parent domains down to the same hierarchy level as 214 * the client's domain. 215 */ 216 for (; server_layer > client_layer; server_layer--) 217 server_walker = server_walker->parent; 218 219 for (; client_layer >= 0; client_layer--) { 220 if (landlock_get_scope_mask(client, client_layer) & scope) { 221 /* 222 * Client and server are at the same level in the 223 * hierarchy. If the client is scoped, the request is 224 * only allowed if this domain is also a server's 225 * ancestor. 226 */ 227 return server_walker != client_walker; 228 } 229 client_walker = client_walker->parent; 230 server_walker = server_walker->parent; 231 } 232 return false; 233 } 234 235 static bool sock_is_scoped(struct sock *const other, 236 const struct landlock_ruleset *const domain) 237 { 238 const struct landlock_ruleset *dom_other; 239 240 /* The credentials will not change. */ 241 lockdep_assert_held(&unix_sk(other)->lock); 242 dom_other = landlock_cred(other->sk_socket->file->f_cred)->domain; 243 return domain_is_scoped(domain, dom_other, 244 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET); 245 } 246 247 static bool is_abstract_socket(struct sock *const sock) 248 { 249 struct unix_address *addr = unix_sk(sock)->addr; 250 251 if (!addr) 252 return false; 253 254 if (addr->len >= offsetof(struct sockaddr_un, sun_path) + 1 && 255 addr->name->sun_path[0] == '\0') 256 return true; 257 258 return false; 259 } 260 261 static const struct access_masks unix_scope = { 262 .scope = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET, 263 }; 264 265 static int hook_unix_stream_connect(struct sock *const sock, 266 struct sock *const other, 267 struct sock *const newsk) 268 { 269 size_t handle_layer; 270 const struct landlock_cred_security *const subject = 271 landlock_get_applicable_subject(current_cred(), unix_scope, 272 &handle_layer); 273 274 /* Quick return for non-landlocked tasks. */ 275 if (!subject) 276 return 0; 277 278 if (!is_abstract_socket(other)) 279 return 0; 280 281 if (!sock_is_scoped(other, subject->domain)) 282 return 0; 283 284 landlock_log_denial(subject, &(struct landlock_request) { 285 .type = LANDLOCK_REQUEST_SCOPE_ABSTRACT_UNIX_SOCKET, 286 .audit = { 287 .type = LSM_AUDIT_DATA_NET, 288 .u.net = &(struct lsm_network_audit) { 289 .sk = other, 290 }, 291 }, 292 .layer_plus_one = handle_layer + 1, 293 }); 294 return -EPERM; 295 } 296 297 static int hook_unix_may_send(struct socket *const sock, 298 struct socket *const other) 299 { 300 size_t handle_layer; 301 const struct landlock_cred_security *const subject = 302 landlock_get_applicable_subject(current_cred(), unix_scope, 303 &handle_layer); 304 305 if (!subject) 306 return 0; 307 308 /* 309 * Checks if this datagram socket was already allowed to be connected 310 * to other. 311 */ 312 if (unix_peer(sock->sk) == other->sk) 313 return 0; 314 315 if (!is_abstract_socket(other->sk)) 316 return 0; 317 318 if (!sock_is_scoped(other->sk, subject->domain)) 319 return 0; 320 321 landlock_log_denial(subject, &(struct landlock_request) { 322 .type = LANDLOCK_REQUEST_SCOPE_ABSTRACT_UNIX_SOCKET, 323 .audit = { 324 .type = LSM_AUDIT_DATA_NET, 325 .u.net = &(struct lsm_network_audit) { 326 .sk = other->sk, 327 }, 328 }, 329 .layer_plus_one = handle_layer + 1, 330 }); 331 return -EPERM; 332 } 333 334 static const struct access_masks signal_scope = { 335 .scope = LANDLOCK_SCOPE_SIGNAL, 336 }; 337 338 static int hook_task_kill(struct task_struct *const p, 339 struct kernel_siginfo *const info, const int sig, 340 const struct cred *cred) 341 { 342 bool is_scoped; 343 size_t handle_layer; 344 const struct landlock_cred_security *subject; 345 346 if (!cred) { 347 /* 348 * Always allow sending signals between threads of the same process. 349 * This is required for process credential changes by the Native POSIX 350 * Threads Library and implemented by the set*id(2) wrappers and 351 * libcap(3) with tgkill(2). See nptl(7) and libpsx(3). 352 * 353 * This exception is similar to the __ptrace_may_access() one. 354 */ 355 if (same_thread_group(p, current)) 356 return 0; 357 358 /* Not dealing with USB IO. */ 359 cred = current_cred(); 360 } 361 362 subject = landlock_get_applicable_subject(cred, signal_scope, 363 &handle_layer); 364 365 /* Quick return for non-landlocked tasks. */ 366 if (!subject) 367 return 0; 368 369 scoped_guard(rcu) 370 { 371 is_scoped = domain_is_scoped(subject->domain, 372 landlock_get_task_domain(p), 373 signal_scope.scope); 374 } 375 376 if (!is_scoped) 377 return 0; 378 379 landlock_log_denial(subject, &(struct landlock_request) { 380 .type = LANDLOCK_REQUEST_SCOPE_SIGNAL, 381 .audit = { 382 .type = LSM_AUDIT_DATA_TASK, 383 .u.tsk = p, 384 }, 385 .layer_plus_one = handle_layer + 1, 386 }); 387 return -EPERM; 388 } 389 390 static int hook_file_send_sigiotask(struct task_struct *tsk, 391 struct fown_struct *fown, int signum) 392 { 393 const struct landlock_cred_security *subject; 394 bool is_scoped = false; 395 396 /* Lock already held by send_sigio() and send_sigurg(). */ 397 lockdep_assert_held(&fown->lock); 398 subject = &landlock_file(fown->file)->fown_subject; 399 400 /* 401 * Quick return for unowned socket. 402 * 403 * subject->domain has already been filtered when saved by 404 * hook_file_set_fowner(), so there is no need to call 405 * landlock_get_applicable_subject() here. 406 */ 407 if (!subject->domain) 408 return 0; 409 410 scoped_guard(rcu) 411 { 412 is_scoped = domain_is_scoped(subject->domain, 413 landlock_get_task_domain(tsk), 414 signal_scope.scope); 415 } 416 417 if (!is_scoped) 418 return 0; 419 420 landlock_log_denial(subject, &(struct landlock_request) { 421 .type = LANDLOCK_REQUEST_SCOPE_SIGNAL, 422 .audit = { 423 .type = LSM_AUDIT_DATA_TASK, 424 .u.tsk = tsk, 425 }, 426 #ifdef CONFIG_AUDIT 427 .layer_plus_one = landlock_file(fown->file)->fown_layer + 1, 428 #endif /* CONFIG_AUDIT */ 429 }); 430 return -EPERM; 431 } 432 433 static struct security_hook_list landlock_hooks[] __ro_after_init = { 434 LSM_HOOK_INIT(ptrace_access_check, hook_ptrace_access_check), 435 LSM_HOOK_INIT(ptrace_traceme, hook_ptrace_traceme), 436 437 LSM_HOOK_INIT(unix_stream_connect, hook_unix_stream_connect), 438 LSM_HOOK_INIT(unix_may_send, hook_unix_may_send), 439 440 LSM_HOOK_INIT(task_kill, hook_task_kill), 441 LSM_HOOK_INIT(file_send_sigiotask, hook_file_send_sigiotask), 442 }; 443 444 __init void landlock_add_task_hooks(void) 445 { 446 security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks), 447 &landlock_lsmid); 448 } 449