Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

landlock: Log scoped denials

Add audit support for unix_stream_connect, unix_may_send, task_kill, and
file_send_sigiotask hooks.

The related blockers are:
- scope.abstract_unix_socket
- scope.signal

Audit event sample for abstract unix socket:

type=LANDLOCK_DENY msg=audit(1729738800.268:30): domain=195ba459b blockers=scope.abstract_unix_socket path=00666F6F

Audit event sample for signal:

type=LANDLOCK_DENY msg=audit(1729738800.291:31): domain=195ba459b blockers=scope.signal opid=1 ocomm="systemd"

Refactor and simplify error handling in LSM hooks.

Extend struct landlock_file_security with fown_layer and use it to log
the blocking domain. The struct aligned size is still 16 bytes.

Cc: Günther Noack <gnoack@google.com>
Cc: Tahera Fahimi <fahimitahera@gmail.com>
Link: https://lore.kernel.org/r/20250320190717.2287696-17-mic@digikod.net
Signed-off-by: Mickaël Salaün <mic@digikod.net>

+97 -18
+8
security/landlock/audit.c
··· 70 70 if (WARN_ON_ONCE(access_bit >= ARRAY_SIZE(net_access_strings))) 71 71 return "unknown"; 72 72 return net_access_strings[access_bit]; 73 + 74 + case LANDLOCK_REQUEST_SCOPE_ABSTRACT_UNIX_SOCKET: 75 + WARN_ON_ONCE(access_bit != -1); 76 + return "scope.abstract_unix_socket"; 77 + 78 + case LANDLOCK_REQUEST_SCOPE_SIGNAL: 79 + WARN_ON_ONCE(access_bit != -1); 80 + return "scope.signal"; 73 81 } 74 82 75 83 WARN_ON_ONCE(1);
+2
security/landlock/audit.h
··· 19 19 LANDLOCK_REQUEST_FS_CHANGE_TOPOLOGY, 20 20 LANDLOCK_REQUEST_FS_ACCESS, 21 21 LANDLOCK_REQUEST_NET_ACCESS, 22 + LANDLOCK_REQUEST_SCOPE_ABSTRACT_UNIX_SOCKET, 23 + LANDLOCK_REQUEST_SCOPE_SIGNAL, 22 24 }; 23 25 24 26 /*
+6 -2
security/landlock/fs.c
··· 1798 1798 { 1799 1799 struct landlock_ruleset *prev_dom; 1800 1800 struct landlock_cred_security fown_subject = {}; 1801 + size_t fown_layer = 0; 1801 1802 1802 1803 if (control_current_fowner(file_f_owner(file))) { 1803 1804 static const struct access_masks signal_scope = { 1804 1805 .scope = LANDLOCK_SCOPE_SIGNAL, 1805 1806 }; 1806 1807 const struct landlock_cred_security *new_subject = 1807 - landlock_get_applicable_subject(current_cred(), 1808 - signal_scope, NULL); 1808 + landlock_get_applicable_subject( 1809 + current_cred(), signal_scope, &fown_layer); 1809 1810 if (new_subject) { 1810 1811 landlock_get_ruleset(new_subject->domain); 1811 1812 fown_subject = *new_subject; ··· 1815 1814 1816 1815 prev_dom = landlock_file(file)->fown_subject.domain; 1817 1816 landlock_file(file)->fown_subject = fown_subject; 1817 + #ifdef CONFIG_AUDIT 1818 + landlock_file(file)->fown_layer = fown_layer; 1819 + #endif /* CONFIG_AUDIT*/ 1818 1820 1819 1821 /* May be called in an RCU read-side critical section. */ 1820 1822 landlock_put_ruleset_deferred(prev_dom);
+16
security/landlock/fs.h
··· 10 10 #ifndef _SECURITY_LANDLOCK_FS_H 11 11 #define _SECURITY_LANDLOCK_FS_H 12 12 13 + #include <linux/build_bug.h> 13 14 #include <linux/fs.h> 14 15 #include <linux/init.h> 15 16 #include <linux/rcupdate.h> ··· 63 62 * _LANDLOCK_ACCESS_FS_OPTIONAL). 64 63 */ 65 64 deny_masks_t deny_masks; 65 + /** 66 + * @fown_layer: Layer level of @fown_subject->domain with 67 + * LANDLOCK_SCOPE_SIGNAL. 68 + */ 69 + u8 fown_layer; 66 70 #endif /* CONFIG_AUDIT */ 67 71 68 72 /** ··· 79 73 */ 80 74 struct landlock_cred_security fown_subject; 81 75 }; 76 + 77 + #ifdef CONFIG_AUDIT 78 + 79 + /* Makes sure all layers can be identified. */ 80 + /* clang-format off */ 81 + static_assert((typeof_member(struct landlock_file_security, fown_layer))~0 >= 82 + LANDLOCK_MAX_NUM_LAYERS); 83 + /* clang-format off */ 84 + 85 + #endif /* CONFIG_AUDIT */ 82 86 83 87 /** 84 88 * struct landlock_superblock_security - Superblock security blob
+65 -16
security/landlock/task.c
··· 266 266 struct sock *const other, 267 267 struct sock *const newsk) 268 268 { 269 + size_t handle_layer; 269 270 const struct landlock_cred_security *const subject = 270 271 landlock_get_applicable_subject(current_cred(), unix_scope, 271 - NULL); 272 + &handle_layer); 272 273 273 274 /* Quick return for non-landlocked tasks. */ 274 275 if (!subject) 275 276 return 0; 276 277 277 - if (is_abstract_socket(other) && sock_is_scoped(other, subject->domain)) 278 - return -EPERM; 278 + if (!is_abstract_socket(other)) 279 + return 0; 279 280 280 - return 0; 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; 281 295 } 282 296 283 297 static int hook_unix_may_send(struct socket *const sock, 284 298 struct socket *const other) 285 299 { 300 + size_t handle_layer; 286 301 const struct landlock_cred_security *const subject = 287 302 landlock_get_applicable_subject(current_cred(), unix_scope, 288 - NULL); 303 + &handle_layer); 289 304 290 305 if (!subject) 291 306 return 0; ··· 312 297 if (unix_peer(sock->sk) == other->sk) 313 298 return 0; 314 299 315 - if (is_abstract_socket(other->sk) && 316 - sock_is_scoped(other->sk, subject->domain)) 317 - return -EPERM; 300 + if (!is_abstract_socket(other->sk)) 301 + return 0; 318 302 319 - return 0; 303 + if (!sock_is_scoped(other->sk, subject->domain)) 304 + return 0; 305 + 306 + landlock_log_denial(subject, &(struct landlock_request) { 307 + .type = LANDLOCK_REQUEST_SCOPE_ABSTRACT_UNIX_SOCKET, 308 + .audit = { 309 + .type = LSM_AUDIT_DATA_NET, 310 + .u.net = &(struct lsm_network_audit) { 311 + .sk = other->sk, 312 + }, 313 + }, 314 + .layer_plus_one = handle_layer + 1, 315 + }); 316 + return -EPERM; 320 317 } 321 318 322 319 static const struct access_masks signal_scope = { ··· 340 313 const struct cred *cred) 341 314 { 342 315 bool is_scoped; 316 + size_t handle_layer; 343 317 const struct landlock_cred_security *subject; 344 318 345 319 if (!cred) { ··· 359 331 cred = current_cred(); 360 332 } 361 333 362 - subject = landlock_get_applicable_subject(cred, signal_scope, NULL); 334 + subject = landlock_get_applicable_subject(cred, signal_scope, 335 + &handle_layer); 363 336 364 337 /* Quick return for non-landlocked tasks. */ 365 338 if (!subject) ··· 372 343 landlock_get_task_domain(p), 373 344 signal_scope.scope); 374 345 } 375 - if (is_scoped) 376 - return -EPERM; 377 346 378 - return 0; 347 + if (!is_scoped) 348 + return 0; 349 + 350 + landlock_log_denial(subject, &(struct landlock_request) { 351 + .type = LANDLOCK_REQUEST_SCOPE_SIGNAL, 352 + .audit = { 353 + .type = LSM_AUDIT_DATA_TASK, 354 + .u.tsk = p, 355 + }, 356 + .layer_plus_one = handle_layer + 1, 357 + }); 358 + return -EPERM; 379 359 } 380 360 381 361 static int hook_file_send_sigiotask(struct task_struct *tsk, ··· 413 375 landlock_get_task_domain(tsk), 414 376 signal_scope.scope); 415 377 } 416 - if (is_scoped) 417 - return -EPERM; 418 378 419 - return 0; 379 + if (!is_scoped) 380 + return 0; 381 + 382 + landlock_log_denial(subject, &(struct landlock_request) { 383 + .type = LANDLOCK_REQUEST_SCOPE_SIGNAL, 384 + .audit = { 385 + .type = LSM_AUDIT_DATA_TASK, 386 + .u.tsk = tsk, 387 + }, 388 + #ifdef CONFIG_AUDIT 389 + .layer_plus_one = landlock_file(fown->file)->fown_layer + 1, 390 + #endif /* CONFIG_AUDIT */ 391 + }); 392 + return -EPERM; 420 393 } 421 394 422 395 static struct security_hook_list landlock_hooks[] __ro_after_init = {