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.

Merge tag 'landlock-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mic/linux

Pull Landlock update from Mickaël Salaün:
"This adds a new Landlock access right for pathname UNIX domain sockets
thanks to a new LSM hook, and a few fixes"

* tag 'landlock-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mic/linux: (23 commits)
landlock: Document fallocate(2) as another truncation corner case
landlock: Document FS access right for pathname UNIX sockets
selftests/landlock: Simplify ruleset creation and enforcement in fs_test
selftests/landlock: Check that coredump sockets stay unrestricted
selftests/landlock: Audit test for LANDLOCK_ACCESS_FS_RESOLVE_UNIX
selftests/landlock: Test LANDLOCK_ACCESS_FS_RESOLVE_UNIX
selftests/landlock: Replace access_fs_16 with ACCESS_ALL in fs_test
samples/landlock: Add support for named UNIX domain socket restrictions
landlock: Clarify BUILD_BUG_ON check in scoping logic
landlock: Control pathname UNIX domain socket resolution by path
landlock: Use mem_is_zero() in is_layer_masks_allowed()
lsm: Add LSM hook security_unix_find
landlock: Fix kernel-doc warning for pointer-to-array parameters
landlock: Fix formatting in tsync.c
landlock: Improve kernel-doc "Return:" section consistency
landlock: Add missing kernel-doc "Return:" sections
selftests/landlock: Fix format warning for __u64 in net_test
selftests/landlock: Skip stale records in audit_match_record()
selftests/landlock: Drain stale audit records on init
selftests/landlock: Fix socket file descriptor leaks in audit helpers
...

+1650 -794
+41 -1
Documentation/security/landlock.rst
··· 7 7 ================================== 8 8 9 9 :Author: Mickaël Salaün 10 - :Date: September 2025 10 + :Date: March 2026 11 11 12 12 Landlock's goal is to create scoped access-control (i.e. sandboxing). To 13 13 harden a whole system, this feature should be available to any process, ··· 88 88 this is required to keep access controls consistent over the whole system, and 89 89 this avoids unattended bypasses through file descriptor passing (i.e. confused 90 90 deputy attack). 91 + 92 + .. _scoped-flags-interaction: 93 + 94 + Interaction between scoped flags and other access rights 95 + -------------------------------------------------------- 96 + 97 + The ``scoped`` flags in &struct landlock_ruleset_attr restrict the 98 + use of *outgoing* IPC from the created Landlock domain, while they 99 + permit reaching out to IPC endpoints *within* the created Landlock 100 + domain. 101 + 102 + In the future, scoped flags *may* interact with other access rights, 103 + e.g. so that abstract UNIX sockets can be allow-listed by name, or so 104 + that signals can be allow-listed by signal number or target process. 105 + 106 + When introducing ``LANDLOCK_ACCESS_FS_RESOLVE_UNIX``, we defined it to 107 + implicitly have the same scoping semantics as a 108 + ``LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET`` flag would have: connecting to 109 + UNIX sockets within the same domain (where 110 + ``LANDLOCK_ACCESS_FS_RESOLVE_UNIX`` is used) is unconditionally 111 + allowed. 112 + 113 + The reasoning is: 114 + 115 + * Like other IPC mechanisms, connecting to named UNIX sockets in the 116 + same domain should be expected and harmless. (If needed, users can 117 + further refine their Landlock policies with nested domains or by 118 + restricting ``LANDLOCK_ACCESS_FS_MAKE_SOCK``.) 119 + * We reserve the option to still introduce 120 + ``LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET`` in the future. (This would 121 + be useful if we wanted to have a Landlock rule to permit IPC access 122 + to other Landlock domains.) 123 + * But we can postpone the point in time when users have to deal with 124 + two interacting flags visible in the userspace API. (In particular, 125 + it is possible that it won't be needed in practice, in which case we 126 + can avoid the second flag altogether.) 127 + * If we *do* introduce ``LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET`` in the 128 + future, setting this scoped flag in a ruleset does *not reduce* the 129 + restrictions, because access within the same scope is already 130 + allowed based on ``LANDLOCK_ACCESS_FS_RESOLVE_UNIX``. 91 131 92 132 Tests 93 133 =====
+19 -3
Documentation/userspace-api/landlock.rst
··· 77 77 LANDLOCK_ACCESS_FS_MAKE_SYM | 78 78 LANDLOCK_ACCESS_FS_REFER | 79 79 LANDLOCK_ACCESS_FS_TRUNCATE | 80 - LANDLOCK_ACCESS_FS_IOCTL_DEV, 80 + LANDLOCK_ACCESS_FS_IOCTL_DEV | 81 + LANDLOCK_ACCESS_FS_RESOLVE_UNIX, 81 82 .handled_access_net = 82 83 LANDLOCK_ACCESS_NET_BIND_TCP | 83 84 LANDLOCK_ACCESS_NET_CONNECT_TCP, ··· 128 127 /* Removes LANDLOCK_SCOPE_* for ABI < 6 */ 129 128 ruleset_attr.scoped &= ~(LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET | 130 129 LANDLOCK_SCOPE_SIGNAL); 130 + __attribute__((fallthrough)); 131 + case 6 ... 8: 132 + /* Removes LANDLOCK_ACCESS_FS_RESOLVE_UNIX for ABI < 9 */ 133 + ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_RESOLVE_UNIX; 131 134 } 132 135 133 136 This enables the creation of an inclusive ruleset that will contain our rules. ··· 383 378 384 379 The operations covered by ``LANDLOCK_ACCESS_FS_WRITE_FILE`` and 385 380 ``LANDLOCK_ACCESS_FS_TRUNCATE`` both change the contents of a file and sometimes 386 - overlap in non-intuitive ways. It is recommended to always specify both of 387 - these together. 381 + overlap in non-intuitive ways. It is strongly recommended to always specify 382 + both of these together (either granting both, or granting none). 388 383 389 384 A particularly surprising example is :manpage:`creat(2)`. The name suggests 390 385 that this system call requires the rights to create and write files. However, ··· 395 390 ``LANDLOCK_ACCESS_FS_WRITE_FILE`` right. Apart from the :manpage:`truncate(2)` 396 391 system call, this can also be done through :manpage:`open(2)` with the flags 397 392 ``O_RDONLY | O_TRUNC``. 393 + 394 + At the same time, on some filesystems, :manpage:`fallocate(2)` offers a way to 395 + shorten file contents with ``FALLOC_FL_COLLAPSE_RANGE`` when the file is opened 396 + for writing, sidestepping the ``LANDLOCK_ACCESS_FS_TRUNCATE`` right. 398 397 399 398 The truncate right is associated with the opened file (see below). 400 399 ··· 708 699 enforce Landlock rulesets across all threads of the calling process 709 700 using the ``LANDLOCK_RESTRICT_SELF_TSYNC`` flag passed to 710 701 sys_landlock_restrict_self(). 702 + 703 + Pathname UNIX sockets (ABI < 9) 704 + ------------------------------- 705 + 706 + Starting with the Landlock ABI version 9, it is possible to restrict 707 + connections to pathname UNIX domain sockets (:manpage:`unix(7)`) using 708 + the new ``LANDLOCK_ACCESS_FS_RESOLVE_UNIX`` right. 711 709 712 710 .. _kernel_support: 713 711
+5
include/linux/lsm_hook_defs.h
··· 322 322 LSM_HOOK(int, 0, watch_key, struct key *key) 323 323 #endif /* CONFIG_SECURITY && CONFIG_KEY_NOTIFICATIONS */ 324 324 325 + #if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH) 326 + LSM_HOOK(int, 0, unix_find, const struct path *path, struct sock *other, 327 + int flags) 328 + #endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */ 329 + 325 330 #ifdef CONFIG_SECURITY_NETWORK 326 331 LSM_HOOK(int, 0, unix_stream_connect, struct sock *sock, struct sock *other, 327 332 struct sock *newsk)
+11
include/linux/security.h
··· 1954 1954 } 1955 1955 #endif /* CONFIG_SECURITY_NETWORK */ 1956 1956 1957 + #if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH) 1958 + 1959 + int security_unix_find(const struct path *path, struct sock *other, int flags); 1960 + 1961 + #else /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */ 1962 + static inline int security_unix_find(const struct path *path, struct sock *other, int flags) 1963 + { 1964 + return 0; 1965 + } 1966 + #endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */ 1967 + 1957 1968 #ifdef CONFIG_SECURITY_INFINIBAND 1958 1969 int security_ib_pkey_access(void *sec, u64 subnet_prefix, u16 pkey); 1959 1970 int security_ib_endport_manage_subnet(void *sec, const char *name, u8 port_num);
+24 -1
include/uapi/linux/landlock.h
··· 116 116 * ``LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF``, this flag only affects 117 117 * future nested domains, not the one being created. It can also be used 118 118 * with a @ruleset_fd value of -1 to mute subdomain logs without creating a 119 - * domain. 119 + * domain. When combined with %LANDLOCK_RESTRICT_SELF_TSYNC and a 120 + * @ruleset_fd value of -1, this configuration is propagated to all threads 121 + * of the current process. 120 122 * 121 123 * The following flag supports policy enforcement in multithreaded processes: 122 124 * ··· 250 248 * 251 249 * This access right is available since the fifth version of the Landlock 252 250 * ABI. 251 + * - %LANDLOCK_ACCESS_FS_RESOLVE_UNIX: Look up pathname UNIX domain sockets 252 + * (:manpage:`unix(7)`). On UNIX domain sockets, this restricts both calls to 253 + * :manpage:`connect(2)` as well as calls to :manpage:`sendmsg(2)` with an 254 + * explicit recipient address. 255 + * 256 + * This access right only applies to connections to UNIX server sockets which 257 + * were created outside of the newly created Landlock domain (e.g. from within 258 + * a parent domain or from an unrestricted process). Newly created UNIX 259 + * servers within the same Landlock domain continue to be accessible. In this 260 + * regard, %LANDLOCK_ACCESS_FS_RESOLVE_UNIX has the same semantics as the 261 + * ``LANDLOCK_SCOPE_*`` flags. 262 + * 263 + * If a resolve attempt is denied, the operation returns an ``EACCES`` error, 264 + * in line with other filesystem access rights (but different to denials for 265 + * abstract UNIX domain sockets). 266 + * 267 + * This access right is available since the ninth version of the Landlock ABI. 268 + * 269 + * The rationale for this design is described in 270 + * :ref:`Documentation/security/landlock.rst <scoped-flags-interaction>`. 253 271 * 254 272 * Whether an opened file can be truncated with :manpage:`ftruncate(2)` or used 255 273 * with `ioctl(2)` is determined during :manpage:`open(2)`, in the same way as ··· 355 333 #define LANDLOCK_ACCESS_FS_REFER (1ULL << 13) 356 334 #define LANDLOCK_ACCESS_FS_TRUNCATE (1ULL << 14) 357 335 #define LANDLOCK_ACCESS_FS_IOCTL_DEV (1ULL << 15) 336 + #define LANDLOCK_ACCESS_FS_RESOLVE_UNIX (1ULL << 16) 358 337 /* clang-format on */ 359 338 360 339 /**
+7 -3
net/unix/af_unix.c
··· 1231 1231 goto path_put; 1232 1232 1233 1233 err = -EPROTOTYPE; 1234 - if (sk->sk_type == type) 1235 - touch_atime(&path); 1236 - else 1234 + if (sk->sk_type != type) 1237 1235 goto sock_put; 1236 + 1237 + err = security_unix_find(&path, sk, flags); 1238 + if (err) 1239 + goto sock_put; 1240 + 1241 + touch_atime(&path); 1238 1242 1239 1243 path_put(&path); 1240 1244
+9 -3
samples/landlock/sandboxer.c
··· 111 111 LANDLOCK_ACCESS_FS_WRITE_FILE | \ 112 112 LANDLOCK_ACCESS_FS_READ_FILE | \ 113 113 LANDLOCK_ACCESS_FS_TRUNCATE | \ 114 - LANDLOCK_ACCESS_FS_IOCTL_DEV) 114 + LANDLOCK_ACCESS_FS_IOCTL_DEV | \ 115 + LANDLOCK_ACCESS_FS_RESOLVE_UNIX) 115 116 116 117 /* clang-format on */ 117 118 ··· 296 295 LANDLOCK_ACCESS_FS_MAKE_SYM | \ 297 296 LANDLOCK_ACCESS_FS_REFER | \ 298 297 LANDLOCK_ACCESS_FS_TRUNCATE | \ 299 - LANDLOCK_ACCESS_FS_IOCTL_DEV) 298 + LANDLOCK_ACCESS_FS_IOCTL_DEV | \ 299 + LANDLOCK_ACCESS_FS_RESOLVE_UNIX) 300 300 301 301 /* clang-format on */ 302 302 303 - #define LANDLOCK_ABI_LAST 8 303 + #define LANDLOCK_ABI_LAST 9 304 304 305 305 #define XSTR(s) #s 306 306 #define STR(s) XSTR(s) ··· 440 438 ~LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON; 441 439 __attribute__((fallthrough)); 442 440 case 7: 441 + case 8: 442 + /* Removes LANDLOCK_ACCESS_FS_RESOLVE_UNIX for ABI < 9 */ 443 + ruleset_attr.handled_access_fs &= 444 + ~LANDLOCK_ACCESS_FS_RESOLVE_UNIX; 443 445 /* Must be printed for any ABI < LANDLOCK_ABI_LAST. */ 444 446 fprintf(stderr, 445 447 "Hint: You should update the running kernel "
+2 -2
security/landlock/access.h
··· 34 34 LANDLOCK_ACCESS_FS_IOCTL_DEV) 35 35 /* clang-format on */ 36 36 37 - typedef u16 access_mask_t; 37 + typedef u32 access_mask_t; 38 38 39 39 /* Makes sure all filesystem access rights can be stored. */ 40 40 static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_FS); ··· 50 50 access_mask_t fs : LANDLOCK_NUM_ACCESS_FS; 51 51 access_mask_t net : LANDLOCK_NUM_ACCESS_NET; 52 52 access_mask_t scope : LANDLOCK_NUM_SCOPE; 53 - }; 53 + } __packed __aligned(sizeof(u32)); 54 54 55 55 union access_masks_all { 56 56 struct access_masks masks;
+1
security/landlock/audit.c
··· 37 37 [BIT_INDEX(LANDLOCK_ACCESS_FS_REFER)] = "fs.refer", 38 38 [BIT_INDEX(LANDLOCK_ACCESS_FS_TRUNCATE)] = "fs.truncate", 39 39 [BIT_INDEX(LANDLOCK_ACCESS_FS_IOCTL_DEV)] = "fs.ioctl_dev", 40 + [BIT_INDEX(LANDLOCK_ACCESS_FS_RESOLVE_UNIX)] = "fs.resolve_unix", 40 41 }; 41 42 42 43 static_assert(ARRAY_SIZE(fs_access_strings) == LANDLOCK_NUM_ACCESS_FS);
+2 -4
security/landlock/cred.c
··· 22 22 const struct landlock_cred_security *const old_llcred = 23 23 landlock_cred(old); 24 24 25 - if (old_llcred->domain) { 26 - landlock_get_ruleset(old_llcred->domain); 27 - *landlock_cred(new) = *old_llcred; 28 - } 25 + landlock_get_ruleset(old_llcred->domain); 26 + *landlock_cred(new) = *old_llcred; 29 27 } 30 28 31 29 static int hook_cred_prepare(struct cred *const new,
+1 -1
security/landlock/cred.h
··· 115 115 * @handle_layer: returned youngest layer handling a subset of @masks. Not set 116 116 * if the function returns NULL. 117 117 * 118 - * Returns: landlock_cred(@cred) if any access rights specified in @masks is 118 + * Return: landlock_cred(@cred) if any access rights specified in @masks is 119 119 * handled, or NULL otherwise. 120 120 */ 121 121 static inline const struct landlock_cred_security *
+4 -2
security/landlock/domain.c
··· 34 34 * @exe_size: Returned size of @exe_str (including the trailing null 35 35 * character), if any. 36 36 * 37 - * Returns: A pointer to an allocated buffer where @exe_str point to, %NULL if 37 + * Return: A pointer to an allocated buffer where @exe_str point to, %NULL if 38 38 * there is no executable path, or an error otherwise. 39 39 */ 40 40 static const void *get_current_exe(const char **const exe_str, ··· 73 73 } 74 74 75 75 /* 76 - * Returns: A newly allocated object describing a domain, or an error 76 + * Return: A newly allocated object describing a domain, or an error 77 77 * otherwise. 78 78 */ 79 79 static struct landlock_details *get_current_details(void) ··· 114 114 * restriction. The subjective credentials must not be in an overridden state. 115 115 * 116 116 * @hierarchy->parent and @hierarchy->usage should already be set. 117 + * 118 + * Return: 0 on success, -errno on failure. 117 119 */ 118 120 int landlock_init_hierarchy_log(struct landlock_hierarchy *const hierarchy) 119 121 {
+145 -18
security/landlock/fs.c
··· 27 27 #include <linux/lsm_hooks.h> 28 28 #include <linux/mount.h> 29 29 #include <linux/namei.h> 30 + #include <linux/net.h> 30 31 #include <linux/path.h> 31 32 #include <linux/pid.h> 32 33 #include <linux/rcupdate.h> ··· 37 36 #include <linux/types.h> 38 37 #include <linux/wait_bit.h> 39 38 #include <linux/workqueue.h> 39 + #include <net/af_unix.h> 40 40 #include <uapi/linux/fiemap.h> 41 41 #include <uapi/linux/landlock.h> 42 42 ··· 121 119 * Any new IOCTL commands that are implemented in fs/ioctl.c's do_vfs_ioctl() 122 120 * should be considered for inclusion here. 123 121 * 124 - * Returns: true if the IOCTL @cmd can not be restricted with Landlock for 125 - * device files. 122 + * Return: True if the IOCTL @cmd can not be restricted with Landlock for 123 + * device files, false otherwise. 126 124 */ 127 125 static __attribute_const__ bool is_masked_device_ioctl(const unsigned int cmd) 128 126 { ··· 316 314 LANDLOCK_ACCESS_FS_WRITE_FILE | \ 317 315 LANDLOCK_ACCESS_FS_READ_FILE | \ 318 316 LANDLOCK_ACCESS_FS_TRUNCATE | \ 319 - LANDLOCK_ACCESS_FS_IOCTL_DEV) 317 + LANDLOCK_ACCESS_FS_IOCTL_DEV | \ 318 + LANDLOCK_ACCESS_FS_RESOLVE_UNIX) 320 319 /* clang-format on */ 321 320 322 321 /* ··· 431 428 * Check that a destination file hierarchy has more restrictions than a source 432 429 * file hierarchy. This is only used for link and rename actions. 433 430 * 434 - * Returns: true if child1 may be moved from parent1 to parent2 without 435 - * increasing its access rights. If child2 is set, an additional condition is 431 + * Return: True if child1 may be moved from parent1 to parent2 without 432 + * increasing its access rights (if child2 is set, an additional condition is 436 433 * that child2 may be used from parent2 to parent1 without increasing its access 437 - * rights. 434 + * rights), false otherwise. 438 435 */ 439 436 static bool no_more_access(const struct layer_access_masks *const parent1, 440 437 const struct layer_access_masks *const child1, ··· 567 564 568 565 static bool is_layer_masks_allowed(const struct layer_access_masks *masks) 569 566 { 570 - return !memchr_inv(&masks->access, 0, sizeof(masks->access)); 567 + return mem_is_zero(&masks->access, sizeof(masks->access)); 571 568 } 572 569 573 570 /* ··· 737 734 * checks that the collected accesses and the remaining ones are enough to 738 735 * allow the request. 739 736 * 740 - * Returns: 741 - * - true if the access request is granted; 742 - * - false otherwise. 737 + * Return: True if the access request is granted, false otherwise. 743 738 */ 744 739 static bool 745 740 is_access_to_paths_allowed(const struct landlock_ruleset *const domain, ··· 1023 1022 * only handles walking on the same mount point and only checks one set of 1024 1023 * accesses. 1025 1024 * 1026 - * Returns: 1027 - * - true if all the domain access rights are allowed for @dir; 1028 - * - false if the walk reached @mnt_root. 1025 + * Return: True if all the domain access rights are allowed for @dir, false if 1026 + * the walk reached @mnt_root. 1029 1027 */ 1030 1028 static bool collect_domain_accesses(const struct landlock_ruleset *const domain, 1031 1029 const struct dentry *const mnt_root, ··· 1120 1120 * ephemeral matrices take some space on the stack, which limits the number of 1121 1121 * layers to a deemed reasonable number: 16. 1122 1122 * 1123 - * Returns: 1124 - * - 0 if access is allowed; 1125 - * - -EXDEV if @old_dentry would inherit new access rights from @new_dir; 1126 - * - -EACCES if file removal or creation is denied. 1123 + * Return: 0 if access is allowed, -EXDEV if @old_dentry would inherit new 1124 + * access rights from @new_dir, or -EACCES if file removal or creation is 1125 + * denied. 1127 1126 */ 1128 1127 static int current_check_refer_path(struct dentry *const old_dentry, 1129 1128 const struct path *const new_dir, ··· 1560 1561 return current_check_access_path(path, LANDLOCK_ACCESS_FS_TRUNCATE); 1561 1562 } 1562 1563 1564 + /** 1565 + * unmask_scoped_access - Remove access right bits in @masks in all layers 1566 + * where @client and @server have the same domain 1567 + * 1568 + * This does the same as domain_is_scoped(), but unmasks bits in @masks. 1569 + * It can not return early as domain_is_scoped() does. 1570 + * 1571 + * A scoped access for a given access right bit is allowed iff, for all layer 1572 + * depths where the access bit is set, the client and server domain are the 1573 + * same. This function clears the access rights @access in @masks at all layer 1574 + * depths where the client and server domain are the same, so that, when they 1575 + * are all cleared, the access is allowed. 1576 + * 1577 + * @client: Client domain 1578 + * @server: Server domain 1579 + * @masks: Layer access masks to unmask 1580 + * @access: Access bits that control scoping 1581 + */ 1582 + static void unmask_scoped_access(const struct landlock_ruleset *const client, 1583 + const struct landlock_ruleset *const server, 1584 + struct layer_access_masks *const masks, 1585 + const access_mask_t access) 1586 + { 1587 + int client_layer, server_layer; 1588 + const struct landlock_hierarchy *client_walker, *server_walker; 1589 + 1590 + /* This should not happen. */ 1591 + if (WARN_ON_ONCE(!client)) 1592 + return; 1593 + 1594 + /* Server has no Landlock domain; nothing to clear. */ 1595 + if (!server) 1596 + return; 1597 + 1598 + /* 1599 + * client_layer must be able to represent all numbers from 1600 + * LANDLOCK_MAX_NUM_LAYERS - 1 to -1 for the loop below to terminate. 1601 + * (It must be large enough, and it must be signed.) 1602 + */ 1603 + BUILD_BUG_ON(!is_signed_type(typeof(client_layer))); 1604 + BUILD_BUG_ON(LANDLOCK_MAX_NUM_LAYERS - 1 > 1605 + type_max(typeof(client_layer))); 1606 + 1607 + client_layer = client->num_layers - 1; 1608 + client_walker = client->hierarchy; 1609 + server_layer = server->num_layers - 1; 1610 + server_walker = server->hierarchy; 1611 + 1612 + /* 1613 + * Clears the access bits at all layers where the client domain is the 1614 + * same as the server domain. We start the walk at min(client_layer, 1615 + * server_layer). The layer bits until there can not be cleared because 1616 + * either the client or the server domain is missing. 1617 + */ 1618 + for (; client_layer > server_layer; client_layer--) 1619 + client_walker = client_walker->parent; 1620 + 1621 + for (; server_layer > client_layer; server_layer--) 1622 + server_walker = server_walker->parent; 1623 + 1624 + for (; client_layer >= 0; client_layer--) { 1625 + if (masks->access[client_layer] & access && 1626 + client_walker == server_walker) 1627 + masks->access[client_layer] &= ~access; 1628 + 1629 + client_walker = client_walker->parent; 1630 + server_walker = server_walker->parent; 1631 + } 1632 + } 1633 + 1634 + static int hook_unix_find(const struct path *const path, struct sock *other, 1635 + int flags) 1636 + { 1637 + const struct landlock_ruleset *dom_other; 1638 + const struct landlock_cred_security *subject; 1639 + struct layer_access_masks layer_masks; 1640 + struct landlock_request request = {}; 1641 + static const struct access_masks fs_resolve_unix = { 1642 + .fs = LANDLOCK_ACCESS_FS_RESOLVE_UNIX, 1643 + }; 1644 + 1645 + /* Lookup for the purpose of saving coredumps is OK. */ 1646 + if (unlikely(flags & SOCK_COREDUMP)) 1647 + return 0; 1648 + 1649 + subject = landlock_get_applicable_subject(current_cred(), 1650 + fs_resolve_unix, NULL); 1651 + 1652 + if (!subject) 1653 + return 0; 1654 + 1655 + /* 1656 + * Ignoring return value: that the domains apply was already checked in 1657 + * landlock_get_applicable_subject() above. 1658 + */ 1659 + landlock_init_layer_masks(subject->domain, fs_resolve_unix.fs, 1660 + &layer_masks, LANDLOCK_KEY_INODE); 1661 + 1662 + /* Checks the layers in which we are connecting within the same domain. */ 1663 + unix_state_lock(other); 1664 + if (unlikely(sock_flag(other, SOCK_DEAD) || !other->sk_socket || 1665 + !other->sk_socket->file)) { 1666 + unix_state_unlock(other); 1667 + /* 1668 + * We rely on the caller to catch the (non-reversible) SOCK_DEAD 1669 + * condition and retry the lookup. If we returned an error 1670 + * here, the lookup would not get retried. 1671 + */ 1672 + return 0; 1673 + } 1674 + dom_other = landlock_cred(other->sk_socket->file->f_cred)->domain; 1675 + 1676 + /* Access to the same (or a lower) domain is always allowed. */ 1677 + unmask_scoped_access(subject->domain, dom_other, &layer_masks, 1678 + fs_resolve_unix.fs); 1679 + unix_state_unlock(other); 1680 + 1681 + /* Checks the connections to allow-listed paths. */ 1682 + if (is_access_to_paths_allowed(subject->domain, path, 1683 + fs_resolve_unix.fs, &layer_masks, 1684 + &request, NULL, 0, NULL, NULL, NULL)) 1685 + return 0; 1686 + 1687 + landlock_log_denial(subject, &request); 1688 + return -EACCES; 1689 + } 1690 + 1563 1691 /* File hooks */ 1564 1692 1565 1693 /** ··· 1694 1568 * 1695 1569 * @file: File being opened. 1696 1570 * 1697 - * Returns the access rights that are required for opening the given file, 1571 + * Return: The access rights that are required for opening the given file, 1698 1572 * depending on the file type and open mode. 1699 1573 */ 1700 1574 static access_mask_t ··· 1964 1838 LSM_HOOK_INIT(path_unlink, hook_path_unlink), 1965 1839 LSM_HOOK_INIT(path_rmdir, hook_path_rmdir), 1966 1840 LSM_HOOK_INIT(path_truncate, hook_path_truncate), 1841 + LSM_HOOK_INIT(unix_find, hook_unix_find), 1967 1842 1968 1843 LSM_HOOK_INIT(file_alloc_security, hook_file_alloc_security), 1969 1844 LSM_HOOK_INIT(file_open, hook_file_open),
+1 -1
security/landlock/id.c
··· 258 258 * 259 259 * @number_of_ids: Number of IDs to hold. Must be greater than one. 260 260 * 261 - * Returns: The first ID in the range. 261 + * Return: The first ID in the range. 262 262 */ 263 263 u64 landlock_get_id_range(size_t number_of_ids) 264 264 {
+1 -1
security/landlock/limits.h
··· 19 19 #define LANDLOCK_MAX_NUM_LAYERS 16 20 20 #define LANDLOCK_MAX_NUM_RULES U32_MAX 21 21 22 - #define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_IOCTL_DEV 22 + #define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_RESOLVE_UNIX 23 23 #define LANDLOCK_MASK_ACCESS_FS ((LANDLOCK_LAST_ACCESS_FS << 1) - 1) 24 24 #define LANDLOCK_NUM_ACCESS_FS __const_hweight64(LANDLOCK_MASK_ACCESS_FS) 25 25
+8 -6
security/landlock/ruleset.c
··· 107 107 108 108 static struct landlock_rule * 109 109 create_rule(const struct landlock_id id, 110 - const struct landlock_layer (*const layers)[], const u32 num_layers, 110 + const struct landlock_layer (*layers)[], const u32 num_layers, 111 111 const struct landlock_layer *const new_layer) 112 112 { 113 113 struct landlock_rule *new_rule; ··· 201 201 * When merging a ruleset in a domain, or copying a domain, @layers will be 202 202 * added to @ruleset as new constraints, similarly to a boolean AND between 203 203 * access rights. 204 + * 205 + * Return: 0 on success, -errno on failure. 204 206 */ 205 207 static int insert_rule(struct landlock_ruleset *const ruleset, 206 208 const struct landlock_id id, 207 - const struct landlock_layer (*const layers)[], 209 + const struct landlock_layer (*layers)[], 208 210 const size_t num_layers) 209 211 { 210 212 struct rb_node **walker_node; ··· 532 530 * The current task is requesting to be restricted. The subjective credentials 533 531 * must not be in an overridden state. cf. landlock_init_hierarchy_log(). 534 532 * 535 - * Returns the intersection of @parent and @ruleset, or returns @parent if 536 - * @ruleset is empty, or returns a duplicate of @ruleset if @parent is empty. 533 + * Return: A new domain merging @parent and @ruleset on success, or ERR_PTR() 534 + * on failure. If @parent is NULL, the new domain duplicates @ruleset. 537 535 */ 538 536 struct landlock_ruleset * 539 537 landlock_merge_ruleset(struct landlock_ruleset *const parent, ··· 624 622 * @rule: A rule that grants a set of access rights for each layer 625 623 * @masks: A matrix of unfulfilled access rights for each layer 626 624 * 627 - * Returns true if the request is allowed (i.e. the access rights granted all 625 + * Return: True if the request is allowed (i.e. the access rights granted all 628 626 * remaining unfulfilled access rights and masks has no leftover set bits). 629 627 */ 630 628 bool landlock_unmask_layers(const struct landlock_rule *const rule, ··· 674 672 * @masks: Layer access masks to populate. 675 673 * @key_type: The key type to switch between access masks of different types. 676 674 * 677 - * Returns: An access mask where each access right bit is set which is handled 675 + * Return: An access mask where each access right bit is set which is handled 678 676 * in any of the active layers in @domain. 679 677 */ 680 678 access_mask_t
+1 -1
security/landlock/ruleset.h
··· 224 224 * 225 225 * @domain: Landlock ruleset (used as a domain) 226 226 * 227 - * Returns: an access_masks result of the OR of all the domain's access masks. 227 + * Return: An access_masks result of the OR of all the domain's access masks. 228 228 */ 229 229 static inline struct access_masks 230 230 landlock_union_access_masks(const struct landlock_ruleset *const domain)
+21 -12
security/landlock/syscalls.c
··· 60 60 * @ksize_min: Minimal required size to be copied. 61 61 * @src: User space pointer or NULL. 62 62 * @usize: (Alleged) size of the data pointed to by @src. 63 + * 64 + * Return: 0 on success, -errno on failure. 63 65 */ 64 66 static __always_inline int 65 67 copy_min_struct_from_user(void *const dst, const size_t ksize, ··· 166 164 * If the change involves a fix that requires userspace awareness, also update 167 165 * the errata documentation in Documentation/userspace-api/landlock.rst . 168 166 */ 169 - const int landlock_abi_version = 8; 167 + const int landlock_abi_version = 9; 170 168 171 169 /** 172 170 * sys_landlock_create_ruleset - Create a new ruleset ··· 180 178 * - %LANDLOCK_CREATE_RULESET_VERSION 181 179 * - %LANDLOCK_CREATE_RULESET_ERRATA 182 180 * 183 - * This system call enables to create a new Landlock ruleset, and returns the 184 - * related file descriptor on success. 181 + * This system call enables to create a new Landlock ruleset. 185 182 * 186 183 * If %LANDLOCK_CREATE_RULESET_VERSION or %LANDLOCK_CREATE_RULESET_ERRATA is 187 184 * set, then @attr must be NULL and @size must be 0. 188 185 * 189 - * Possible returned errors are: 186 + * Return: The ruleset file descriptor on success, the Landlock ABI version if 187 + * %LANDLOCK_CREATE_RULESET_VERSION is set, the errata value if 188 + * %LANDLOCK_CREATE_RULESET_ERRATA is set, or -errno on failure. Possible 189 + * returned errors are: 190 190 * 191 191 * - %EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time; 192 - * - %EINVAL: unknown @flags, or unknown access, or unknown scope, or too small @size; 192 + * - %EINVAL: unknown @flags, or unknown access, or unknown scope, or too small 193 + * @size; 193 194 * - %E2BIG: @attr or @size inconsistencies; 194 195 * - %EFAULT: @attr or @size inconsistencies; 195 196 * - %ENOMSG: empty &landlock_ruleset_attr.handled_access_fs. ··· 403 398 * This system call enables to define a new rule and add it to an existing 404 399 * ruleset. 405 400 * 406 - * Possible returned errors are: 401 + * Return: 0 on success, or -errno on failure. Possible returned errors are: 407 402 * 408 403 * - %EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time; 409 404 * - %EAFNOSUPPORT: @rule_type is %LANDLOCK_RULE_NET_PORT but TCP/IP is not ··· 469 464 * namespace or is running with no_new_privs. This avoids scenarios where 470 465 * unprivileged tasks can affect the behavior of privileged children. 471 466 * 472 - * Possible returned errors are: 467 + * Return: 0 on success, or -errno on failure. Possible returned errors are: 473 468 * 474 469 * - %EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time; 475 470 * - %EINVAL: @flags contains an unknown bit. ··· 517 512 518 513 /* 519 514 * It is allowed to set LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF with 520 - * -1 as ruleset_fd, but no other flag must be set. 515 + * -1 as ruleset_fd, optionally combined with 516 + * LANDLOCK_RESTRICT_SELF_TSYNC to propagate this configuration to all 517 + * threads. No other flag must be set. 521 518 */ 522 519 if (!(ruleset_fd == -1 && 523 - flags == LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF)) { 520 + (flags & ~LANDLOCK_RESTRICT_SELF_TSYNC) == 521 + LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF)) { 524 522 /* Gets and checks the ruleset. */ 525 523 ruleset = get_ruleset_from_fd(ruleset_fd, FMODE_CAN_READ); 526 524 if (IS_ERR(ruleset)) ··· 545 537 546 538 /* 547 539 * The only case when a ruleset may not be set is if 548 - * LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF is set and ruleset_fd is -1. 549 - * We could optimize this case by not calling commit_creds() if this flag 550 - * was already set, but it is not worth the complexity. 540 + * LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF is set (optionally with 541 + * LANDLOCK_RESTRICT_SELF_TSYNC) and ruleset_fd is -1. We could 542 + * optimize this case by not calling commit_creds() if this flag was 543 + * already set, but it is not worth the complexity. 551 544 */ 552 545 if (ruleset) { 553 546 /*
+13 -9
security/landlock/task.c
··· 37 37 * 38 38 * Checks if the @parent domain is less or equal to (i.e. an ancestor, which 39 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. 40 43 */ 41 44 static bool domain_scope_le(const struct landlock_ruleset *const parent, 42 45 const struct landlock_ruleset *const child) ··· 82 79 * If the current task has Landlock rules, then the child must have at least 83 80 * the same rules. Else denied. 84 81 * 85 - * Determines whether a process may access another, returning 0 if permission 86 - * granted, -errno if denied. 82 + * Return: 0 if permission is granted, -errno if denied. 87 83 */ 88 84 static int hook_ptrace_access_check(struct task_struct *const child, 89 85 const unsigned int mode) ··· 131 129 * If the parent has Landlock rules, then the current task must have the same 132 130 * or more rules. Else denied. 133 131 * 134 - * Determines whether the nominated task is permitted to trace the current 135 - * process, returning 0 if permission is granted, -errno if denied. 132 + * Return: 0 if permission is granted, -errno if denied. 136 133 */ 137 134 static int hook_ptrace_traceme(struct task_struct *const parent) 138 135 { ··· 174 173 * @server: IPC receiver domain. 175 174 * @scope: The scope restriction criteria. 176 175 * 177 - * Returns: True if @server is in a different domain from @client, and @client 178 - * is scoped to access @server (i.e. access should be denied). 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. 179 178 */ 180 179 static bool domain_is_scoped(const struct landlock_ruleset *const client, 181 180 const struct landlock_ruleset *const server, ··· 191 190 client_layer = client->num_layers - 1; 192 191 client_walker = client->hierarchy; 193 192 /* 194 - * client_layer must be a signed integer with greater capacity 195 - * than client->num_layers to ensure the following loop stops. 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 196 */ 197 - BUILD_BUG_ON(sizeof(client_layer) > sizeof(client->num_layers)); 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))); 198 200 199 201 server_layer = server ? (server->num_layers - 1) : -1; 200 202 server_walker = server ? server->hierarchy : NULL;
+64 -60
security/landlock/tsync.c
··· 85 85 /* 86 86 * Switch out old_cred with new_cred, if possible. 87 87 * 88 - * In the common case, where all threads initially point to the same 89 - * struct cred, this optimization avoids creating separate redundant 90 - * credentials objects for each, which would all have the same contents. 88 + * In the common case, where all threads initially point to the 89 + * same struct cred, this optimization avoids creating separate 90 + * redundant credentials objects for each, which would all have 91 + * the same contents. 91 92 * 92 - * Note: We are intentionally dropping the const qualifier here, because 93 - * it is required by commit_creds() and abort_creds(). 93 + * Note: We are intentionally dropping the const qualifier 94 + * here, because it is required by commit_creds() and 95 + * abort_creds(). 94 96 */ 95 97 cred = (struct cred *)get_cred(ctx->new_cred); 96 98 } else { ··· 103 101 atomic_set(&ctx->preparation_error, -ENOMEM); 104 102 105 103 /* 106 - * Even on error, we need to adhere to the protocol and coordinate 107 - * with concurrently running invocations. 104 + * Even on error, we need to adhere to the protocol and 105 + * coordinate with concurrently running invocations. 108 106 */ 109 107 if (atomic_dec_return(&ctx->num_preparing) == 0) 110 108 complete_all(&ctx->all_prepared); ··· 137 135 } 138 136 139 137 /* 140 - * Make sure that all sibling tasks fulfill the no_new_privs prerequisite. 141 - * (This is in line with Seccomp's SECCOMP_FILTER_FLAG_TSYNC logic in 142 - * kernel/seccomp.c) 138 + * Make sure that all sibling tasks fulfill the no_new_privs 139 + * prerequisite. (This is in line with Seccomp's 140 + * SECCOMP_FILTER_FLAG_TSYNC logic in kernel/seccomp.c) 143 141 */ 144 142 if (ctx->set_no_new_privs) 145 143 task_set_no_new_privs(current); ··· 185 183 * capacity. This can legitimately happen if new threads get started after we 186 184 * grew the capacity. 187 185 * 188 - * Returns: 189 - * A pointer to the preallocated context struct, with task filled in. 190 - * 191 - * NULL, if we ran out of preallocated context structs. 186 + * Return: A pointer to the preallocated context struct with task filled in, or 187 + * NULL if preallocated context structs ran out. 192 188 */ 193 189 static struct tsync_work *tsync_works_provide(struct tsync_works *s, 194 190 struct task_struct *task) ··· 223 223 ctx = s->works[s->size - 1]; 224 224 225 225 /* 226 - * For consistency, remove the task from ctx so that it does not look like 227 - * we handed it a task_work. 226 + * For consistency, remove the task from ctx so that it does not look 227 + * like we handed it a task_work. 228 228 */ 229 229 put_task_struct(ctx->task); 230 230 *ctx = (typeof(*ctx)){}; 231 231 232 232 /* 233 - * Cancel the tsync_works_provide() change to recycle the reserved memory 234 - * for the next thread, if any. This also ensures that cancel_tsync_works() 235 - * and tsync_works_release() do not see any NULL task pointers. 233 + * Cancel the tsync_works_provide() change to recycle the reserved 234 + * memory for the next thread, if any. This also ensures that 235 + * cancel_tsync_works() and tsync_works_release() do not see any NULL 236 + * task pointers. 236 237 */ 237 238 s->size--; 238 239 } ··· 244 243 * On a successful return, the subsequent n calls to tsync_works_provide() are 245 244 * guaranteed to succeed. (size + n <= capacity) 246 245 * 247 - * Returns: 248 - * -ENOMEM if the (re)allocation fails 249 - 250 - * 0 if the allocation succeeds, partially succeeds, or no reallocation 251 - * was needed 246 + * Return: 0 if sufficient space for n more elements could be provided, -ENOMEM 247 + * on allocation errors, -EOVERFLOW in case of integer overflow. 252 248 */ 253 249 static int tsync_works_grow_by(struct tsync_works *s, size_t n, gfp_t flags) 254 250 { ··· 361 363 * For each added task_work, atomically increments shared_ctx->num_preparing and 362 364 * shared_ctx->num_unfinished. 363 365 * 364 - * Returns: 365 - * true, if at least one eligible sibling thread was found 366 + * Return: True if at least one eligible sibling thread was found, false 367 + * otherwise. 366 368 */ 367 369 static bool schedule_task_work(struct tsync_works *works, 368 370 struct tsync_shared_context *shared_ctx) ··· 391 393 continue; 392 394 393 395 /* 394 - * We found a sibling thread that is not doing its task_work yet, and 395 - * which might spawn new threads before our task work runs, so we need 396 - * at least one more round in the outer loop. 396 + * We found a sibling thread that is not doing its task_work 397 + * yet, and which might spawn new threads before our task work 398 + * runs, so we need at least one more round in the outer loop. 397 399 */ 398 400 found_more_threads = true; 399 401 400 402 ctx = tsync_works_provide(works, thread); 401 403 if (!ctx) { 402 404 /* 403 - * We ran out of preallocated contexts -- we need to try again with 404 - * this thread at a later time! 405 + * We ran out of preallocated contexts -- we need to 406 + * try again with this thread at a later time! 405 407 * found_more_threads is already true at this point. 406 408 */ 407 409 break; ··· 416 418 err = task_work_add(thread, &ctx->work, TWA_SIGNAL); 417 419 if (unlikely(err)) { 418 420 /* 419 - * task_work_add() only fails if the task is about to exit. We 420 - * checked that earlier, but it can happen as a race. Resume 421 - * without setting an error, as the task is probably gone in the 422 - * next loop iteration. 421 + * task_work_add() only fails if the task is about to 422 + * exit. We checked that earlier, but it can happen as 423 + * a race. Resume without setting an error, as the 424 + * task is probably gone in the next loop iteration. 423 425 */ 424 426 tsync_works_trim(works); 425 427 ··· 510 512 * After this barrier is reached, it's safe to read 511 513 * shared_ctx.preparation_error. 512 514 * 513 - * 4) reads shared_ctx.preparation_error and then either does commit_creds() 514 - * or abort_creds(). 515 + * 4) reads shared_ctx.preparation_error and then either does 516 + * commit_creds() or abort_creds(). 515 517 * 516 518 * 5) signals that it's done altogether (barrier synchronization 517 519 * "all_finished") 518 520 * 519 - * Unlike seccomp, which modifies sibling tasks directly, we do not need to 520 - * acquire the cred_guard_mutex and sighand->siglock: 521 + * Unlike seccomp, which modifies sibling tasks directly, we do not 522 + * need to acquire the cred_guard_mutex and sighand->siglock: 521 523 * 522 - * - As in our case, all threads are themselves exchanging their own struct 523 - * cred through the credentials API, no locks are needed for that. 524 + * - As in our case, all threads are themselves exchanging their own 525 + * struct cred through the credentials API, no locks are needed for 526 + * that. 524 527 * - Our for_each_thread() loops are protected by RCU. 525 - * - We do not acquire a lock to keep the list of sibling threads stable 526 - * between our for_each_thread loops. If the list of available sibling 527 - * threads changes between these for_each_thread loops, we make up for 528 - * that by continuing to look for threads until they are all discovered 529 - * and have entered their task_work, where they are unable to spawn new 530 - * threads. 528 + * - We do not acquire a lock to keep the list of sibling threads 529 + * stable between our for_each_thread loops. If the list of 530 + * available sibling threads changes between these for_each_thread 531 + * loops, we make up for that by continuing to look for threads until 532 + * they are all discovered and have entered their task_work, where 533 + * they are unable to spawn new threads. 531 534 */ 532 535 do { 533 536 /* In RCU read-lock, count the threads we need. */ ··· 545 546 } 546 547 547 548 /* 548 - * The "all_prepared" barrier is used locally to the loop body, this use 549 - * of for_each_thread(). We can reset it on each loop iteration because 550 - * all previous loop iterations are done with it already. 549 + * The "all_prepared" barrier is used locally to the loop body, 550 + * this use of for_each_thread(). We can reset it on each loop 551 + * iteration because all previous loop iterations are done with 552 + * it already. 551 553 * 552 - * num_preparing is initialized to 1 so that the counter can not go to 0 553 - * and mark the completion as done before all task works are registered. 554 - * We decrement it at the end of the loop body. 554 + * num_preparing is initialized to 1 so that the counter can 555 + * not go to 0 and mark the completion as done before all task 556 + * works are registered. We decrement it at the end of the 557 + * loop body. 555 558 */ 556 559 atomic_set(&shared_ctx.num_preparing, 1); 557 560 reinit_completion(&shared_ctx.all_prepared); 558 561 559 562 /* 560 - * In RCU read-lock, schedule task work on newly discovered sibling 561 - * tasks. 563 + * In RCU read-lock, schedule task work on newly discovered 564 + * sibling tasks. 562 565 */ 563 566 found_more_threads = schedule_task_work(&works, &shared_ctx); 564 567 565 568 /* 566 - * Decrement num_preparing for current, to undo that we initialized it 567 - * to 1 a few lines above. 569 + * Decrement num_preparing for current, to undo that we 570 + * initialized it to 1 a few lines above. 568 571 */ 569 572 if (atomic_dec_return(&shared_ctx.num_preparing) > 0) { 570 573 if (wait_for_completion_interruptible( 571 574 &shared_ctx.all_prepared)) { 572 - /* In case of interruption, we need to retry the system call. */ 575 + /* 576 + * In case of interruption, we need to retry 577 + * the system call. 578 + */ 573 579 atomic_set(&shared_ctx.preparation_error, 574 580 -ERESTARTNOINTR); 575 581 ··· 607 603 complete_all(&shared_ctx.ready_to_commit); 608 604 609 605 /* 610 - * Decrement num_unfinished for current, to undo that we initialized it to 1 611 - * at the beginning. 606 + * Decrement num_unfinished for current, to undo that we initialized it 607 + * to 1 at the beginning. 612 608 */ 613 609 if (atomic_dec_return(&shared_ctx.num_unfinished) > 0) 614 610 wait_for_completion(&shared_ctx.all_finished);
+20
security/security.c
··· 4834 4834 4835 4835 #endif /* CONFIG_SECURITY_NETWORK */ 4836 4836 4837 + #if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH) 4838 + /** 4839 + * security_unix_find() - Check if a named AF_UNIX socket can connect 4840 + * @path: path of the socket being connected to 4841 + * @other: peer sock 4842 + * @flags: flags associated with the socket 4843 + * 4844 + * This hook is called to check permissions before connecting to a named 4845 + * AF_UNIX socket. The caller does not hold any locks on @other. 4846 + * 4847 + * Return: Returns 0 if permission is granted. 4848 + */ 4849 + int security_unix_find(const struct path *path, struct sock *other, int flags) 4850 + { 4851 + return call_int_hook(unix_find, path, other, flags); 4852 + } 4853 + EXPORT_SYMBOL(security_unix_find); 4854 + 4855 + #endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */ 4856 + 4837 4857 #ifdef CONFIG_SECURITY_INFINIBAND 4838 4858 /** 4839 4859 * security_ib_pkey_access() - Check if access to an IB pkey is allowed
+102 -29
tools/testing/selftests/landlock/audit.h
··· 249 249 static int audit_match_record(int audit_fd, const __u16 type, 250 250 const char *const pattern, __u64 *domain_id) 251 251 { 252 - struct audit_message msg; 252 + struct audit_message msg, last_mismatch = {}; 253 253 int ret, err = 0; 254 - bool matches_record = !type; 254 + int num_type_match = 0; 255 255 regmatch_t matches[2]; 256 256 regex_t regex; 257 257 ··· 259 259 if (ret) 260 260 return -EINVAL; 261 261 262 - do { 262 + /* 263 + * Reads records until one matches both the expected type and the 264 + * pattern. Type-matching records with non-matching content are 265 + * silently consumed, which handles stale domain deallocation records 266 + * from a previous test emitted asynchronously by kworker threads. 267 + */ 268 + while (true) { 263 269 memset(&msg, 0, sizeof(msg)); 264 270 err = audit_recv(audit_fd, &msg); 265 - if (err) 271 + if (err) { 272 + if (num_type_match) { 273 + printf("DATA: %s\n", last_mismatch.data); 274 + printf("ERROR: %d record(s) matched type %u" 275 + " but not pattern: %s\n", 276 + num_type_match, type, pattern); 277 + } 266 278 goto out; 279 + } 267 280 268 - if (msg.header.nlmsg_type == type) 269 - matches_record = true; 270 - } while (!matches_record); 281 + if (type && msg.header.nlmsg_type != type) 282 + continue; 271 283 272 - ret = regexec(&regex, msg.data, ARRAY_SIZE(matches), matches, 0); 273 - if (ret) { 274 - printf("DATA: %s\n", msg.data); 275 - printf("ERROR: no match for pattern: %s\n", pattern); 276 - err = -ENOENT; 284 + ret = regexec(&regex, msg.data, ARRAY_SIZE(matches), matches, 285 + 0); 286 + if (!ret) 287 + break; 288 + 289 + num_type_match++; 290 + last_mismatch = msg; 277 291 } 278 292 279 293 if (domain_id) { ··· 323 309 324 310 log_match_len = 325 311 snprintf(log_match, sizeof(log_match), log_template, pid); 326 - if (log_match_len > sizeof(log_match)) 312 + if (log_match_len >= sizeof(log_match)) 327 313 return -E2BIG; 328 314 329 315 return audit_match_record(audit_fd, AUDIT_LANDLOCK_DOMAIN, log_match, 330 316 domain_id); 331 317 } 332 318 333 - static int __maybe_unused matches_log_domain_deallocated( 334 - int audit_fd, unsigned int num_denials, __u64 *domain_id) 319 + /* 320 + * Matches a domain deallocation record. When expected_domain_id is non-zero, 321 + * the pattern includes the specific domain ID so that stale deallocation 322 + * records from a previous test (with a different domain ID) are skipped by 323 + * audit_match_record(), and the socket timeout is temporarily increased to 324 + * audit_tv_dom_drop to wait for the asynchronous kworker deallocation. 325 + */ 326 + static int __maybe_unused 327 + matches_log_domain_deallocated(int audit_fd, unsigned int num_denials, 328 + __u64 expected_domain_id, __u64 *domain_id) 335 329 { 336 330 static const char log_template[] = REGEX_LANDLOCK_PREFIX 337 331 " status=deallocated denials=%u$"; 338 - char log_match[sizeof(log_template) + 10]; 339 - int log_match_len; 332 + static const char log_template_with_id[] = 333 + "^audit([0-9.:]\\+): domain=\\(%llx\\)" 334 + " status=deallocated denials=%u$"; 335 + char log_match[sizeof(log_template_with_id) + 32]; 336 + int log_match_len, err; 340 337 341 - log_match_len = snprintf(log_match, sizeof(log_match), log_template, 342 - num_denials); 343 - if (log_match_len > sizeof(log_match)) 338 + if (expected_domain_id) 339 + log_match_len = snprintf(log_match, sizeof(log_match), 340 + log_template_with_id, 341 + (unsigned long long)expected_domain_id, 342 + num_denials); 343 + else 344 + log_match_len = snprintf(log_match, sizeof(log_match), 345 + log_template, num_denials); 346 + 347 + if (log_match_len >= sizeof(log_match)) 344 348 return -E2BIG; 345 349 346 - return audit_match_record(audit_fd, AUDIT_LANDLOCK_DOMAIN, log_match, 347 - domain_id); 350 + if (expected_domain_id) 351 + setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO, 352 + &audit_tv_dom_drop, sizeof(audit_tv_dom_drop)); 353 + 354 + err = audit_match_record(audit_fd, AUDIT_LANDLOCK_DOMAIN, log_match, 355 + domain_id); 356 + 357 + if (expected_domain_id) 358 + setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_default, 359 + sizeof(audit_tv_default)); 360 + 361 + return err; 348 362 } 349 363 350 364 struct audit_records { ··· 380 338 size_t domain; 381 339 }; 382 340 341 + /* 342 + * WARNING: Do not assert records.domain == 0 without a preceding 343 + * audit_match_record() call. Domain deallocation records are emitted 344 + * asynchronously from kworker threads and can arrive after the drain in 345 + * audit_init(), corrupting the domain count. A preceding audit_match_record() 346 + * call consumes stale records while scanning, making the assertion safe in 347 + * practice because stale deallocation records arrive before the expected access 348 + * records. 349 + */ 383 350 static int audit_count_records(int audit_fd, struct audit_records *records) 384 351 { 385 352 struct audit_message msg; ··· 430 379 431 380 err = audit_set_status(fd, AUDIT_STATUS_ENABLED, 1); 432 381 if (err) 433 - return err; 382 + goto err_close; 434 383 435 384 err = audit_set_status(fd, AUDIT_STATUS_PID, getpid()); 436 385 if (err) 437 - return err; 386 + goto err_close; 438 387 439 388 /* Sets a timeout for negative tests. */ 440 389 err = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_default, 441 390 sizeof(audit_tv_default)); 442 - if (err) 443 - return -errno; 391 + if (err) { 392 + err = -errno; 393 + goto err_close; 394 + } 395 + 396 + /* 397 + * Drains stale audit records that accumulated in the kernel backlog 398 + * while no audit daemon socket was open. This happens when non-audit 399 + * Landlock tests generate records while audit_enabled is non-zero (e.g. 400 + * from boot configuration), or when domain deallocation records arrive 401 + * asynchronously after a previous test's socket was closed. 402 + */ 403 + while (audit_recv(fd, NULL) == 0) 404 + ; 444 405 445 406 return fd; 407 + 408 + err_close: 409 + close(fd); 410 + return err; 446 411 } 447 412 448 413 static int audit_init_filter_exe(struct audit_filter *filter, const char *path) ··· 508 441 509 442 filter = &new_filter; 510 443 err = audit_init_filter_exe(filter, NULL); 511 - if (err) 444 + if (err) { 445 + close(audit_fd); 512 446 return err; 447 + } 513 448 } 514 449 515 450 /* Filters might not be in place. */ ··· 537 468 538 469 err = audit_init_filter_exe(filter, NULL); 539 470 if (err) 540 - return err; 471 + goto err_close; 541 472 542 473 err = audit_filter_exe(fd, filter, AUDIT_ADD_RULE); 543 474 if (err) 544 - return err; 475 + goto err_close; 545 476 546 477 return fd; 478 + 479 + err_close: 480 + close(fd); 481 + return err; 547 482 }
+336 -21
tools/testing/selftests/landlock/audit_test.c
··· 139 139 WEXITSTATUS(status) != EXIT_SUCCESS) 140 140 _metadata->exit_code = KSFT_FAIL; 141 141 142 - /* Purges log from deallocated domains. */ 143 - EXPECT_EQ(0, setsockopt(self->audit_fd, SOL_SOCKET, SO_RCVTIMEO, 144 - &audit_tv_dom_drop, sizeof(audit_tv_dom_drop))); 142 + /* 143 + * Purges log from deallocated domains. Records arrive in LIFO order 144 + * (innermost domain first) because landlock_put_hierarchy() walks the 145 + * chain sequentially in a single kworker context. 146 + */ 145 147 for (i = ARRAY_SIZE(*domain_stack) - 1; i >= 0; i--) { 146 148 __u64 deallocated_dom = 2; 147 149 148 150 EXPECT_EQ(0, matches_log_domain_deallocated(self->audit_fd, 1, 151 + (*domain_stack)[i], 149 152 &deallocated_dom)); 150 153 EXPECT_EQ((*domain_stack)[i], deallocated_dom) 151 154 { 152 155 TH_LOG("Failed to match domain %llx (#%d)", 153 - (*domain_stack)[i], i); 156 + (unsigned long long)(*domain_stack)[i], i); 154 157 } 155 158 } 156 159 EXPECT_EQ(0, munmap(domain_stack, sizeof(*domain_stack))); 157 - EXPECT_EQ(0, setsockopt(self->audit_fd, SOL_SOCKET, SO_RCVTIMEO, 158 - &audit_tv_default, sizeof(audit_tv_default))); 159 160 EXPECT_EQ(0, close(ruleset_fd)); 160 161 } 161 162 162 163 struct thread_data { 163 164 pid_t parent_pid; 164 165 int ruleset_fd, pipe_child, pipe_parent; 166 + bool mute_subdomains; 165 167 }; 166 168 167 169 static void *thread_audit_test(void *arg) ··· 272 270 EXPECT_EQ(0, close(pipe_parent[1])); 273 271 ASSERT_EQ(0, pthread_join(thread, NULL)); 274 272 275 - EXPECT_EQ(0, setsockopt(self->audit_fd, SOL_SOCKET, SO_RCVTIMEO, 276 - &audit_tv_dom_drop, sizeof(audit_tv_dom_drop))); 277 - EXPECT_EQ(0, matches_log_domain_deallocated(self->audit_fd, 1, 278 - &deallocated_dom)); 273 + EXPECT_EQ(0, matches_log_domain_deallocated( 274 + self->audit_fd, 1, denial_dom, &deallocated_dom)); 279 275 EXPECT_EQ(denial_dom, deallocated_dom); 280 - EXPECT_EQ(0, setsockopt(self->audit_fd, SOL_SOCKET, SO_RCVTIMEO, 281 - &audit_tv_default, sizeof(audit_tv_default))); 276 + } 277 + 278 + /* 279 + * Verifies that log_subdomains_off set via the ruleset_fd=-1 path (without 280 + * creating a domain) is inherited by children across fork(). This exercises 281 + * the hook_cred_transfer() fix: the Landlock credential blob must be copied 282 + * even when the source credential has no domain. 283 + * 284 + * Phase 1 (baseline): a child without muting creates a domain and triggers a 285 + * denial that IS logged. 286 + * 287 + * Phase 2 (after muting): the parent mutes subdomain logs, forks another child 288 + * who creates a domain and triggers a denial that is NOT logged. 289 + */ 290 + TEST_F(audit, log_subdomains_off_fork) 291 + { 292 + const struct landlock_ruleset_attr ruleset_attr = { 293 + .scoped = LANDLOCK_SCOPE_SIGNAL, 294 + }; 295 + struct audit_records records; 296 + int ruleset_fd, status; 297 + pid_t child; 298 + 299 + ruleset_fd = 300 + landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 301 + ASSERT_LE(0, ruleset_fd); 302 + 303 + ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); 304 + 305 + /* 306 + * Phase 1: forks a child that creates a domain and triggers a denial 307 + * before any muting. This proves the audit path works. 308 + */ 309 + child = fork(); 310 + ASSERT_LE(0, child); 311 + if (child == 0) { 312 + ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0)); 313 + ASSERT_EQ(-1, kill(getppid(), 0)); 314 + ASSERT_EQ(EPERM, errno); 315 + _exit(0); 316 + return; 317 + } 318 + 319 + ASSERT_EQ(child, waitpid(child, &status, 0)); 320 + ASSERT_EQ(true, WIFEXITED(status)); 321 + ASSERT_EQ(0, WEXITSTATUS(status)); 322 + 323 + /* The denial must be logged (baseline). */ 324 + EXPECT_EQ(0, matches_log_signal(_metadata, self->audit_fd, getpid(), 325 + NULL)); 326 + 327 + /* Drains any remaining records (e.g. domain allocation). */ 328 + EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 329 + 330 + /* 331 + * Mutes subdomain logs without creating a domain. The parent's 332 + * credential has domain=NULL and log_subdomains_off=1. 333 + */ 334 + ASSERT_EQ(0, landlock_restrict_self( 335 + -1, LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF)); 336 + 337 + /* 338 + * Phase 2: forks a child that creates a domain and triggers a denial. 339 + * Because log_subdomains_off was inherited via fork(), the child's 340 + * domain has log_status=LANDLOCK_LOG_DISABLED. 341 + */ 342 + child = fork(); 343 + ASSERT_LE(0, child); 344 + if (child == 0) { 345 + ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0)); 346 + ASSERT_EQ(-1, kill(getppid(), 0)); 347 + ASSERT_EQ(EPERM, errno); 348 + _exit(0); 349 + return; 350 + } 351 + 352 + ASSERT_EQ(child, waitpid(child, &status, 0)); 353 + ASSERT_EQ(true, WIFEXITED(status)); 354 + ASSERT_EQ(0, WEXITSTATUS(status)); 355 + 356 + /* No denial record should appear. */ 357 + EXPECT_EQ(-EAGAIN, matches_log_signal(_metadata, self->audit_fd, 358 + getpid(), NULL)); 359 + 360 + EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 361 + EXPECT_EQ(0, records.access); 362 + 363 + EXPECT_EQ(0, close(ruleset_fd)); 364 + } 365 + 366 + /* 367 + * Thread function: runs two rounds of (create domain, trigger denial, signal 368 + * back), waiting for the main thread before each round. When mute_subdomains 369 + * is set, phase 1 also mutes subdomain logs via the fd=-1 path before creating 370 + * the domain. The ruleset_fd is kept open across both rounds so each 371 + * restrict_self call stacks a new domain layer. 372 + */ 373 + static void *thread_sandbox_deny_twice(void *arg) 374 + { 375 + const struct thread_data *data = (struct thread_data *)arg; 376 + uintptr_t err = 0; 377 + char buffer; 378 + 379 + /* Phase 1: optionally mutes, creates a domain, and triggers a denial. */ 380 + if (read(data->pipe_parent, &buffer, 1) != 1) { 381 + err = 1; 382 + goto out; 383 + } 384 + 385 + if (data->mute_subdomains && 386 + landlock_restrict_self(-1, 387 + LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF)) { 388 + err = 2; 389 + goto out; 390 + } 391 + 392 + if (landlock_restrict_self(data->ruleset_fd, 0)) { 393 + err = 3; 394 + goto out; 395 + } 396 + 397 + if (kill(data->parent_pid, 0) != -1 || errno != EPERM) { 398 + err = 4; 399 + goto out; 400 + } 401 + 402 + if (write(data->pipe_child, ".", 1) != 1) { 403 + err = 5; 404 + goto out; 405 + } 406 + 407 + /* Phase 2: stacks another domain and triggers a denial. */ 408 + if (read(data->pipe_parent, &buffer, 1) != 1) { 409 + err = 6; 410 + goto out; 411 + } 412 + 413 + if (landlock_restrict_self(data->ruleset_fd, 0)) { 414 + err = 7; 415 + goto out; 416 + } 417 + 418 + if (kill(data->parent_pid, 0) != -1 || errno != EPERM) { 419 + err = 8; 420 + goto out; 421 + } 422 + 423 + if (write(data->pipe_child, ".", 1) != 1) { 424 + err = 9; 425 + goto out; 426 + } 427 + 428 + out: 429 + close(data->ruleset_fd); 430 + close(data->pipe_child); 431 + close(data->pipe_parent); 432 + return (void *)err; 433 + } 434 + 435 + /* 436 + * Verifies that LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF with 437 + * LANDLOCK_RESTRICT_SELF_TSYNC and ruleset_fd=-1 propagates log_subdomains_off 438 + * to a sibling thread, suppressing audit logging on domains it subsequently 439 + * creates. 440 + * 441 + * Phase 1 (before TSYNC) acts as an inline baseline: the sibling creates a 442 + * domain and triggers a denial that IS logged. 443 + * 444 + * Phase 2 (after TSYNC) verifies suppression: the sibling stacks another domain 445 + * and triggers a denial that is NOT logged. 446 + */ 447 + TEST_F(audit, log_subdomains_off_tsync) 448 + { 449 + const struct landlock_ruleset_attr ruleset_attr = { 450 + .scoped = LANDLOCK_SCOPE_SIGNAL, 451 + }; 452 + struct audit_records records; 453 + struct thread_data child_data = {}; 454 + int pipe_child[2], pipe_parent[2]; 455 + char buffer; 456 + pthread_t thread; 457 + void *thread_ret; 458 + 459 + child_data.parent_pid = getppid(); 460 + ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC)); 461 + child_data.pipe_child = pipe_child[1]; 462 + ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC)); 463 + child_data.pipe_parent = pipe_parent[0]; 464 + child_data.ruleset_fd = 465 + landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 466 + ASSERT_LE(0, child_data.ruleset_fd); 467 + 468 + ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); 469 + 470 + /* Creates the sibling thread. */ 471 + ASSERT_EQ(0, pthread_create(&thread, NULL, thread_sandbox_deny_twice, 472 + &child_data)); 473 + 474 + /* 475 + * Phase 1: the sibling creates a domain and triggers a denial before 476 + * any log muting. This proves the audit path works. 477 + */ 478 + ASSERT_EQ(1, write(pipe_parent[1], ".", 1)); 479 + ASSERT_EQ(1, read(pipe_child[0], &buffer, 1)); 480 + 481 + /* The denial must be logged. */ 482 + EXPECT_EQ(0, matches_log_signal(_metadata, self->audit_fd, 483 + child_data.parent_pid, NULL)); 484 + 485 + /* Drains any remaining records (e.g. domain allocation). */ 486 + EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 487 + 488 + /* 489 + * Mutes subdomain logs and propagates to the sibling thread via TSYNC, 490 + * without creating a domain. 491 + */ 492 + ASSERT_EQ(0, landlock_restrict_self( 493 + -1, LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF | 494 + LANDLOCK_RESTRICT_SELF_TSYNC)); 495 + 496 + /* 497 + * Phase 2: the sibling stacks another domain and triggers a denial. 498 + * Because log_subdomains_off was propagated via TSYNC, the new domain 499 + * has log_status=LANDLOCK_LOG_DISABLED. 500 + */ 501 + ASSERT_EQ(1, write(pipe_parent[1], ".", 1)); 502 + ASSERT_EQ(1, read(pipe_child[0], &buffer, 1)); 503 + 504 + /* No denial record should appear. */ 505 + EXPECT_EQ(-EAGAIN, matches_log_signal(_metadata, self->audit_fd, 506 + child_data.parent_pid, NULL)); 507 + 508 + EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 509 + EXPECT_EQ(0, records.access); 510 + 511 + EXPECT_EQ(0, close(pipe_child[0])); 512 + EXPECT_EQ(0, close(pipe_parent[1])); 513 + ASSERT_EQ(0, pthread_join(thread, &thread_ret)); 514 + EXPECT_EQ(NULL, thread_ret); 515 + } 516 + 517 + /* 518 + * Verifies that LANDLOCK_RESTRICT_SELF_TSYNC without 519 + * LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF overrides a sibling thread's 520 + * log_subdomains_off, re-enabling audit logging on domains the sibling 521 + * subsequently creates. 522 + * 523 + * Phase 1: the sibling sets log_subdomains_off, creates a muted domain, and 524 + * triggers a denial that is NOT logged. 525 + * 526 + * Phase 2 (after TSYNC without LOG_SUBDOMAINS_OFF): the sibling stacks another 527 + * domain and triggers a denial that IS logged, proving the muting was 528 + * overridden. 529 + */ 530 + TEST_F(audit, tsync_override_log_subdomains_off) 531 + { 532 + const struct landlock_ruleset_attr ruleset_attr = { 533 + .scoped = LANDLOCK_SCOPE_SIGNAL, 534 + }; 535 + struct audit_records records; 536 + struct thread_data child_data = {}; 537 + int pipe_child[2], pipe_parent[2]; 538 + char buffer; 539 + pthread_t thread; 540 + void *thread_ret; 541 + 542 + child_data.parent_pid = getppid(); 543 + ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC)); 544 + child_data.pipe_child = pipe_child[1]; 545 + ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC)); 546 + child_data.pipe_parent = pipe_parent[0]; 547 + child_data.ruleset_fd = 548 + landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 549 + ASSERT_LE(0, child_data.ruleset_fd); 550 + 551 + ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); 552 + 553 + child_data.mute_subdomains = true; 554 + 555 + /* Creates the sibling thread. */ 556 + ASSERT_EQ(0, pthread_create(&thread, NULL, thread_sandbox_deny_twice, 557 + &child_data)); 558 + 559 + /* 560 + * Phase 1: the sibling mutes subdomain logs, creates a domain, and 561 + * triggers a denial. The denial must not be logged. 562 + */ 563 + ASSERT_EQ(1, write(pipe_parent[1], ".", 1)); 564 + ASSERT_EQ(1, read(pipe_child[0], &buffer, 1)); 565 + 566 + EXPECT_EQ(-EAGAIN, matches_log_signal(_metadata, self->audit_fd, 567 + child_data.parent_pid, NULL)); 568 + 569 + /* Drains any remaining records. */ 570 + EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 571 + EXPECT_EQ(0, records.access); 572 + 573 + /* 574 + * Overrides the sibling's log_subdomains_off by calling TSYNC without 575 + * LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF. 576 + */ 577 + ASSERT_EQ(0, landlock_restrict_self(child_data.ruleset_fd, 578 + LANDLOCK_RESTRICT_SELF_TSYNC)); 579 + 580 + /* 581 + * Phase 2: the sibling stacks another domain and triggers a denial. 582 + * Because TSYNC replaced its log_subdomains_off with 0, the new domain 583 + * has log_status=LANDLOCK_LOG_PENDING. 584 + */ 585 + ASSERT_EQ(1, write(pipe_parent[1], ".", 1)); 586 + ASSERT_EQ(1, read(pipe_child[0], &buffer, 1)); 587 + 588 + /* The denial must be logged. */ 589 + EXPECT_EQ(0, matches_log_signal(_metadata, self->audit_fd, 590 + child_data.parent_pid, NULL)); 591 + 592 + EXPECT_EQ(0, close(pipe_child[0])); 593 + EXPECT_EQ(0, close(pipe_parent[1])); 594 + ASSERT_EQ(0, pthread_join(thread, &thread_ret)); 595 + EXPECT_EQ(NULL, thread_ret); 282 596 } 283 597 284 598 FIXTURE(audit_flags) ··· 730 412 } else { 731 413 EXPECT_EQ(1, records.access); 732 414 } 733 - EXPECT_EQ(0, records.domain); 734 415 735 416 /* Updates filter rules to match the drop record. */ 736 417 set_cap(_metadata, CAP_AUDIT_CONTROL); ··· 750 433 751 434 if (variant->restrict_flags & 752 435 LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF) { 436 + /* 437 + * No deallocation record: denials=0 never matches a real 438 + * record. 439 + */ 753 440 EXPECT_EQ(-EAGAIN, 754 - matches_log_domain_deallocated(self->audit_fd, 0, 441 + matches_log_domain_deallocated(self->audit_fd, 0, 0, 755 442 &deallocated_dom)); 756 443 EXPECT_EQ(deallocated_dom, 2); 757 444 } else { 758 - EXPECT_EQ(0, setsockopt(self->audit_fd, SOL_SOCKET, SO_RCVTIMEO, 759 - &audit_tv_dom_drop, 760 - sizeof(audit_tv_dom_drop))); 761 445 EXPECT_EQ(0, matches_log_domain_deallocated(self->audit_fd, 2, 446 + *self->domain_id, 762 447 &deallocated_dom)); 763 448 EXPECT_NE(deallocated_dom, 2); 764 449 EXPECT_NE(deallocated_dom, 0); 765 450 EXPECT_EQ(deallocated_dom, *self->domain_id); 766 - EXPECT_EQ(0, setsockopt(self->audit_fd, SOL_SOCKET, SO_RCVTIMEO, 767 - &audit_tv_default, 768 - sizeof(audit_tv_default))); 769 451 } 770 452 } 771 453 ··· 917 601 /* Tests that there was no denial until now. */ 918 602 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 919 603 EXPECT_EQ(0, records.access); 920 - EXPECT_EQ(0, records.domain); 921 604 922 605 /* 923 606 * Wait for the child to do a first denied action by layer1 and
+1 -1
tools/testing/selftests/landlock/base_test.c
··· 76 76 const struct landlock_ruleset_attr ruleset_attr = { 77 77 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE, 78 78 }; 79 - ASSERT_EQ(8, landlock_create_ruleset(NULL, 0, 79 + ASSERT_EQ(9, landlock_create_ruleset(NULL, 0, 80 80 LANDLOCK_CREATE_RULESET_VERSION)); 81 81 82 82 ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0,
+733 -612
tools/testing/selftests/landlock/fs_test.c
··· 22 22 #include <sys/ioctl.h> 23 23 #include <sys/mount.h> 24 24 #include <sys/prctl.h> 25 + #include <sys/resource.h> 25 26 #include <sys/sendfile.h> 26 27 #include <sys/socket.h> 27 28 #include <sys/stat.h> ··· 576 575 LANDLOCK_ACCESS_FS_WRITE_FILE | \ 577 576 LANDLOCK_ACCESS_FS_READ_FILE | \ 578 577 LANDLOCK_ACCESS_FS_TRUNCATE | \ 579 - LANDLOCK_ACCESS_FS_IOCTL_DEV) 578 + LANDLOCK_ACCESS_FS_IOCTL_DEV | \ 579 + LANDLOCK_ACCESS_FS_RESOLVE_UNIX) 580 580 581 - #define ACCESS_LAST LANDLOCK_ACCESS_FS_IOCTL_DEV 581 + #define ACCESS_LAST LANDLOCK_ACCESS_FS_RESOLVE_UNIX 582 582 583 583 #define ACCESS_ALL ( \ 584 584 ACCESS_FILE | \ ··· 767 765 .handled_access_fs = handled_access_fs, 768 766 }; 769 767 770 - ASSERT_NE(NULL, rules) 771 - { 772 - TH_LOG("No rule list"); 773 - } 774 - ASSERT_NE(NULL, rules[0].path) 775 - { 776 - TH_LOG("Empty rule list"); 777 - } 778 - 779 768 ruleset_fd = 780 769 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 781 770 ASSERT_LE(0, ruleset_fd) ··· 774 781 TH_LOG("Failed to create a ruleset: %s", strerror(errno)); 775 782 } 776 783 777 - for (i = 0; rules[i].path; i++) { 778 - if (!rules[i].access) 779 - continue; 784 + if (rules) 785 + for (i = 0; rules[i].path; i++) { 786 + if (!rules[i].access) 787 + continue; 780 788 781 - add_path_beneath(_metadata, ruleset_fd, rules[i].access, 782 - rules[i].path); 783 - } 789 + add_path_beneath(_metadata, ruleset_fd, rules[i].access, 790 + rules[i].path); 791 + } 784 792 return ruleset_fd; 793 + } 794 + 795 + static void enforce_fs(struct __test_metadata *const _metadata, 796 + const __u64 access_fs, const struct rule rules[]) 797 + { 798 + const int ruleset_fd = create_ruleset(_metadata, access_fs, rules); 799 + 800 + enforce_ruleset(_metadata, ruleset_fd); 801 + EXPECT_EQ(0, close(ruleset_fd)); 785 802 } 786 803 787 804 TEST_F_FORK(layout0, proc_nsfs) ··· 880 877 }, 881 878 {}, 882 879 }; 883 - const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 884 880 char buf; 885 881 int reg_fd; 886 882 887 - ASSERT_LE(0, ruleset_fd); 888 - enforce_ruleset(_metadata, ruleset_fd); 889 - ASSERT_EQ(0, close(ruleset_fd)); 883 + enforce_fs(_metadata, ACCESS_RW, rules); 890 884 891 885 /* Tests on a directory (with or without O_PATH). */ 892 886 ASSERT_EQ(EACCES, test_open("/", O_RDONLY)); ··· 930 930 }, 931 931 {}, 932 932 }; 933 - /* Here, we only handle read accesses, not write accesses. */ 934 - const int ruleset_fd = create_ruleset(_metadata, ACCESS_RO, rules); 935 933 936 - ASSERT_LE(0, ruleset_fd); 937 - enforce_ruleset(_metadata, ruleset_fd); 938 - ASSERT_EQ(0, close(ruleset_fd)); 934 + /* Here, we only handle read accesses, not write accesses. */ 935 + enforce_fs(_metadata, ACCESS_RO, rules); 939 936 940 937 /* 941 938 * Because the policy does not handle LANDLOCK_ACCESS_FS_WRITE_FILE, ··· 961 964 }, 962 965 {}, 963 966 }; 964 - const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 965 967 966 - ASSERT_LE(0, ruleset_fd); 967 - enforce_ruleset(_metadata, ruleset_fd); 968 - ASSERT_EQ(0, close(ruleset_fd)); 968 + enforce_fs(_metadata, ACCESS_RW, rules); 969 969 970 970 /* Checks s1d1 hierarchy. */ 971 971 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); ··· 1014 1020 }, 1015 1021 {}, 1016 1022 }; 1017 - int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1); 1018 1023 1019 - ASSERT_LE(0, ruleset_fd); 1020 - enforce_ruleset(_metadata, ruleset_fd); 1021 - ASSERT_EQ(0, close(ruleset_fd)); 1024 + enforce_fs(_metadata, ACCESS_RW, layer1); 1022 1025 1023 1026 /* Checks s1d1 hierarchy with layer1. */ 1024 1027 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); ··· 1037 1046 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 1038 1047 1039 1048 /* Doesn't change anything from layer1. */ 1040 - ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2); 1041 - ASSERT_LE(0, ruleset_fd); 1042 - enforce_ruleset(_metadata, ruleset_fd); 1043 - ASSERT_EQ(0, close(ruleset_fd)); 1049 + enforce_fs(_metadata, ACCESS_RW, layer2); 1044 1050 1045 1051 /* Checks s1d1 hierarchy with layer2. */ 1046 1052 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); ··· 1059 1071 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY | O_DIRECTORY)); 1060 1072 1061 1073 /* Only allows write (but not read) to dir_s1d3. */ 1062 - ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer3); 1063 - ASSERT_LE(0, ruleset_fd); 1064 - enforce_ruleset(_metadata, ruleset_fd); 1065 - ASSERT_EQ(0, close(ruleset_fd)); 1074 + enforce_fs(_metadata, ACCESS_RW, layer3); 1066 1075 1067 1076 /* Checks s1d1 hierarchy with layer3. */ 1068 1077 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); ··· 1097 1112 }, 1098 1113 {}, 1099 1114 }; 1100 - int ruleset_fd; 1101 1115 1102 1116 ASSERT_EQ(0, unlink(file1_s1d1)); 1103 1117 ASSERT_EQ(0, unlink(file1_s1d2)); 1104 1118 1105 - ruleset_fd = 1106 - create_ruleset(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, layer1); 1107 - ASSERT_LE(0, ruleset_fd); 1108 - enforce_ruleset(_metadata, ruleset_fd); 1109 - ASSERT_EQ(0, close(ruleset_fd)); 1119 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, layer1); 1110 1120 1111 1121 ASSERT_EQ(-1, mknod(file1_s1d1, S_IFREG | 0700, 0)); 1112 1122 ASSERT_EQ(EACCES, errno); 1113 1123 ASSERT_EQ(0, mknod(file1_s1d2, S_IFREG | 0700, 0)); 1114 1124 ASSERT_EQ(0, unlink(file1_s1d2)); 1115 1125 1116 - ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_REMOVE_FILE, 1117 - layer2); 1118 - ASSERT_LE(0, ruleset_fd); 1119 - enforce_ruleset(_metadata, ruleset_fd); 1120 - ASSERT_EQ(0, close(ruleset_fd)); 1126 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_REMOVE_FILE, layer2); 1121 1127 1122 1128 /* Unchanged accesses for file creation. */ 1123 1129 ASSERT_EQ(-1, mknod(file1_s1d1, S_IFREG | 0700, 0)); ··· 1212 1236 }, 1213 1237 {}, 1214 1238 }; 1215 - int ruleset_fd; 1216 1239 1217 - ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE, 1218 - layer1_read); 1219 - ASSERT_LE(0, ruleset_fd); 1220 - enforce_ruleset(_metadata, ruleset_fd); 1221 - ASSERT_EQ(0, close(ruleset_fd)); 1240 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_READ_FILE, layer1_read); 1222 1241 1223 1242 /* Checks that read access is granted for file1_s1d3 with layer 1. */ 1224 1243 ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR)); 1225 1244 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY)); 1226 1245 ASSERT_EQ(0, test_open(file2_s1d3, O_WRONLY)); 1227 1246 1228 - ruleset_fd = create_ruleset(_metadata, 1229 - LANDLOCK_ACCESS_FS_READ_FILE | 1230 - LANDLOCK_ACCESS_FS_WRITE_FILE, 1231 - layer2_read_write); 1232 - ASSERT_LE(0, ruleset_fd); 1233 - enforce_ruleset(_metadata, ruleset_fd); 1234 - ASSERT_EQ(0, close(ruleset_fd)); 1247 + enforce_fs(_metadata, 1248 + LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE, 1249 + layer2_read_write); 1235 1250 1236 1251 /* Checks that previous access rights are unchanged with layer 2. */ 1237 1252 ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR)); 1238 1253 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY)); 1239 1254 ASSERT_EQ(0, test_open(file2_s1d3, O_WRONLY)); 1240 1255 1241 - ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE, 1242 - layer3_read); 1243 - ASSERT_LE(0, ruleset_fd); 1244 - enforce_ruleset(_metadata, ruleset_fd); 1245 - ASSERT_EQ(0, close(ruleset_fd)); 1256 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_READ_FILE, layer3_read); 1246 1257 1247 1258 /* Checks that previous access rights are unchanged with layer 3. */ 1248 1259 ASSERT_EQ(0, test_open(file1_s1d3, O_RDWR)); ··· 1237 1274 ASSERT_EQ(0, test_open(file2_s1d3, O_WRONLY)); 1238 1275 1239 1276 /* This time, denies write access for the file hierarchy. */ 1240 - ruleset_fd = create_ruleset(_metadata, 1241 - LANDLOCK_ACCESS_FS_READ_FILE | 1242 - LANDLOCK_ACCESS_FS_WRITE_FILE, 1243 - layer4_read_write); 1244 - ASSERT_LE(0, ruleset_fd); 1245 - enforce_ruleset(_metadata, ruleset_fd); 1246 - ASSERT_EQ(0, close(ruleset_fd)); 1277 + enforce_fs(_metadata, 1278 + LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE, 1279 + layer4_read_write); 1247 1280 1248 1281 /* 1249 1282 * Checks that the only change with layer 4 is that write access is ··· 1250 1291 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY)); 1251 1292 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY)); 1252 1293 1253 - ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE, 1254 - layer5_read); 1255 - ASSERT_LE(0, ruleset_fd); 1256 - enforce_ruleset(_metadata, ruleset_fd); 1257 - ASSERT_EQ(0, close(ruleset_fd)); 1294 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_READ_FILE, layer5_read); 1258 1295 1259 1296 /* Checks that previous access rights are unchanged with layer 5. */ 1260 1297 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); ··· 1258 1303 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY)); 1259 1304 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY)); 1260 1305 1261 - ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_EXECUTE, 1262 - layer6_execute); 1263 - ASSERT_LE(0, ruleset_fd); 1264 - enforce_ruleset(_metadata, ruleset_fd); 1265 - ASSERT_EQ(0, close(ruleset_fd)); 1306 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_EXECUTE, layer6_execute); 1266 1307 1267 1308 /* Checks that previous access rights are unchanged with layer 6. */ 1268 1309 ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY)); ··· 1266 1315 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_WRONLY)); 1267 1316 ASSERT_EQ(EACCES, test_open(file2_s1d3, O_RDONLY)); 1268 1317 1269 - ruleset_fd = create_ruleset(_metadata, 1270 - LANDLOCK_ACCESS_FS_READ_FILE | 1271 - LANDLOCK_ACCESS_FS_WRITE_FILE, 1272 - layer7_read_write); 1273 - ASSERT_LE(0, ruleset_fd); 1274 - enforce_ruleset(_metadata, ruleset_fd); 1275 - ASSERT_EQ(0, close(ruleset_fd)); 1318 + enforce_fs(_metadata, 1319 + LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE, 1320 + layer7_read_write); 1276 1321 1277 1322 /* Checks read access is now denied with layer 7. */ 1278 1323 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_RDONLY)); ··· 1289 1342 }; 1290 1343 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1291 1344 1292 - ASSERT_LE(0, ruleset_fd); 1293 1345 enforce_ruleset(_metadata, ruleset_fd); 1294 1346 1295 1347 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY)); ··· 1404 1458 }; 1405 1459 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1406 1460 1407 - ASSERT_LE(0, ruleset_fd); 1408 1461 enforce_ruleset(_metadata, ruleset_fd); 1409 1462 1410 1463 /* Readdir access is denied for dir_s1d2. */ ··· 1419 1474 LANDLOCK_ACCESS_FS_READ_DIR, 1420 1475 dir_s1d2); 1421 1476 enforce_ruleset(_metadata, ruleset_fd); 1422 - ASSERT_EQ(0, close(ruleset_fd)); 1477 + EXPECT_EQ(0, close(ruleset_fd)); 1423 1478 1424 1479 /* Readdir access is still denied for dir_s1d2. */ 1425 1480 ASSERT_EQ(EACCES, test_open(dir_s1d2, O_RDONLY | O_DIRECTORY)); ··· 1441 1496 }; 1442 1497 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1443 1498 1444 - ASSERT_LE(0, ruleset_fd); 1445 1499 for (i = 0; i < 16; i++) 1446 1500 enforce_ruleset(_metadata, ruleset_fd); 1447 1501 ··· 1449 1505 ASSERT_EQ(-1, err); 1450 1506 ASSERT_EQ(E2BIG, errno); 1451 1507 } 1452 - ASSERT_EQ(0, close(ruleset_fd)); 1508 + EXPECT_EQ(0, close(ruleset_fd)); 1453 1509 } 1454 1510 1455 1511 TEST_F_FORK(layout1, empty_or_same_ruleset) ··· 1463 1519 ASSERT_LE(-1, ruleset_fd); 1464 1520 ASSERT_EQ(ENOMSG, errno); 1465 1521 1466 - /* Enforces policy which deny read access to all files. */ 1467 - ruleset_attr.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE; 1468 - ruleset_fd = 1469 - landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 1470 - ASSERT_LE(0, ruleset_fd); 1471 - enforce_ruleset(_metadata, ruleset_fd); 1522 + /* Enforces policy which denies read access to all files. */ 1523 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_READ_FILE, NULL); 1524 + 1472 1525 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); 1473 1526 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY)); 1474 1527 1475 - /* Nests a policy which deny read access to all directories. */ 1476 - ruleset_attr.handled_access_fs = LANDLOCK_ACCESS_FS_READ_DIR; 1528 + /* Nests a policy which denies read access to all directories. */ 1477 1529 ruleset_fd = 1478 - landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 1479 - ASSERT_LE(0, ruleset_fd); 1530 + create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_DIR, NULL); 1480 1531 enforce_ruleset(_metadata, ruleset_fd); 1481 1532 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); 1482 1533 ASSERT_EQ(EACCES, test_open(dir_s1d1, O_RDONLY)); ··· 1495 1556 }, 1496 1557 {}, 1497 1558 }; 1498 - const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1499 1559 1500 - ASSERT_LE(0, ruleset_fd); 1501 - enforce_ruleset(_metadata, ruleset_fd); 1502 - ASSERT_EQ(0, close(ruleset_fd)); 1560 + enforce_fs(_metadata, ACCESS_RW, rules); 1503 1561 1504 1562 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY)); 1505 1563 ··· 1521 1585 }, 1522 1586 {}, 1523 1587 }; 1524 - const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1525 1588 1526 - ASSERT_LE(0, ruleset_fd); 1527 - enforce_ruleset(_metadata, ruleset_fd); 1528 - ASSERT_EQ(0, close(ruleset_fd)); 1589 + enforce_fs(_metadata, ACCESS_RW, rules); 1529 1590 1530 1591 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY)); 1531 1592 ··· 1546 1613 }, 1547 1614 {}, 1548 1615 }; 1549 - int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1550 1616 1551 - ASSERT_LE(0, ruleset_fd); 1552 - enforce_ruleset(_metadata, ruleset_fd); 1553 - ASSERT_EQ(0, close(ruleset_fd)); 1617 + enforce_fs(_metadata, ACCESS_RW, rules); 1554 1618 1555 1619 /* Checks allowed access. */ 1556 1620 ASSERT_EQ(0, test_open("/", O_RDONLY)); 1557 1621 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY)); 1558 1622 1559 1623 rules[0].access = LANDLOCK_ACCESS_FS_READ_FILE; 1560 - ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1561 - ASSERT_LE(0, ruleset_fd); 1562 - enforce_ruleset(_metadata, ruleset_fd); 1563 - ASSERT_EQ(0, close(ruleset_fd)); 1624 + enforce_fs(_metadata, ACCESS_RW, rules); 1564 1625 1565 1626 /* Checks denied access (on a directory). */ 1566 1627 ASSERT_EQ(EACCES, test_open("/", O_RDONLY)); ··· 1570 1643 }, 1571 1644 {}, 1572 1645 }; 1573 - const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1574 1646 1575 - ASSERT_LE(0, ruleset_fd); 1576 - enforce_ruleset(_metadata, ruleset_fd); 1577 - ASSERT_EQ(0, close(ruleset_fd)); 1647 + enforce_fs(_metadata, ACCESS_RW, rules); 1578 1648 1579 1649 /* Checks denied access (on a directory). */ 1580 1650 ASSERT_EQ(EACCES, test_open("/", O_RDONLY)); ··· 1587 1663 }, 1588 1664 {}, 1589 1665 }; 1590 - int ruleset_fd; 1591 1666 1592 1667 set_cap(_metadata, CAP_SYS_ADMIN); 1593 1668 ASSERT_EQ(0, syscall(__NR_pivot_root, dir_s3d2, dir_s3d3)) ··· 1596 1673 ASSERT_EQ(0, chdir("/")); 1597 1674 clear_cap(_metadata, CAP_SYS_ADMIN); 1598 1675 1599 - ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1600 - ASSERT_LE(0, ruleset_fd); 1601 - enforce_ruleset(_metadata, ruleset_fd); 1602 - ASSERT_EQ(0, close(ruleset_fd)); 1676 + enforce_fs(_metadata, ACCESS_RW, rules); 1603 1677 1604 1678 ASSERT_EQ(0, test_open("s3d3", O_RDONLY)); 1605 1679 ASSERT_EQ(EACCES, test_open("/", O_RDONLY)); ··· 1611 1691 }, 1612 1692 {}, 1613 1693 }; 1614 - const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1615 1694 1616 - ASSERT_LE(0, ruleset_fd); 1617 - enforce_ruleset(_metadata, ruleset_fd); 1618 - ASSERT_EQ(0, close(ruleset_fd)); 1695 + enforce_fs(_metadata, ACCESS_RW, rules); 1619 1696 1620 1697 set_cap(_metadata, CAP_SYS_ADMIN); 1621 1698 ASSERT_EQ(-1, mount(NULL, dir_s3d2, NULL, MS_RDONLY, NULL)); ··· 1631 1714 }, 1632 1715 {}, 1633 1716 }; 1634 - const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1635 - 1636 - ASSERT_LE(0, ruleset_fd); 1637 1717 1638 1718 set_cap(_metadata, CAP_SYS_ADMIN); 1639 1719 ASSERT_EQ(0, syscall(__NR_move_mount, AT_FDCWD, dir_s3d2, AT_FDCWD, ··· 1643 1729 dir_s3d2, 0)); 1644 1730 clear_cap(_metadata, CAP_SYS_ADMIN); 1645 1731 1646 - enforce_ruleset(_metadata, ruleset_fd); 1647 - ASSERT_EQ(0, close(ruleset_fd)); 1732 + enforce_fs(_metadata, ACCESS_RW, rules); 1648 1733 1649 1734 set_cap(_metadata, CAP_SYS_ADMIN); 1650 1735 ASSERT_EQ(-1, syscall(__NR_move_mount, AT_FDCWD, dir_s3d2, AT_FDCWD, ··· 1658 1745 .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | 1659 1746 LANDLOCK_ACCESS_NET_CONNECT_TCP, 1660 1747 }; 1661 - int ruleset_fd; 1662 1748 1663 1749 /* Add network restrictions. */ 1664 - ruleset_fd = 1665 - landlock_create_ruleset(&ruleset_net, sizeof(ruleset_net), 0); 1666 - ASSERT_LE(0, ruleset_fd); 1667 - enforce_ruleset(_metadata, ruleset_fd); 1668 - ASSERT_EQ(0, close(ruleset_fd)); 1750 + drop_access_rights(_metadata, &ruleset_net); 1669 1751 1670 1752 /* Mount, remount, move_mount, umount, and pivot_root checks. */ 1671 1753 set_cap(_metadata, CAP_SYS_ADMIN); ··· 1681 1773 LANDLOCK_ACCESS_NET_CONNECT_TCP, 1682 1774 .handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE, 1683 1775 }; 1684 - int ruleset_fd; 1685 1776 1686 1777 /* Add network and filesystem restrictions. */ 1687 - ruleset_fd = landlock_create_ruleset(&ruleset_net_fs, 1688 - sizeof(ruleset_net_fs), 0); 1689 - ASSERT_LE(0, ruleset_fd); 1690 - enforce_ruleset(_metadata, ruleset_fd); 1691 - ASSERT_EQ(0, close(ruleset_fd)); 1778 + drop_access_rights(_metadata, &ruleset_net_fs); 1692 1779 1693 1780 /* Mount, remount, move_mount, umount, and pivot_root checks. */ 1694 1781 set_cap(_metadata, CAP_SYS_ADMIN); ··· 1720 1817 }; 1721 1818 const int ruleset_fd = create_ruleset(_metadata, ACCESS_RW, rules); 1722 1819 1723 - ASSERT_LE(0, ruleset_fd); 1724 1820 /* Unmount a file hierarchy while it is being used by a ruleset. */ 1725 1821 set_cap(_metadata, CAP_SYS_ADMIN); 1726 1822 ASSERT_EQ(0, umount(dir_s3d2)); 1727 1823 clear_cap(_metadata, CAP_SYS_ADMIN); 1728 1824 1729 1825 enforce_ruleset(_metadata, ruleset_fd); 1730 - ASSERT_EQ(0, close(ruleset_fd)); 1826 + EXPECT_EQ(0, close(ruleset_fd)); 1731 1827 1732 1828 ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY)); 1733 1829 ASSERT_EQ(EACCES, test_open(dir_s3d2, O_RDONLY)); ··· 1758 1856 /* Creates a ruleset with the future hidden directory. */ 1759 1857 ruleset_fd = 1760 1858 create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_DIR, layer1); 1761 - ASSERT_LE(0, ruleset_fd); 1762 1859 1763 1860 /* Covers with a new mount point. */ 1764 1861 set_cap(_metadata, CAP_SYS_ADMIN); ··· 1807 1906 }; 1808 1907 int dirfd, ruleset_fd; 1809 1908 1810 - ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_base); 1811 - ASSERT_LE(0, ruleset_fd); 1812 - enforce_ruleset(_metadata, ruleset_fd); 1813 - ASSERT_EQ(0, close(ruleset_fd)); 1909 + enforce_fs(_metadata, ACCESS_RW, layer1_base); 1814 1910 1815 1911 ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_subs); 1816 1912 ··· 1988 2090 }, 1989 2091 {}, 1990 2092 }; 1991 - const int ruleset_fd = 1992 - create_ruleset(_metadata, rules[0].access, rules); 1993 2093 1994 - ASSERT_LE(0, ruleset_fd); 1995 2094 copy_file(_metadata, bin_true, file1_s1d1); 1996 2095 copy_file(_metadata, bin_true, file1_s1d2); 1997 2096 copy_file(_metadata, bin_true, file1_s1d3); ··· 1997 2102 test_execute(_metadata, 0, file1_s1d1); 1998 2103 test_check_exec(_metadata, 0, file1_s1d1); 1999 2104 2000 - enforce_ruleset(_metadata, ruleset_fd); 2001 - ASSERT_EQ(0, close(ruleset_fd)); 2105 + enforce_fs(_metadata, rules[0].access, rules); 2002 2106 2003 2107 ASSERT_EQ(0, test_open(dir_s1d1, O_RDONLY)); 2004 2108 ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY)); ··· 2108 2214 }, 2109 2215 {}, 2110 2216 }; 2111 - int ruleset_fd = create_ruleset(_metadata, layer1[0].access, layer1); 2112 - 2113 - ASSERT_LE(0, ruleset_fd); 2114 2217 2115 2218 ASSERT_EQ(0, unlink(file1_s1d1)); 2116 2219 ASSERT_EQ(0, unlink(file1_s1d2)); 2117 2220 ASSERT_EQ(0, unlink(file1_s1d3)); 2118 2221 2119 - enforce_ruleset(_metadata, ruleset_fd); 2120 - ASSERT_EQ(0, close(ruleset_fd)); 2222 + enforce_fs(_metadata, layer1[0].access, layer1); 2121 2223 2122 2224 ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1)); 2123 2225 ASSERT_EQ(EACCES, errno); ··· 2133 2243 ASSERT_EQ(0, unlink(file2_s1d2)); 2134 2244 ASSERT_EQ(0, unlink(file2_s1d3)); 2135 2245 2136 - ruleset_fd = create_ruleset(_metadata, layer2[0].access, layer2); 2137 - ASSERT_LE(0, ruleset_fd); 2138 - enforce_ruleset(_metadata, ruleset_fd); 2139 - ASSERT_EQ(0, close(ruleset_fd)); 2246 + enforce_fs(_metadata, layer2[0].access, layer2); 2140 2247 2141 2248 /* Checks that linkind doesn't require the ability to delete a file. */ 2142 2249 ASSERT_EQ(0, link(file1_s1d2, file2_s1d2)); ··· 2183 2296 }, 2184 2297 {}, 2185 2298 }; 2186 - const int ruleset_fd = 2187 - create_ruleset(_metadata, rules[0].access, rules); 2188 - 2189 - ASSERT_LE(0, ruleset_fd); 2190 2299 2191 2300 ASSERT_EQ(0, unlink(file1_s1d2)); 2192 2301 2193 - enforce_ruleset(_metadata, ruleset_fd); 2194 - ASSERT_EQ(0, close(ruleset_fd)); 2302 + enforce_fs(_metadata, rules[0].access, rules); 2195 2303 2196 2304 /* 2197 2305 * Tries to replace a file, from a directory that allows file removal, ··· 2260 2378 }, 2261 2379 {}, 2262 2380 }; 2263 - const int ruleset_fd = 2264 - create_ruleset(_metadata, rules[0].access, rules); 2265 - 2266 - ASSERT_LE(0, ruleset_fd); 2267 2381 2268 2382 /* Empties dir_s1d3 to allow renaming. */ 2269 2383 ASSERT_EQ(0, unlink(file1_s1d3)); 2270 2384 ASSERT_EQ(0, unlink(file2_s1d3)); 2271 2385 2272 - enforce_ruleset(_metadata, ruleset_fd); 2273 - ASSERT_EQ(0, close(ruleset_fd)); 2386 + enforce_fs(_metadata, rules[0].access, rules); 2274 2387 2275 2388 /* Exchanges and renames directory to a different parent. */ 2276 2389 ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d3, AT_FDCWD, dir_s1d3, ··· 2319 2442 }, 2320 2443 {}, 2321 2444 }; 2322 - int ruleset_fd = 2323 - create_ruleset(_metadata, LANDLOCK_ACCESS_FS_REFER, layer1); 2324 2445 2325 - ASSERT_LE(0, ruleset_fd); 2326 - enforce_ruleset(_metadata, ruleset_fd); 2327 - ASSERT_EQ(0, close(ruleset_fd)); 2446 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_REFER, layer1); 2328 2447 2329 2448 ASSERT_EQ(-1, rename(dir_s1d2, dir_s2d1)); 2330 2449 ASSERT_EQ(EXDEV, errno); ··· 2350 2477 const int layer1_err, 2351 2478 const struct rule layer2[]) 2352 2479 { 2353 - int ruleset_fd; 2354 - 2355 2480 ASSERT_EQ(0, unlink(file1_s1d2)); 2356 2481 2357 - ruleset_fd = create_ruleset(_metadata, layer1[0].access, layer1); 2358 - ASSERT_LE(0, ruleset_fd); 2359 - enforce_ruleset(_metadata, ruleset_fd); 2360 - ASSERT_EQ(0, close(ruleset_fd)); 2482 + enforce_fs(_metadata, layer1[0].access, layer1); 2361 2483 2362 2484 /* 2363 2485 * If the first layer handles LANDLOCK_ACCESS_FS_REFER (according to ··· 2364 2496 ASSERT_EQ(layer1_err, test_exchange(file2_s1d1, file2_s1d2)); 2365 2497 ASSERT_EQ(layer1_err, test_exchange(file2_s1d2, file2_s1d1)); 2366 2498 2367 - ruleset_fd = create_ruleset(_metadata, layer2[0].access, layer2); 2368 - ASSERT_LE(0, ruleset_fd); 2369 - enforce_ruleset(_metadata, ruleset_fd); 2370 - ASSERT_EQ(0, close(ruleset_fd)); 2499 + enforce_fs(_metadata, layer2[0].access, layer2); 2371 2500 2372 2501 /* 2373 2502 * Now, either the first or the second layer does not handle ··· 2450 2585 */ 2451 2586 TEST_F_FORK(layout1, refer_mount_root_deny) 2452 2587 { 2453 - const struct landlock_ruleset_attr ruleset_attr = { 2454 - .handled_access_fs = LANDLOCK_ACCESS_FS_MAKE_DIR, 2455 - }; 2456 - int root_fd, ruleset_fd; 2588 + int root_fd; 2457 2589 2458 2590 /* Creates a mount object from a non-mount point. */ 2459 2591 set_cap(_metadata, CAP_SYS_ADMIN); ··· 2460 2598 clear_cap(_metadata, CAP_SYS_ADMIN); 2461 2599 ASSERT_LE(0, root_fd); 2462 2600 2463 - ruleset_fd = 2464 - landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 2465 - ASSERT_LE(0, ruleset_fd); 2466 - 2467 - ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); 2468 - ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0)); 2469 - EXPECT_EQ(0, close(ruleset_fd)); 2601 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_MAKE_DIR, NULL); 2470 2602 2471 2603 /* Link denied by Landlock: EACCES. */ 2472 2604 EXPECT_EQ(-1, linkat(root_fd, ".", root_fd, "does_not_exist", 0)); ··· 2495 2639 }, 2496 2640 {}, 2497 2641 }; 2498 - int ruleset_fd; 2499 2642 2500 2643 ASSERT_EQ(0, unlink(file1_s3d3)); 2501 - ruleset_fd = create_ruleset(_metadata, 2502 - LANDLOCK_ACCESS_FS_REFER | 2503 - LANDLOCK_ACCESS_FS_MAKE_REG | 2504 - LANDLOCK_ACCESS_FS_REMOVE_FILE, 2505 - layer1); 2506 - 2507 - ASSERT_LE(0, ruleset_fd); 2508 - enforce_ruleset(_metadata, ruleset_fd); 2509 - ASSERT_EQ(0, close(ruleset_fd)); 2644 + enforce_fs(_metadata, 2645 + LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG | 2646 + LANDLOCK_ACCESS_FS_REMOVE_FILE, 2647 + layer1); 2510 2648 2511 2649 ASSERT_EQ(0, rename(file1_s3d4, file1_s3d3)); 2512 2650 } ··· 2526 2676 }, 2527 2677 {}, 2528 2678 }; 2529 - const int ruleset_fd = create_ruleset( 2530 - _metadata, 2531 - LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_REFER, layer1); 2532 2679 2533 - ASSERT_LE(0, ruleset_fd); 2534 - enforce_ruleset(_metadata, ruleset_fd); 2535 - ASSERT_EQ(0, close(ruleset_fd)); 2680 + enforce_fs(_metadata, 2681 + LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_REFER, 2682 + layer1); 2536 2683 2537 2684 ASSERT_EQ(0, unlink(file1_s1d1)); 2538 2685 ASSERT_EQ(0, unlink(file1_s1d2)); ··· 2601 2754 }, 2602 2755 {}, 2603 2756 }; 2604 - const int ruleset_fd = create_ruleset( 2605 - _metadata, 2606 - LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_REFER, layer1); 2607 2757 2608 - ASSERT_LE(0, ruleset_fd); 2609 - enforce_ruleset(_metadata, ruleset_fd); 2610 - ASSERT_EQ(0, close(ruleset_fd)); 2758 + enforce_fs(_metadata, 2759 + LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_REFER, 2760 + layer1); 2611 2761 2612 2762 ASSERT_EQ(0, unlink(file1_s1d2)); 2613 2763 ASSERT_EQ(0, unlink(file1_s1d3)); ··· 2744 2900 }, 2745 2901 {}, 2746 2902 }; 2747 - const int ruleset_fd = create_ruleset( 2748 - _metadata, 2749 - LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_REFER, layer1); 2750 - 2751 - ASSERT_LE(0, ruleset_fd); 2752 - enforce_ruleset(_metadata, ruleset_fd); 2753 - ASSERT_EQ(0, close(ruleset_fd)); 2903 + enforce_fs(_metadata, 2904 + LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_REFER, 2905 + layer1); 2754 2906 } 2755 2907 2756 2908 static void ··· 2763 2923 * Same checks as before but with a second layer and a new MAKE_DIR 2764 2924 * rule (and no explicit handling of REFER). 2765 2925 */ 2766 - const int ruleset_fd = 2767 - create_ruleset(_metadata, LANDLOCK_ACCESS_FS_MAKE_DIR, layer2); 2768 - 2769 - ASSERT_LE(0, ruleset_fd); 2770 - enforce_ruleset(_metadata, ruleset_fd); 2771 - ASSERT_EQ(0, close(ruleset_fd)); 2926 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_MAKE_DIR, layer2); 2772 2927 } 2773 2928 2774 2929 TEST_F_FORK(layout1, reparent_exdev_layers_rename1) ··· 3032 3197 }, 3033 3198 {}, 3034 3199 }; 3035 - const int ruleset_fd = create_ruleset( 3036 - _metadata, 3037 - LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_REMOVE_DIR | 3038 - LANDLOCK_ACCESS_FS_REMOVE_FILE, 3039 - layer1); 3040 3200 3041 - ASSERT_LE(0, ruleset_fd); 3042 - enforce_ruleset(_metadata, ruleset_fd); 3043 - ASSERT_EQ(0, close(ruleset_fd)); 3201 + enforce_fs(_metadata, 3202 + LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_REMOVE_DIR | 3203 + LANDLOCK_ACCESS_FS_REMOVE_FILE, 3204 + layer1); 3044 3205 3045 3206 /* Access denied because of wrong/swapped remove file/dir. */ 3046 3207 ASSERT_EQ(-1, rename(file1_s1d1, dir_s2d2)); ··· 3100 3269 }, 3101 3270 {}, 3102 3271 }; 3103 - int ruleset_fd = create_ruleset(_metadata, 3104 - LANDLOCK_ACCESS_FS_REFER | 3105 - LANDLOCK_ACCESS_FS_EXECUTE | 3106 - LANDLOCK_ACCESS_FS_MAKE_SOCK | 3107 - LANDLOCK_ACCESS_FS_READ_FILE | 3108 - LANDLOCK_ACCESS_FS_MAKE_FIFO, 3109 - layer1); 3110 3272 3111 - ASSERT_LE(0, ruleset_fd); 3112 - enforce_ruleset(_metadata, ruleset_fd); 3113 - ASSERT_EQ(0, close(ruleset_fd)); 3273 + enforce_fs(_metadata, 3274 + LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_EXECUTE | 3275 + LANDLOCK_ACCESS_FS_MAKE_SOCK | 3276 + LANDLOCK_ACCESS_FS_READ_FILE | 3277 + LANDLOCK_ACCESS_FS_MAKE_FIFO, 3278 + layer1); 3114 3279 3115 3280 ASSERT_EQ(-1, rename(file1_s1d2, file1_s2d1)); 3116 3281 ASSERT_EQ(EXDEV, errno); ··· 3169 3342 }, 3170 3343 {}, 3171 3344 }; 3172 - const int ruleset_fd = 3173 - create_ruleset(_metadata, rules[0].access, rules); 3174 - 3175 - ASSERT_LE(0, ruleset_fd); 3176 3345 3177 3346 ASSERT_EQ(0, unlink(file1_s1d1)); 3178 3347 ASSERT_EQ(0, unlink(file1_s1d2)); 3179 3348 ASSERT_EQ(0, unlink(file1_s1d3)); 3180 3349 ASSERT_EQ(0, unlink(file2_s1d3)); 3181 3350 3182 - enforce_ruleset(_metadata, ruleset_fd); 3183 - ASSERT_EQ(0, close(ruleset_fd)); 3351 + enforce_fs(_metadata, rules[0].access, rules); 3184 3352 3185 3353 ASSERT_EQ(0, rmdir(dir_s1d3)); 3186 3354 ASSERT_EQ(0, mkdir(dir_s1d3, 0700)); ··· 3201 3379 }, 3202 3380 {}, 3203 3381 }; 3204 - const int ruleset_fd = 3205 - create_ruleset(_metadata, rules[0].access, rules); 3206 3382 3207 - ASSERT_LE(0, ruleset_fd); 3208 - enforce_ruleset(_metadata, ruleset_fd); 3209 - ASSERT_EQ(0, close(ruleset_fd)); 3383 + enforce_fs(_metadata, rules[0].access, rules); 3210 3384 3211 3385 ASSERT_EQ(-1, unlink(file1_s1d1)); 3212 3386 ASSERT_EQ(EACCES, errno); ··· 3223 3405 }, 3224 3406 {}, 3225 3407 }; 3226 - const int ruleset_fd = create_ruleset(_metadata, access, rules); 3227 - 3228 - ASSERT_LE(0, ruleset_fd); 3229 3408 3230 3409 ASSERT_EQ(0, unlink(file1_s1d1)); 3231 3410 ASSERT_EQ(0, unlink(file2_s1d1)); ··· 3238 3423 ASSERT_EQ(0, unlink(file1_s1d3)); 3239 3424 ASSERT_EQ(0, unlink(file2_s1d3)); 3240 3425 3241 - enforce_ruleset(_metadata, ruleset_fd); 3242 - ASSERT_EQ(0, close(ruleset_fd)); 3426 + enforce_fs(_metadata, access, rules); 3243 3427 3244 3428 ASSERT_EQ(-1, mknod(file1_s1d1, mode | 0400, dev)); 3245 3429 ASSERT_EQ(EACCES, errno); ··· 3307 3493 }, 3308 3494 {}, 3309 3495 }; 3310 - const int ruleset_fd = 3311 - create_ruleset(_metadata, rules[0].access, rules); 3312 - 3313 - ASSERT_LE(0, ruleset_fd); 3314 3496 3315 3497 ASSERT_EQ(0, unlink(file1_s1d1)); 3316 3498 ASSERT_EQ(0, unlink(file2_s1d1)); ··· 3318 3508 ASSERT_EQ(0, unlink(file1_s1d3)); 3319 3509 ASSERT_EQ(0, unlink(file2_s1d3)); 3320 3510 3321 - enforce_ruleset(_metadata, ruleset_fd); 3322 - ASSERT_EQ(0, close(ruleset_fd)); 3511 + enforce_fs(_metadata, rules[0].access, rules); 3323 3512 3324 3513 ASSERT_EQ(-1, symlink("none", file1_s1d1)); 3325 3514 ASSERT_EQ(EACCES, errno); ··· 3347 3538 }, 3348 3539 {}, 3349 3540 }; 3350 - const int ruleset_fd = 3351 - create_ruleset(_metadata, rules[0].access, rules); 3352 - 3353 - ASSERT_LE(0, ruleset_fd); 3354 3541 3355 3542 ASSERT_EQ(0, unlink(file1_s1d1)); 3356 3543 ASSERT_EQ(0, unlink(file1_s1d2)); 3357 3544 ASSERT_EQ(0, unlink(file1_s1d3)); 3358 3545 3359 - enforce_ruleset(_metadata, ruleset_fd); 3360 - ASSERT_EQ(0, close(ruleset_fd)); 3546 + enforce_fs(_metadata, rules[0].access, rules); 3361 3547 3362 3548 /* Uses file_* as directory names. */ 3363 3549 ASSERT_EQ(-1, mkdir(file1_s1d1, 0700)); ··· 3383 3579 {}, 3384 3580 }; 3385 3581 int reg_fd, proc_fd; 3386 - const int ruleset_fd = create_ruleset( 3387 - _metadata, 3388 - LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE, 3389 - rules); 3390 3582 3391 - ASSERT_LE(0, ruleset_fd); 3392 - enforce_ruleset(_metadata, ruleset_fd); 3393 - ASSERT_EQ(0, close(ruleset_fd)); 3583 + enforce_fs(_metadata, 3584 + LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE, 3585 + rules); 3394 3586 3395 3587 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDWR)); 3396 3588 ASSERT_EQ(0, test_open(file1_s1d2, O_RDONLY)); ··· 3422 3622 }, 3423 3623 {}, 3424 3624 }; 3425 - /* Limits read and write access to files tied to the filesystem. */ 3426 - const int ruleset_fd = 3427 - create_ruleset(_metadata, rules[0].access, rules); 3428 3625 3429 - ASSERT_LE(0, ruleset_fd); 3430 - enforce_ruleset(_metadata, ruleset_fd); 3431 - ASSERT_EQ(0, close(ruleset_fd)); 3626 + /* Limits read and write access to files tied to the filesystem. */ 3627 + enforce_fs(_metadata, rules[0].access, rules); 3432 3628 3433 3629 /* Checks enforcement for normal files. */ 3434 3630 ASSERT_EQ(0, test_open(file1_s1d2, O_RDWR)); ··· 3514 3718 {}, 3515 3719 }; 3516 3720 3517 - const __u64 handled = LANDLOCK_ACCESS_FS_READ_FILE | 3518 - LANDLOCK_ACCESS_FS_WRITE_FILE; 3519 - int ruleset_fd; 3520 - 3521 3721 /* Enables Landlock. */ 3522 - ruleset_fd = create_ruleset(_metadata, handled, rules); 3523 - 3524 - ASSERT_LE(0, ruleset_fd); 3525 - enforce_ruleset(_metadata, ruleset_fd); 3526 - ASSERT_EQ(0, close(ruleset_fd)); 3722 + enforce_fs(_metadata, 3723 + LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE, 3724 + rules); 3527 3725 3528 3726 /* 3529 3727 * Checks read right: truncate and open with O_TRUNC work, unless the ··· 3590 3800 }, 3591 3801 {}, 3592 3802 }; 3593 - const __u64 handled = LANDLOCK_ACCESS_FS_READ_FILE | 3594 - LANDLOCK_ACCESS_FS_WRITE_FILE | 3595 - LANDLOCK_ACCESS_FS_TRUNCATE; 3596 - int ruleset_fd; 3597 3803 3598 3804 /* Enables Landlock. */ 3599 - ruleset_fd = create_ruleset(_metadata, handled, rules); 3600 - 3601 - ASSERT_LE(0, ruleset_fd); 3602 - enforce_ruleset(_metadata, ruleset_fd); 3603 - ASSERT_EQ(0, close(ruleset_fd)); 3805 + enforce_fs(_metadata, 3806 + LANDLOCK_ACCESS_FS_READ_FILE | 3807 + LANDLOCK_ACCESS_FS_WRITE_FILE | 3808 + LANDLOCK_ACCESS_FS_TRUNCATE, 3809 + rules); 3604 3810 3605 3811 /* Checks read, write and truncate rights: truncation works. */ 3606 3812 EXPECT_EQ(0, test_truncate(file_rwt)); ··· 3696 3910 }, 3697 3911 {}, 3698 3912 }; 3699 - int fd_layer0, fd_layer1, fd_layer2, fd_layer3, ruleset_fd; 3913 + int fd_layer0, fd_layer1, fd_layer2, fd_layer3; 3700 3914 3701 3915 fd_layer0 = open(path, O_WRONLY); 3702 3916 EXPECT_EQ(0, test_ftruncate(fd_layer0)); 3703 3917 3704 - ruleset_fd = create_ruleset(_metadata, handled1, layer1); 3705 - ASSERT_LE(0, ruleset_fd); 3706 - enforce_ruleset(_metadata, ruleset_fd); 3707 - ASSERT_EQ(0, close(ruleset_fd)); 3918 + enforce_fs(_metadata, handled1, layer1); 3708 3919 3709 3920 fd_layer1 = open(path, O_WRONLY); 3710 3921 EXPECT_EQ(0, test_ftruncate(fd_layer0)); 3711 3922 EXPECT_EQ(0, test_ftruncate(fd_layer1)); 3712 3923 3713 - ruleset_fd = create_ruleset(_metadata, handled2, layer2); 3714 - ASSERT_LE(0, ruleset_fd); 3715 - enforce_ruleset(_metadata, ruleset_fd); 3716 - ASSERT_EQ(0, close(ruleset_fd)); 3924 + enforce_fs(_metadata, handled2, layer2); 3717 3925 3718 3926 fd_layer2 = open(path, O_WRONLY); 3719 3927 EXPECT_EQ(0, test_ftruncate(fd_layer0)); 3720 3928 EXPECT_EQ(0, test_ftruncate(fd_layer1)); 3721 3929 EXPECT_EQ(0, test_ftruncate(fd_layer2)); 3722 3930 3723 - ruleset_fd = create_ruleset(_metadata, handled3, layer3); 3724 - ASSERT_LE(0, ruleset_fd); 3725 - enforce_ruleset(_metadata, ruleset_fd); 3726 - ASSERT_EQ(0, close(ruleset_fd)); 3931 + enforce_fs(_metadata, handled3, layer3); 3727 3932 3728 3933 fd_layer3 = open(path, O_WRONLY); 3729 3934 EXPECT_EQ(0, test_ftruncate(fd_layer0)); ··· 3806 4029 }, 3807 4030 {}, 3808 4031 }; 3809 - int fd, ruleset_fd; 4032 + int fd; 3810 4033 3811 4034 /* Enables Landlock. */ 3812 - ruleset_fd = create_ruleset(_metadata, variant->handled, rules); 3813 - ASSERT_LE(0, ruleset_fd); 3814 - enforce_ruleset(_metadata, ruleset_fd); 3815 - ASSERT_EQ(0, close(ruleset_fd)); 4035 + enforce_fs(_metadata, variant->handled, rules); 3816 4036 3817 4037 fd = open(path, O_WRONLY); 3818 4038 EXPECT_EQ(variant->expected_open_result, (fd < 0 ? errno : 0)); ··· 3844 4070 }, 3845 4071 {}, 3846 4072 }; 3847 - int fd, ruleset_fd; 4073 + int fd; 3848 4074 3849 - ruleset_fd = create_ruleset(_metadata, variant->handled, rules); 3850 - ASSERT_LE(0, ruleset_fd); 3851 - enforce_ruleset(_metadata, ruleset_fd); 3852 - ASSERT_EQ(0, close(ruleset_fd)); 4075 + enforce_fs(_metadata, variant->handled, rules); 3853 4076 3854 4077 fd = open(path, O_WRONLY); 3855 4078 ASSERT_EQ(variant->expected_open_result, (fd < 0 ? errno : 0)); ··· 3891 4120 3892 4121 TEST(memfd_ftruncate_and_ioctl) 3893 4122 { 3894 - const struct landlock_ruleset_attr attr = { 3895 - .handled_access_fs = ACCESS_ALL, 3896 - }; 3897 - int ruleset_fd, fd, i; 4123 + int fd, i; 3898 4124 3899 4125 /* 3900 4126 * We exercise the same test both with and without Landlock enabled, to ··· 3913 4145 ASSERT_EQ(0, close(fd)); 3914 4146 3915 4147 /* Enables Landlock. */ 3916 - ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0); 3917 - ASSERT_LE(0, ruleset_fd); 3918 - enforce_ruleset(_metadata, ruleset_fd); 3919 - ASSERT_EQ(0, close(ruleset_fd)); 4148 + enforce_fs(_metadata, ACCESS_ALL, NULL); 3920 4149 } 3921 4150 } 3922 4151 ··· 3928 4163 3929 4164 TEST_F_FORK(layout1, o_path_ftruncate_and_ioctl) 3930 4165 { 3931 - const struct landlock_ruleset_attr attr = { 3932 - .handled_access_fs = ACCESS_ALL, 3933 - }; 3934 - int ruleset_fd, fd; 4166 + int fd; 3935 4167 3936 4168 /* 3937 4169 * Checks that for files opened with O_PATH, both ioctl(2) and ··· 3944 4182 ASSERT_EQ(0, close(fd)); 3945 4183 3946 4184 /* Enables Landlock. */ 3947 - ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0); 3948 - ASSERT_LE(0, ruleset_fd); 3949 - enforce_ruleset(_metadata, ruleset_fd); 3950 - ASSERT_EQ(0, close(ruleset_fd)); 4185 + enforce_fs(_metadata, ACCESS_ALL, NULL); 3951 4186 3952 4187 /* 3953 4188 * Checks that after enabling Landlock, ··· 4018 4259 */ 4019 4260 TEST_F_FORK(layout1, blanket_permitted_ioctls) 4020 4261 { 4021 - const struct landlock_ruleset_attr attr = { 4022 - .handled_access_fs = LANDLOCK_ACCESS_FS_IOCTL_DEV, 4023 - }; 4024 - int ruleset_fd, fd; 4262 + int fd; 4025 4263 4026 4264 /* Enables Landlock. */ 4027 - ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0); 4028 - ASSERT_LE(0, ruleset_fd); 4029 - enforce_ruleset(_metadata, ruleset_fd); 4030 - ASSERT_EQ(0, close(ruleset_fd)); 4265 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_IOCTL_DEV, NULL); 4031 4266 4032 4267 fd = open("/dev/null", O_RDWR | O_CLOEXEC); 4033 4268 ASSERT_LE(0, fd); ··· 4074 4321 TEST_F_FORK(layout1, named_pipe_ioctl) 4075 4322 { 4076 4323 pid_t child_pid; 4077 - int fd, ruleset_fd; 4324 + int fd; 4078 4325 const char *const path = file1_s1d1; 4079 - const struct landlock_ruleset_attr attr = { 4080 - .handled_access_fs = LANDLOCK_ACCESS_FS_IOCTL_DEV, 4081 - }; 4082 4326 4083 4327 ASSERT_EQ(0, unlink(path)); 4084 4328 ASSERT_EQ(0, mkfifo(path, 0600)); 4085 4329 4086 4330 /* Enables Landlock. */ 4087 - ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0); 4088 - ASSERT_LE(0, ruleset_fd); 4089 - enforce_ruleset(_metadata, ruleset_fd); 4090 - ASSERT_EQ(0, close(ruleset_fd)); 4331 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_IOCTL_DEV, NULL); 4091 4332 4092 4333 /* The child process opens the pipe for writing. */ 4093 4334 child_pid = fork(); ··· 4104 4357 ASSERT_EQ(child_pid, waitpid(child_pid, NULL, 0)); 4105 4358 } 4106 4359 4360 + /* 4361 + * set_up_named_unix_server - Create a pathname unix socket 4362 + * 4363 + * If the socket type is not SOCK_DGRAM, also invoke listen(2). 4364 + * 4365 + * Return: The listening FD - it is the caller responsibility to close it. 4366 + */ 4367 + static int set_up_named_unix_server(struct __test_metadata *const _metadata, 4368 + int type, const char *const path) 4369 + { 4370 + int fd; 4371 + struct sockaddr_un addr = { 4372 + .sun_family = AF_UNIX, 4373 + }; 4374 + 4375 + fd = socket(AF_UNIX, type, 0); 4376 + ASSERT_LE(0, fd); 4377 + 4378 + ASSERT_LT(strlen(path), sizeof(addr.sun_path)); 4379 + strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); 4380 + 4381 + ASSERT_EQ(0, bind(fd, (struct sockaddr *)&addr, sizeof(addr))); 4382 + 4383 + if (type != SOCK_DGRAM) 4384 + ASSERT_EQ(0, listen(fd, 10 /* qlen */)); 4385 + return fd; 4386 + } 4387 + 4388 + /* 4389 + * test_connect_named_unix - connect to the given named UNIX socket 4390 + * 4391 + * Return: The errno from connect(), or 0 4392 + */ 4393 + static int test_connect_named_unix(struct __test_metadata *const _metadata, 4394 + int fd, const char *const path) 4395 + { 4396 + struct sockaddr_un addr = { 4397 + .sun_family = AF_UNIX, 4398 + }; 4399 + 4400 + ASSERT_LT(strlen(path), sizeof(addr.sun_path)); 4401 + strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); 4402 + 4403 + if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) 4404 + return errno; 4405 + return 0; 4406 + } 4407 + 4107 4408 /* For named UNIX domain sockets, no IOCTL restrictions apply. */ 4108 4409 TEST_F_FORK(layout1, named_unix_domain_socket_ioctl) 4109 4410 { 4110 4411 const char *const path = file1_s1d1; 4111 - int srv_fd, cli_fd, ruleset_fd; 4112 - struct sockaddr_un srv_un = { 4113 - .sun_family = AF_UNIX, 4114 - }; 4115 - struct sockaddr_un cli_un = { 4116 - .sun_family = AF_UNIX, 4117 - }; 4118 - const struct landlock_ruleset_attr attr = { 4119 - .handled_access_fs = LANDLOCK_ACCESS_FS_IOCTL_DEV, 4120 - }; 4412 + int srv_fd, cli_fd; 4121 4413 4122 4414 /* Sets up a server */ 4123 4415 ASSERT_EQ(0, unlink(path)); 4124 - srv_fd = socket(AF_UNIX, SOCK_STREAM, 0); 4125 - ASSERT_LE(0, srv_fd); 4126 - 4127 - strncpy(srv_un.sun_path, path, sizeof(srv_un.sun_path)); 4128 - ASSERT_EQ(0, bind(srv_fd, (struct sockaddr *)&srv_un, sizeof(srv_un))); 4129 - 4130 - ASSERT_EQ(0, listen(srv_fd, 10 /* qlen */)); 4416 + srv_fd = set_up_named_unix_server(_metadata, SOCK_STREAM, path); 4131 4417 4132 4418 /* Enables Landlock. */ 4133 - ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0); 4134 - ASSERT_LE(0, ruleset_fd); 4135 - enforce_ruleset(_metadata, ruleset_fd); 4136 - ASSERT_EQ(0, close(ruleset_fd)); 4419 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_IOCTL_DEV, NULL); 4137 4420 4138 4421 /* Sets up a client connection to it */ 4139 4422 cli_fd = socket(AF_UNIX, SOCK_STREAM, 0); 4140 4423 ASSERT_LE(0, cli_fd); 4141 4424 4142 - strncpy(cli_un.sun_path, path, sizeof(cli_un.sun_path)); 4143 - ASSERT_EQ(0, 4144 - connect(cli_fd, (struct sockaddr *)&cli_un, sizeof(cli_un))); 4425 + ASSERT_EQ(0, test_connect_named_unix(_metadata, cli_fd, path)); 4145 4426 4146 4427 /* FIONREAD and other IOCTLs should not be forbidden. */ 4147 4428 EXPECT_EQ(0, test_fionread_ioctl(cli_fd)); ··· 4236 4461 }, 4237 4462 {}, 4238 4463 }; 4239 - int file_fd, ruleset_fd; 4464 + int fd; 4240 4465 4241 4466 /* Enables Landlock. */ 4242 - ruleset_fd = create_ruleset(_metadata, variant->handled, rules); 4243 - ASSERT_LE(0, ruleset_fd); 4244 - enforce_ruleset(_metadata, ruleset_fd); 4245 - ASSERT_EQ(0, close(ruleset_fd)); 4467 + enforce_fs(_metadata, variant->handled, rules); 4246 4468 4247 - file_fd = open("/dev/zero", variant->open_mode); 4248 - ASSERT_LE(0, file_fd); 4469 + fd = open("/dev/zero", variant->open_mode); 4470 + ASSERT_LE(0, fd); 4249 4471 4250 4472 /* Checks that IOCTL commands return the expected errors. */ 4251 - EXPECT_EQ(variant->expected_fionread_result, 4252 - test_fionread_ioctl(file_fd)); 4473 + EXPECT_EQ(variant->expected_fionread_result, test_fionread_ioctl(fd)); 4253 4474 4254 4475 /* Checks that unrestrictable commands are unrestricted. */ 4255 - EXPECT_EQ(0, ioctl(file_fd, FIOCLEX)); 4256 - EXPECT_EQ(0, ioctl(file_fd, FIONCLEX)); 4257 - EXPECT_EQ(0, ioctl(file_fd, FIONBIO, &flag)); 4258 - EXPECT_EQ(0, ioctl(file_fd, FIOASYNC, &flag)); 4259 - EXPECT_EQ(0, ioctl(file_fd, FIGETBSZ, &flag)); 4476 + EXPECT_EQ(0, ioctl(fd, FIOCLEX)); 4477 + EXPECT_EQ(0, ioctl(fd, FIONCLEX)); 4478 + EXPECT_EQ(0, ioctl(fd, FIONBIO, &flag)); 4479 + EXPECT_EQ(0, ioctl(fd, FIOASYNC, &flag)); 4480 + EXPECT_EQ(0, ioctl(fd, FIGETBSZ, &flag)); 4260 4481 4261 - ASSERT_EQ(0, close(file_fd)); 4482 + ASSERT_EQ(0, close(fd)); 4262 4483 } 4263 4484 4264 4485 TEST_F_FORK(ioctl, handle_dir_access_dir) ··· 4267 4496 }, 4268 4497 {}, 4269 4498 }; 4270 - int dir_fd, ruleset_fd; 4499 + int dir_fd; 4271 4500 4272 4501 /* Enables Landlock. */ 4273 - ruleset_fd = create_ruleset(_metadata, variant->handled, rules); 4274 - ASSERT_LE(0, ruleset_fd); 4275 - enforce_ruleset(_metadata, ruleset_fd); 4276 - ASSERT_EQ(0, close(ruleset_fd)); 4502 + enforce_fs(_metadata, variant->handled, rules); 4277 4503 4278 4504 /* 4279 4505 * Ignore variant->open_mode for this test, as we intend to open a ··· 4309 4541 }, 4310 4542 {}, 4311 4543 }; 4312 - int file_fd, ruleset_fd; 4544 + int fd; 4313 4545 4314 4546 /* Enables Landlock. */ 4315 - ruleset_fd = create_ruleset(_metadata, variant->handled, rules); 4316 - ASSERT_LE(0, ruleset_fd); 4317 - enforce_ruleset(_metadata, ruleset_fd); 4318 - ASSERT_EQ(0, close(ruleset_fd)); 4547 + enforce_fs(_metadata, variant->handled, rules); 4319 4548 4320 - file_fd = open("/dev/zero", variant->open_mode); 4321 - ASSERT_LE(0, file_fd) 4549 + fd = open("/dev/zero", variant->open_mode); 4550 + ASSERT_LE(0, fd) 4322 4551 { 4323 4552 TH_LOG("Failed to open /dev/zero: %s", strerror(errno)); 4324 4553 } 4325 4554 4326 4555 /* Checks that IOCTL commands return the expected errors. */ 4327 - EXPECT_EQ(variant->expected_fionread_result, 4328 - test_fionread_ioctl(file_fd)); 4556 + EXPECT_EQ(variant->expected_fionread_result, test_fionread_ioctl(fd)); 4329 4557 4330 4558 /* Checks that unrestrictable commands are unrestricted. */ 4331 - EXPECT_EQ(0, ioctl(file_fd, FIOCLEX)); 4332 - EXPECT_EQ(0, ioctl(file_fd, FIONCLEX)); 4333 - EXPECT_EQ(0, ioctl(file_fd, FIONBIO, &flag)); 4334 - EXPECT_EQ(0, ioctl(file_fd, FIOASYNC, &flag)); 4335 - EXPECT_EQ(0, ioctl(file_fd, FIGETBSZ, &flag)); 4559 + EXPECT_EQ(0, ioctl(fd, FIOCLEX)); 4560 + EXPECT_EQ(0, ioctl(fd, FIONCLEX)); 4561 + EXPECT_EQ(0, ioctl(fd, FIONBIO, &flag)); 4562 + EXPECT_EQ(0, ioctl(fd, FIOASYNC, &flag)); 4563 + EXPECT_EQ(0, ioctl(fd, FIGETBSZ, &flag)); 4336 4564 4337 - ASSERT_EQ(0, close(file_fd)); 4565 + ASSERT_EQ(0, close(fd)); 4566 + } 4567 + 4568 + /* 4569 + * test_sendto_named_unix - sendto to the given named UNIX socket 4570 + * 4571 + * sendto() is equivalent to sendmsg() in this respect. 4572 + * 4573 + * Return: The errno from sendto(), or 0 4574 + */ 4575 + static int test_sendto_named_unix(struct __test_metadata *const _metadata, 4576 + int fd, const char *const path) 4577 + { 4578 + static const char buf[] = "dummy"; 4579 + struct sockaddr_un addr = { 4580 + .sun_family = AF_UNIX, 4581 + }; 4582 + 4583 + ASSERT_LT(strlen(path), sizeof(addr.sun_path)); 4584 + strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); 4585 + 4586 + if (sendto(fd, buf, sizeof(buf), 0, (struct sockaddr *)&addr, 4587 + sizeof(addr)) == -1) 4588 + return errno; 4589 + return 0; 4590 + } 4591 + 4592 + /* clang-format off */ 4593 + FIXTURE(scoped_domains) {}; 4594 + /* clang-format on */ 4595 + 4596 + #include "scoped_base_variants.h" 4597 + 4598 + FIXTURE_SETUP(scoped_domains) 4599 + { 4600 + drop_caps(_metadata); 4601 + }; 4602 + 4603 + FIXTURE_TEARDOWN(scoped_domains) 4604 + { 4605 + } 4606 + 4607 + /* 4608 + * Flags for test_connect_to_parent and test_connect_to_child: 4609 + * 4610 + * USE_SENDTO: Use sendto() instead of connect() (for SOCK_DGRAM only) 4611 + * ENFORCE_ALL: Enforce a Landlock domain even when the variant says 4612 + * we shouldn't. We enforce a domain where the path is allow-listed, 4613 + * and expect the behavior to be the same as if none was used. 4614 + */ 4615 + #define USE_SENDTO (1 << 0) 4616 + #define ENFORCE_ALL (1 << 1) 4617 + 4618 + static void test_connect_to_parent(struct __test_metadata *const _metadata, 4619 + const FIXTURE_VARIANT(scoped_domains) * 4620 + variant, 4621 + int sock_type, int flags) 4622 + { 4623 + const char *const path = "sock"; 4624 + const struct rule rules[] = { 4625 + { 4626 + .path = ".", 4627 + .access = LANDLOCK_ACCESS_FS_RESOLVE_UNIX, 4628 + }, 4629 + {}, 4630 + }; 4631 + int cli_fd, srv_fd, res, status; 4632 + pid_t child_pid; 4633 + int readiness_pipe[2]; 4634 + char buf[1]; 4635 + 4636 + if (variant->domain_both) 4637 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_RESOLVE_UNIX, NULL); 4638 + else if (flags & ENFORCE_ALL) 4639 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_RESOLVE_UNIX, rules); 4640 + 4641 + unlink(path); 4642 + ASSERT_EQ(0, pipe2(readiness_pipe, O_CLOEXEC)); 4643 + 4644 + child_pid = fork(); 4645 + ASSERT_LE(0, child_pid); 4646 + 4647 + if (child_pid == 0) { 4648 + if (variant->domain_child) 4649 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_RESOLVE_UNIX, 4650 + NULL); 4651 + else if (flags & ENFORCE_ALL) 4652 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_RESOLVE_UNIX, 4653 + rules); 4654 + 4655 + /* Wait for server to be available. */ 4656 + EXPECT_EQ(0, close(readiness_pipe[1])); 4657 + EXPECT_EQ(1, read(readiness_pipe[0], &buf, 1)); 4658 + EXPECT_EQ(0, close(readiness_pipe[0])); 4659 + 4660 + /* Talk to server. */ 4661 + cli_fd = socket(AF_UNIX, sock_type, 0); 4662 + ASSERT_LE(0, cli_fd); 4663 + 4664 + if (flags & USE_SENDTO) 4665 + res = test_sendto_named_unix(_metadata, cli_fd, path); 4666 + else 4667 + res = test_connect_named_unix(_metadata, cli_fd, path); 4668 + 4669 + EXPECT_EQ(variant->domain_child ? EACCES : 0, res); 4670 + 4671 + /* Clean up. */ 4672 + EXPECT_EQ(0, close(cli_fd)); 4673 + 4674 + _exit(_metadata->exit_code); 4675 + return; 4676 + } 4677 + 4678 + if (variant->domain_parent) 4679 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_RESOLVE_UNIX, NULL); 4680 + else if (flags & ENFORCE_ALL) 4681 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_RESOLVE_UNIX, rules); 4682 + 4683 + srv_fd = set_up_named_unix_server(_metadata, sock_type, path); 4684 + 4685 + /* Tell the child that it can connect. */ 4686 + EXPECT_EQ(0, close(readiness_pipe[0])); 4687 + EXPECT_EQ(sizeof(buf), write(readiness_pipe[1], buf, sizeof(buf))); 4688 + EXPECT_EQ(0, close(readiness_pipe[1])); 4689 + 4690 + /* Wait for child. */ 4691 + ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0)); 4692 + EXPECT_EQ(1, WIFEXITED(status)); 4693 + EXPECT_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); 4694 + 4695 + /* Clean up. */ 4696 + EXPECT_EQ(0, close(srv_fd)); 4697 + EXPECT_EQ(0, unlink(path)); 4698 + } 4699 + 4700 + static void test_connect_to_child(struct __test_metadata *const _metadata, 4701 + const FIXTURE_VARIANT(scoped_domains) * 4702 + variant, 4703 + int sock_type, int flags) 4704 + { 4705 + const char *const path = "sock"; 4706 + const struct rule rules[] = { 4707 + { 4708 + .path = ".", 4709 + .access = LANDLOCK_ACCESS_FS_RESOLVE_UNIX, 4710 + }, 4711 + {}, 4712 + }; 4713 + int readiness_pipe[2]; 4714 + int shutdown_pipe[2]; 4715 + int cli_fd, srv_fd, res, status; 4716 + pid_t child_pid; 4717 + char buf[1]; 4718 + 4719 + if (variant->domain_both) 4720 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_RESOLVE_UNIX, NULL); 4721 + else if (flags & ENFORCE_ALL) 4722 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_RESOLVE_UNIX, rules); 4723 + 4724 + unlink(path); 4725 + ASSERT_EQ(0, pipe2(readiness_pipe, O_CLOEXEC)); 4726 + ASSERT_EQ(0, pipe2(shutdown_pipe, O_CLOEXEC)); 4727 + 4728 + child_pid = fork(); 4729 + ASSERT_LE(0, child_pid); 4730 + 4731 + if (child_pid == 0) { 4732 + if (variant->domain_child) 4733 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_RESOLVE_UNIX, 4734 + NULL); 4735 + else if (flags & ENFORCE_ALL) 4736 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_RESOLVE_UNIX, 4737 + rules); 4738 + 4739 + srv_fd = set_up_named_unix_server(_metadata, sock_type, path); 4740 + 4741 + /* Tell the parent that it can connect. */ 4742 + EXPECT_EQ(0, close(readiness_pipe[0])); 4743 + EXPECT_EQ(sizeof(buf), 4744 + write(readiness_pipe[1], buf, sizeof(buf))); 4745 + EXPECT_EQ(0, close(readiness_pipe[1])); 4746 + 4747 + /* Wait until it is time to shut down. */ 4748 + EXPECT_EQ(0, close(shutdown_pipe[1])); 4749 + EXPECT_EQ(1, read(shutdown_pipe[0], &buf, 1)); 4750 + EXPECT_EQ(0, close(shutdown_pipe[0])); 4751 + 4752 + /* Cleanup */ 4753 + EXPECT_EQ(0, close(srv_fd)); 4754 + EXPECT_EQ(0, unlink(path)); 4755 + 4756 + _exit(_metadata->exit_code); 4757 + return; 4758 + } 4759 + 4760 + if (variant->domain_parent) 4761 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_RESOLVE_UNIX, NULL); 4762 + else if (flags & ENFORCE_ALL) 4763 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_RESOLVE_UNIX, rules); 4764 + 4765 + /* Wait for server to be available. */ 4766 + EXPECT_EQ(0, close(readiness_pipe[1])); 4767 + EXPECT_EQ(1, read(readiness_pipe[0], &buf, 1)); 4768 + EXPECT_EQ(0, close(readiness_pipe[0])); 4769 + 4770 + /* Talk to server. */ 4771 + cli_fd = socket(AF_UNIX, sock_type, 0); 4772 + ASSERT_LE(0, cli_fd); 4773 + 4774 + if (flags & USE_SENDTO) 4775 + res = test_sendto_named_unix(_metadata, cli_fd, path); 4776 + else 4777 + res = test_connect_named_unix(_metadata, cli_fd, path); 4778 + 4779 + EXPECT_EQ(variant->domain_parent ? EACCES : 0, res); 4780 + 4781 + /* Clean up. */ 4782 + EXPECT_EQ(0, close(cli_fd)); 4783 + 4784 + /* Tell the server to shut down. */ 4785 + EXPECT_EQ(0, close(shutdown_pipe[0])); 4786 + EXPECT_EQ(sizeof(buf), write(shutdown_pipe[1], buf, sizeof(buf))); 4787 + EXPECT_EQ(0, close(shutdown_pipe[1])); 4788 + 4789 + /* Wait for child. */ 4790 + ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0)); 4791 + EXPECT_EQ(1, WIFEXITED(status)); 4792 + EXPECT_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); 4793 + } 4794 + 4795 + TEST_F(scoped_domains, unix_stream_connect_to_parent) 4796 + { 4797 + test_connect_to_parent(_metadata, variant, SOCK_STREAM, 0); 4798 + } 4799 + 4800 + TEST_F(scoped_domains, unix_dgram_connect_to_parent) 4801 + { 4802 + test_connect_to_parent(_metadata, variant, SOCK_DGRAM, 0); 4803 + } 4804 + 4805 + TEST_F(scoped_domains, unix_dgram_sendmsg_to_parent) 4806 + { 4807 + test_connect_to_parent(_metadata, variant, SOCK_DGRAM, USE_SENDTO); 4808 + } 4809 + 4810 + TEST_F(scoped_domains, unix_seqpacket_connect_to_parent) 4811 + { 4812 + test_connect_to_parent(_metadata, variant, SOCK_SEQPACKET, 0); 4813 + } 4814 + 4815 + TEST_F(scoped_domains, unix_stream_connect_to_parent_full) 4816 + { 4817 + test_connect_to_parent(_metadata, variant, SOCK_STREAM, ENFORCE_ALL); 4818 + } 4819 + 4820 + TEST_F(scoped_domains, unix_dgram_connect_to_parent_full) 4821 + { 4822 + test_connect_to_parent(_metadata, variant, SOCK_DGRAM, ENFORCE_ALL); 4823 + } 4824 + 4825 + TEST_F(scoped_domains, unix_dgram_sendmsg_to_parent_full) 4826 + { 4827 + test_connect_to_parent(_metadata, variant, SOCK_DGRAM, 4828 + USE_SENDTO | ENFORCE_ALL); 4829 + } 4830 + 4831 + TEST_F(scoped_domains, unix_seqpacket_connect_to_parent_full) 4832 + { 4833 + test_connect_to_parent(_metadata, variant, SOCK_SEQPACKET, ENFORCE_ALL); 4834 + } 4835 + 4836 + TEST_F(scoped_domains, unix_stream_connect_to_child) 4837 + { 4838 + test_connect_to_child(_metadata, variant, SOCK_STREAM, 0); 4839 + } 4840 + 4841 + TEST_F(scoped_domains, unix_dgram_connect_to_child) 4842 + { 4843 + test_connect_to_child(_metadata, variant, SOCK_DGRAM, 0); 4844 + } 4845 + 4846 + TEST_F(scoped_domains, unix_dgram_sendmsg_to_child) 4847 + { 4848 + test_connect_to_child(_metadata, variant, SOCK_DGRAM, USE_SENDTO); 4849 + } 4850 + 4851 + TEST_F(scoped_domains, unix_seqpacket_connect_to_child) 4852 + { 4853 + test_connect_to_child(_metadata, variant, SOCK_SEQPACKET, 0); 4854 + } 4855 + 4856 + TEST_F(scoped_domains, unix_stream_connect_to_child_full) 4857 + { 4858 + test_connect_to_child(_metadata, variant, SOCK_STREAM, ENFORCE_ALL); 4859 + } 4860 + 4861 + TEST_F(scoped_domains, unix_dgram_connect_to_child_full) 4862 + { 4863 + test_connect_to_child(_metadata, variant, SOCK_DGRAM, ENFORCE_ALL); 4864 + } 4865 + 4866 + TEST_F(scoped_domains, unix_dgram_sendmsg_to_child_full) 4867 + { 4868 + test_connect_to_child(_metadata, variant, SOCK_DGRAM, 4869 + USE_SENDTO | ENFORCE_ALL); 4870 + } 4871 + 4872 + TEST_F(scoped_domains, unix_seqpacket_connect_to_child_full) 4873 + { 4874 + test_connect_to_child(_metadata, variant, SOCK_SEQPACKET, ENFORCE_ALL); 4875 + } 4876 + 4877 + #undef USE_SENDTO 4878 + #undef ENFORCE_ALL 4879 + 4880 + static void read_core_pattern(struct __test_metadata *const _metadata, 4881 + char *buf, size_t buf_size) 4882 + { 4883 + int fd; 4884 + ssize_t ret; 4885 + 4886 + fd = open("/proc/sys/kernel/core_pattern", O_RDONLY | O_CLOEXEC); 4887 + ASSERT_LE(0, fd); 4888 + 4889 + ret = read(fd, buf, buf_size - 1); 4890 + ASSERT_LE(0, ret); 4891 + EXPECT_EQ(0, close(fd)); 4892 + 4893 + buf[ret] = '\0'; 4894 + } 4895 + 4896 + static void set_core_pattern(struct __test_metadata *const _metadata, 4897 + const char *pattern) 4898 + { 4899 + int fd; 4900 + size_t len = strlen(pattern); 4901 + 4902 + /* 4903 + * Writing to /proc/sys/kernel/core_pattern requires EUID 0 because 4904 + * sysctl_perm() checks that, ignoring capabilities like 4905 + * CAP_SYS_ADMIN or CAP_DAC_OVERRIDE. 4906 + * 4907 + * Switching EUID clears the dumpable flag, which must be restored 4908 + * afterwards to allow coredumps. 4909 + */ 4910 + set_cap(_metadata, CAP_SETUID); 4911 + ASSERT_EQ(0, seteuid(0)); 4912 + clear_cap(_metadata, CAP_SETUID); 4913 + 4914 + fd = open("/proc/sys/kernel/core_pattern", O_WRONLY | O_CLOEXEC); 4915 + ASSERT_LE(0, fd) 4916 + { 4917 + TH_LOG("Failed to open core_pattern for writing: %s", 4918 + strerror(errno)); 4919 + } 4920 + 4921 + ASSERT_EQ(len, write(fd, pattern, len)); 4922 + EXPECT_EQ(0, close(fd)); 4923 + 4924 + set_cap(_metadata, CAP_SETUID); 4925 + ASSERT_EQ(0, seteuid(getuid())); 4926 + clear_cap(_metadata, CAP_SETUID); 4927 + 4928 + /* Restore dumpable flag cleared by seteuid(). */ 4929 + ASSERT_EQ(0, prctl(PR_SET_DUMPABLE, 1, 0, 0, 0)); 4930 + } 4931 + 4932 + FIXTURE(coredump) 4933 + { 4934 + char original_core_pattern[256]; 4935 + }; 4936 + 4937 + FIXTURE_SETUP(coredump) 4938 + { 4939 + disable_caps(_metadata); 4940 + read_core_pattern(_metadata, self->original_core_pattern, 4941 + sizeof(self->original_core_pattern)); 4942 + } 4943 + 4944 + FIXTURE_TEARDOWN_PARENT(coredump) 4945 + { 4946 + set_core_pattern(_metadata, self->original_core_pattern); 4947 + } 4948 + 4949 + /* 4950 + * Test that even when a process is restricted with 4951 + * LANDLOCK_ACCESS_FS_RESOLVE_UNIX, the kernel can still initiate a connection 4952 + * to the coredump socket on the processes' behalf. 4953 + */ 4954 + TEST_F_FORK(coredump, socket_not_restricted) 4955 + { 4956 + static const char core_pattern[] = "@/tmp/landlock_coredump_test.sock"; 4957 + const char *const sock_path = core_pattern + 1; 4958 + int srv_fd, conn_fd, status; 4959 + pid_t child_pid; 4960 + struct ucred cred; 4961 + socklen_t cred_len = sizeof(cred); 4962 + char buf[4096]; 4963 + 4964 + /* Set up the coredump server socket. */ 4965 + unlink(sock_path); 4966 + srv_fd = set_up_named_unix_server(_metadata, SOCK_STREAM, sock_path); 4967 + 4968 + /* Point coredumps at our socket. */ 4969 + set_core_pattern(_metadata, core_pattern); 4970 + 4971 + /* Restrict LANDLOCK_ACCESS_FS_RESOLVE_UNIX. */ 4972 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_RESOLVE_UNIX, NULL); 4973 + 4974 + /* Fork a child that crashes. */ 4975 + child_pid = fork(); 4976 + ASSERT_LE(0, child_pid); 4977 + if (child_pid == 0) { 4978 + struct rlimit rl = { 4979 + .rlim_cur = RLIM_INFINITY, 4980 + .rlim_max = RLIM_INFINITY, 4981 + }; 4982 + 4983 + ASSERT_EQ(0, setrlimit(RLIMIT_CORE, &rl)); 4984 + 4985 + /* Crash on purpose. */ 4986 + kill(getpid(), SIGSEGV); 4987 + _exit(1); 4988 + } 4989 + 4990 + /* 4991 + * Accept the coredump connection. If Landlock incorrectly denies the 4992 + * kernel's coredump connect, accept() will block forever, so the test 4993 + * would time out. 4994 + */ 4995 + conn_fd = accept(srv_fd, NULL, NULL); 4996 + ASSERT_LE(0, conn_fd); 4997 + 4998 + /* Check that the connection came from the crashing child. */ 4999 + ASSERT_EQ(0, getsockopt(conn_fd, SOL_SOCKET, SO_PEERCRED, &cred, 5000 + &cred_len)); 5001 + EXPECT_EQ(child_pid, cred.pid); 5002 + 5003 + /* Drain the coredump data so the kernel can finish. */ 5004 + while (read(conn_fd, buf, sizeof(buf)) > 0) 5005 + ; 5006 + 5007 + EXPECT_EQ(0, close(conn_fd)); 5008 + 5009 + /* Wait for the child and verify it coredumped. */ 5010 + ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0)); 5011 + ASSERT_TRUE(WIFSIGNALED(status)); 5012 + ASSERT_TRUE(WCOREDUMP(status)); 5013 + 5014 + EXPECT_EQ(0, close(srv_fd)); 5015 + EXPECT_EQ(0, unlink(sock_path)); 4338 5016 } 4339 5017 4340 5018 /* clang-format off */ ··· 4924 4710 }, 4925 4711 {}, 4926 4712 }; 4927 - int ruleset_fd; 4928 4713 4929 4714 /* Sets rules for the parent directories. */ 4930 - ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_parent); 4931 - ASSERT_LE(0, ruleset_fd); 4932 - enforce_ruleset(_metadata, ruleset_fd); 4933 - ASSERT_EQ(0, close(ruleset_fd)); 4715 + enforce_fs(_metadata, ACCESS_RW, layer1_parent); 4934 4716 4935 4717 /* Checks source hierarchy. */ 4936 4718 ASSERT_EQ(0, test_open(file1_s1d1, O_RDONLY)); ··· 4945 4735 ASSERT_EQ(0, test_open(dir_s2d2, O_RDONLY | O_DIRECTORY)); 4946 4736 4947 4737 /* Sets rules for the mount points. */ 4948 - ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_mount_point); 4949 - ASSERT_LE(0, ruleset_fd); 4950 - enforce_ruleset(_metadata, ruleset_fd); 4951 - ASSERT_EQ(0, close(ruleset_fd)); 4738 + enforce_fs(_metadata, ACCESS_RW, layer2_mount_point); 4952 4739 4953 4740 /* Checks source hierarchy. */ 4954 4741 ASSERT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); ··· 4966 4759 ASSERT_EQ(0, test_open(bind_dir_s1d3, O_RDONLY | O_DIRECTORY)); 4967 4760 4968 4761 /* Sets a (shared) rule only on the source. */ 4969 - ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer3_source); 4970 - ASSERT_LE(0, ruleset_fd); 4971 - enforce_ruleset(_metadata, ruleset_fd); 4972 - ASSERT_EQ(0, close(ruleset_fd)); 4762 + enforce_fs(_metadata, ACCESS_RW, layer3_source); 4973 4763 4974 4764 /* Checks source hierarchy. */ 4975 4765 ASSERT_EQ(EACCES, test_open(file1_s1d2, O_RDONLY)); ··· 4987 4783 ASSERT_EQ(EACCES, test_open(bind_dir_s1d3, O_RDONLY | O_DIRECTORY)); 4988 4784 4989 4785 /* Sets a (shared) rule only on the destination. */ 4990 - ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer4_destination); 4991 - ASSERT_LE(0, ruleset_fd); 4992 - enforce_ruleset(_metadata, ruleset_fd); 4993 - ASSERT_EQ(0, close(ruleset_fd)); 4786 + enforce_fs(_metadata, ACCESS_RW, layer4_destination); 4994 4787 4995 4788 /* Checks source hierarchy. */ 4996 4789 ASSERT_EQ(EACCES, test_open(file1_s1d3, O_RDONLY)); ··· 5012 4811 }, 5013 4812 {}, 5014 4813 }; 5015 - int ruleset_fd = create_ruleset( 5016 - _metadata, 5017 - LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_EXECUTE, layer1); 5018 4814 5019 - ASSERT_LE(0, ruleset_fd); 5020 - enforce_ruleset(_metadata, ruleset_fd); 5021 - ASSERT_EQ(0, close(ruleset_fd)); 4815 + enforce_fs(_metadata, 4816 + LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_EXECUTE, 4817 + layer1); 5022 4818 5023 4819 /* Checks basic denied move. */ 5024 4820 ASSERT_EQ(-1, rename(file1_s1d1, file1_s1d2)); ··· 5071 4873 int ruleset_fd_l3 = 5072 4874 create_ruleset(_metadata, ACCESS_RW, layer3_only_s1d2); 5073 4875 int bind_s1d3_fd; 5074 - 5075 - ASSERT_LE(0, ruleset_fd_l1); 5076 - ASSERT_LE(0, ruleset_fd_l2); 5077 - ASSERT_LE(0, ruleset_fd_l3); 5078 4876 5079 4877 enforce_ruleset(_metadata, ruleset_fd_l1); 5080 4878 EXPECT_EQ(0, close(ruleset_fd_l1)); ··· 5175 4981 ruleset_fd_l1 = create_ruleset(_metadata, ACCESS_ALL, layer1); 5176 4982 ruleset_fd_l2 = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE, 5177 4983 layer2_only_s1d2); 5178 - ASSERT_LE(0, ruleset_fd_l1); 5179 - ASSERT_LE(0, ruleset_fd_l2); 5180 4984 5181 4985 enforce_ruleset(_metadata, ruleset_fd_l1); 5182 4986 EXPECT_EQ(0, close(ruleset_fd_l1)); ··· 5320 5128 }, 5321 5129 {} 5322 5130 }; 5323 - int ruleset_fd, bind_s1d3_fd; 5131 + int bind_s1d3_fd; 5324 5132 5325 5133 /* Removes unneeded files created by layout1, otherwise it will EEXIST. */ 5326 5134 ASSERT_EQ(0, unlink(file1_s1d2)); ··· 5343 5151 TH_LOG("Failed to create %s: %s", dir_s4d2, strerror(errno)); 5344 5152 } 5345 5153 5346 - ruleset_fd = create_ruleset(_metadata, ACCESS_ALL, layer1); 5347 - ASSERT_LE(0, ruleset_fd); 5348 - enforce_ruleset(_metadata, ruleset_fd); 5349 - EXPECT_EQ(0, close(ruleset_fd)); 5154 + enforce_fs(_metadata, ACCESS_ALL, layer1); 5350 5155 5351 5156 /* From disconnected to connected. */ 5352 5157 ASSERT_EQ(0, linkat(bind_s1d3_fd, file1_name, AT_FDCWD, file1_s2d2, 0)) ··· 5881 5692 int ruleset_fd, s1d41_bind_fd, s1d42_bind_fd; 5882 5693 5883 5694 ruleset_fd = create_ruleset(_metadata, handled_access, rules); 5884 - ASSERT_LE(0, ruleset_fd); 5885 5695 5886 5696 /* Adds rule for the covered directory. */ 5887 5697 if (variant->allowed_s2d2) { ··· 6813 6625 }, 6814 6626 {}, 6815 6627 }; 6816 - int ruleset_fd; 6817 6628 size_t i; 6818 6629 const char *path_entry; 6819 6630 ··· 6820 6633 SKIP(return, "overlayfs is not supported (test)"); 6821 6634 6822 6635 /* Sets rules on base directories (i.e. outside overlay scope). */ 6823 - ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_base); 6824 - ASSERT_LE(0, ruleset_fd); 6825 - enforce_ruleset(_metadata, ruleset_fd); 6826 - ASSERT_EQ(0, close(ruleset_fd)); 6636 + enforce_fs(_metadata, ACCESS_RW, layer1_base); 6827 6637 6828 6638 /* Checks lower layer. */ 6829 6639 for_each_path(lower_base_files, path_entry, i) { ··· 6865 6681 } 6866 6682 6867 6683 /* Sets rules on data directories (i.e. inside overlay scope). */ 6868 - ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer2_data); 6869 - ASSERT_LE(0, ruleset_fd); 6870 - enforce_ruleset(_metadata, ruleset_fd); 6871 - ASSERT_EQ(0, close(ruleset_fd)); 6684 + enforce_fs(_metadata, ACCESS_RW, layer2_data); 6872 6685 6873 6686 /* Checks merge. */ 6874 6687 for_each_path(merge_base_files, path_entry, i) { ··· 6879 6698 } 6880 6699 6881 6700 /* Same checks with tighter rules. */ 6882 - ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer3_subdirs); 6883 - ASSERT_LE(0, ruleset_fd); 6884 - enforce_ruleset(_metadata, ruleset_fd); 6885 - ASSERT_EQ(0, close(ruleset_fd)); 6701 + enforce_fs(_metadata, ACCESS_RW, layer3_subdirs); 6886 6702 6887 6703 /* Checks changes for lower layer. */ 6888 6704 for_each_path(lower_base_files, path_entry, i) { ··· 6901 6723 } 6902 6724 6903 6725 /* Sets rules directly on overlayed files. */ 6904 - ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer4_files); 6905 - ASSERT_LE(0, ruleset_fd); 6906 - enforce_ruleset(_metadata, ruleset_fd); 6907 - ASSERT_EQ(0, close(ruleset_fd)); 6726 + enforce_fs(_metadata, ACCESS_RW, layer4_files); 6908 6727 6909 6728 /* Checks unchanged accesses on lower layer. */ 6910 6729 for_each_path(lower_sub_files, path_entry, i) { ··· 6926 6751 } 6927 6752 6928 6753 /* Only allowes access to the merge hierarchy. */ 6929 - ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer5_merge_only); 6930 - ASSERT_LE(0, ruleset_fd); 6931 - enforce_ruleset(_metadata, ruleset_fd); 6932 - ASSERT_EQ(0, close(ruleset_fd)); 6754 + enforce_fs(_metadata, ACCESS_RW, layer5_merge_only); 6933 6755 6934 6756 /* Checks new accesses on lower layer. */ 6935 6757 for_each_path(lower_sub_files, path_entry, i) { ··· 7112 6940 }, 7113 6941 {}, 7114 6942 }; 7115 - const struct landlock_ruleset_attr layer2_deny_everything_attr = { 7116 - .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE, 7117 - }; 7118 6943 const char *const dev_null_path = "/dev/null"; 7119 - int ruleset_fd; 7120 6944 7121 6945 if (self->skip_test) 7122 6946 SKIP(return, "this filesystem is not supported (test)"); ··· 7121 6953 EXPECT_EQ(0, test_open(dev_null_path, O_RDONLY | O_CLOEXEC)); 7122 6954 EXPECT_EQ(0, test_open(variant->file_path, O_RDONLY | O_CLOEXEC)); 7123 6955 7124 - ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE, 7125 - layer1_allow_read_file); 7126 - EXPECT_LE(0, ruleset_fd); 7127 - enforce_ruleset(_metadata, ruleset_fd); 7128 - EXPECT_EQ(0, close(ruleset_fd)); 6956 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_READ_FILE, 6957 + layer1_allow_read_file); 7129 6958 7130 6959 EXPECT_EQ(EACCES, test_open(dev_null_path, O_RDONLY | O_CLOEXEC)); 7131 6960 EXPECT_EQ(0, test_open(variant->file_path, O_RDONLY | O_CLOEXEC)); 7132 6961 7133 6962 /* Forbids directory reading. */ 7134 - ruleset_fd = 7135 - landlock_create_ruleset(&layer2_deny_everything_attr, 7136 - sizeof(layer2_deny_everything_attr), 0); 7137 - EXPECT_LE(0, ruleset_fd); 7138 - enforce_ruleset(_metadata, ruleset_fd); 7139 - EXPECT_EQ(0, close(ruleset_fd)); 6963 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_READ_FILE, NULL); 7140 6964 7141 6965 /* Checks with Landlock and forbidden access. */ 7142 6966 EXPECT_EQ(EACCES, test_open(dev_null_path, O_RDONLY | O_CLOEXEC)); ··· 7190 7030 7191 7031 ruleset_fd = 7192 7032 create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_DIR, layer1); 7193 - ASSERT_LE(0, ruleset_fd); 7194 7033 7195 7034 /* Unmount the filesystem while it is being used by a ruleset. */ 7196 7035 set_cap(_metadata, CAP_SYS_ADMIN); ··· 7296 7137 test_execute(_metadata, 0, file1_s1d1); 7297 7138 test_check_exec(_metadata, 0, file1_s1d1); 7298 7139 7299 - drop_access_rights(_metadata, 7300 - &(struct landlock_ruleset_attr){ 7301 - .handled_access_fs = 7302 - LANDLOCK_ACCESS_FS_EXECUTE, 7303 - }); 7140 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_EXECUTE, NULL); 7304 7141 7305 7142 test_execute(_metadata, EACCES, file1_s1d1); 7306 7143 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.execute", ··· 7315 7160 * only the blocked ones are logged. 7316 7161 */ 7317 7162 7318 - /* clang-format off */ 7319 - static const __u64 access_fs_16 = 7320 - LANDLOCK_ACCESS_FS_EXECUTE | 7321 - LANDLOCK_ACCESS_FS_WRITE_FILE | 7322 - LANDLOCK_ACCESS_FS_READ_FILE | 7323 - LANDLOCK_ACCESS_FS_READ_DIR | 7324 - LANDLOCK_ACCESS_FS_REMOVE_DIR | 7325 - LANDLOCK_ACCESS_FS_REMOVE_FILE | 7326 - LANDLOCK_ACCESS_FS_MAKE_CHAR | 7327 - LANDLOCK_ACCESS_FS_MAKE_DIR | 7328 - LANDLOCK_ACCESS_FS_MAKE_REG | 7329 - LANDLOCK_ACCESS_FS_MAKE_SOCK | 7330 - LANDLOCK_ACCESS_FS_MAKE_FIFO | 7331 - LANDLOCK_ACCESS_FS_MAKE_BLOCK | 7332 - LANDLOCK_ACCESS_FS_MAKE_SYM | 7333 - LANDLOCK_ACCESS_FS_REFER | 7334 - LANDLOCK_ACCESS_FS_TRUNCATE | 7335 - LANDLOCK_ACCESS_FS_IOCTL_DEV; 7336 - /* clang-format on */ 7337 - 7338 7163 TEST_F(audit_layout1, execute_read) 7339 7164 { 7340 7165 struct audit_records records; ··· 7323 7188 test_execute(_metadata, 0, file1_s1d1); 7324 7189 test_check_exec(_metadata, 0, file1_s1d1); 7325 7190 7326 - drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 7327 - .handled_access_fs = access_fs_16, 7328 - }); 7191 + enforce_fs(_metadata, ACCESS_ALL, NULL); 7329 7192 7330 7193 /* 7331 7194 * The only difference with the previous audit_layout1.execute_read test is ··· 7345 7212 { 7346 7213 struct audit_records records; 7347 7214 7348 - drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 7349 - .handled_access_fs = access_fs_16, 7350 - }); 7215 + enforce_fs(_metadata, ACCESS_ALL, NULL); 7351 7216 7352 7217 EXPECT_EQ(EACCES, test_open(file1_s1d1, O_WRONLY)); 7353 7218 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, ··· 7360 7229 { 7361 7230 struct audit_records records; 7362 7231 7363 - drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 7364 - .handled_access_fs = access_fs_16, 7365 - }); 7232 + enforce_fs(_metadata, ACCESS_ALL, NULL); 7366 7233 7367 7234 EXPECT_EQ(EACCES, test_open(file1_s1d1, O_RDONLY)); 7368 7235 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.read_file", ··· 7375 7246 { 7376 7247 struct audit_records records; 7377 7248 7378 - drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 7379 - .handled_access_fs = access_fs_16, 7380 - }); 7249 + enforce_fs(_metadata, ACCESS_ALL, NULL); 7381 7250 7382 7251 EXPECT_EQ(EACCES, test_open(dir_s1d1, O_DIRECTORY)); 7383 7252 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.read_dir", ··· 7393 7266 EXPECT_EQ(0, unlink(file1_s1d3)); 7394 7267 EXPECT_EQ(0, unlink(file2_s1d3)); 7395 7268 7396 - drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 7397 - .handled_access_fs = access_fs_16, 7398 - }); 7269 + enforce_fs(_metadata, ACCESS_ALL, NULL); 7399 7270 7400 7271 EXPECT_EQ(-1, rmdir(dir_s1d3)); 7401 7272 EXPECT_EQ(EACCES, errno); ··· 7414 7289 { 7415 7290 struct audit_records records; 7416 7291 7417 - drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 7418 - .handled_access_fs = access_fs_16, 7419 - }); 7292 + enforce_fs(_metadata, ACCESS_ALL, NULL); 7420 7293 7421 7294 EXPECT_EQ(-1, unlink(file1_s1d3)); 7422 7295 EXPECT_EQ(EACCES, errno); ··· 7432 7309 7433 7310 EXPECT_EQ(0, unlink(file1_s1d3)); 7434 7311 7435 - drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 7436 - .handled_access_fs = access_fs_16, 7437 - }); 7312 + enforce_fs(_metadata, ACCESS_ALL, NULL); 7438 7313 7439 7314 EXPECT_EQ(-1, mknod(file1_s1d3, S_IFCHR | 0644, 0)); 7440 7315 EXPECT_EQ(EACCES, errno); ··· 7450 7329 7451 7330 EXPECT_EQ(0, unlink(file1_s1d3)); 7452 7331 7453 - drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 7454 - .handled_access_fs = access_fs_16, 7455 - }); 7332 + enforce_fs(_metadata, ACCESS_ALL, NULL); 7456 7333 7457 7334 EXPECT_EQ(-1, mkdir(file1_s1d3, 0755)); 7458 7335 EXPECT_EQ(EACCES, errno); ··· 7468 7349 7469 7350 EXPECT_EQ(0, unlink(file1_s1d3)); 7470 7351 7471 - drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 7472 - .handled_access_fs = access_fs_16, 7473 - }); 7352 + enforce_fs(_metadata, ACCESS_ALL, NULL); 7474 7353 7475 7354 EXPECT_EQ(-1, mknod(file1_s1d3, S_IFREG | 0644, 0)); 7476 7355 EXPECT_EQ(EACCES, errno); ··· 7486 7369 7487 7370 EXPECT_EQ(0, unlink(file1_s1d3)); 7488 7371 7489 - drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 7490 - .handled_access_fs = access_fs_16, 7491 - }); 7372 + enforce_fs(_metadata, ACCESS_ALL, NULL); 7492 7373 7493 7374 EXPECT_EQ(-1, mknod(file1_s1d3, S_IFSOCK | 0644, 0)); 7494 7375 EXPECT_EQ(EACCES, errno); ··· 7504 7389 7505 7390 EXPECT_EQ(0, unlink(file1_s1d3)); 7506 7391 7507 - drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 7508 - .handled_access_fs = access_fs_16, 7509 - }); 7392 + enforce_fs(_metadata, ACCESS_ALL, NULL); 7510 7393 7511 7394 EXPECT_EQ(-1, mknod(file1_s1d3, S_IFIFO | 0644, 0)); 7512 7395 EXPECT_EQ(EACCES, errno); ··· 7522 7409 7523 7410 EXPECT_EQ(0, unlink(file1_s1d3)); 7524 7411 7525 - drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 7526 - .handled_access_fs = access_fs_16, 7527 - }); 7412 + enforce_fs(_metadata, ACCESS_ALL, NULL); 7528 7413 7529 7414 EXPECT_EQ(-1, mknod(file1_s1d3, S_IFBLK | 0644, 0)); 7530 7415 EXPECT_EQ(EACCES, errno); ··· 7540 7429 7541 7430 EXPECT_EQ(0, unlink(file1_s1d3)); 7542 7431 7543 - drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 7544 - .handled_access_fs = access_fs_16, 7545 - }); 7432 + enforce_fs(_metadata, ACCESS_ALL, NULL); 7546 7433 7547 7434 EXPECT_EQ(-1, symlink("target", file1_s1d3)); 7548 7435 EXPECT_EQ(EACCES, errno); ··· 7558 7449 7559 7450 EXPECT_EQ(0, unlink(file1_s1d3)); 7560 7451 7561 - drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 7562 - .handled_access_fs = 7563 - LANDLOCK_ACCESS_FS_REFER, 7564 - }); 7452 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_REFER, NULL); 7565 7453 7566 7454 EXPECT_EQ(-1, link(file1_s1d1, file1_s1d3)); 7567 7455 EXPECT_EQ(EXDEV, errno); ··· 7580 7474 7581 7475 EXPECT_EQ(0, unlink(file1_s1d3)); 7582 7476 7583 - drop_access_rights(_metadata, 7584 - &(struct landlock_ruleset_attr){ 7585 - .handled_access_fs = 7586 - LANDLOCK_ACCESS_FS_MAKE_REG | 7587 - LANDLOCK_ACCESS_FS_REFER, 7588 - }); 7477 + enforce_fs(_metadata, 7478 + LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_REFER, 7479 + NULL); 7589 7480 7590 7481 EXPECT_EQ(-1, link(file1_s1d1, file1_s1d3)); 7591 7482 EXPECT_EQ(EACCES, errno); ··· 7602 7499 7603 7500 EXPECT_EQ(0, unlink(file1_s1d3)); 7604 7501 7605 - drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 7606 - .handled_access_fs = access_fs_16, 7607 - }); 7502 + enforce_fs(_metadata, ACCESS_ALL, NULL); 7608 7503 7609 7504 EXPECT_EQ(EACCES, test_rename(file1_s1d2, file1_s2d3)); 7610 7505 EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, ··· 7622 7521 7623 7522 EXPECT_EQ(0, unlink(file1_s1d3)); 7624 7523 7625 - drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 7626 - .handled_access_fs = access_fs_16, 7627 - }); 7524 + enforce_fs(_metadata, ACCESS_ALL, NULL); 7628 7525 7629 7526 /* 7630 7527 * The only difference with the previous audit_layout1.refer_rename test is ··· 7660 7561 }, 7661 7562 {}, 7662 7563 }; 7663 - int ruleset_fd = 7664 - create_ruleset(_metadata, LANDLOCK_ACCESS_FS_REFER, layer1); 7665 7564 7666 - ASSERT_LE(0, ruleset_fd); 7667 - enforce_ruleset(_metadata, ruleset_fd); 7668 - ASSERT_EQ(0, close(ruleset_fd)); 7565 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_REFER, layer1); 7669 7566 7670 7567 ASSERT_EQ(-1, rename(dir_s1d2, dir_s2d3)); 7671 7568 ASSERT_EQ(EXDEV, errno); ··· 7679 7584 { 7680 7585 struct audit_records records; 7681 7586 7682 - drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ 7683 - .handled_access_fs = access_fs_16, 7684 - }); 7587 + enforce_fs(_metadata, ACCESS_ALL, NULL); 7685 7588 7686 7589 EXPECT_EQ(-1, truncate(file1_s1d3, 0)); 7687 7590 EXPECT_EQ(EACCES, errno); ··· 7696 7603 struct audit_records records; 7697 7604 int fd; 7698 7605 7699 - drop_access_rights(_metadata, 7700 - &(struct landlock_ruleset_attr){ 7701 - .handled_access_fs = 7702 - access_fs_16 & 7703 - ~LANDLOCK_ACCESS_FS_READ_FILE, 7704 - }); 7606 + enforce_fs(_metadata, ACCESS_ALL & ~LANDLOCK_ACCESS_FS_READ_FILE, NULL); 7705 7607 7706 7608 fd = open("/dev/null", O_RDONLY | O_CLOEXEC); 7707 7609 ASSERT_LE(0, fd); ··· 7710 7622 EXPECT_EQ(1, records.domain); 7711 7623 } 7712 7624 7625 + TEST_F(audit_layout1, resolve_unix) 7626 + { 7627 + struct audit_records records; 7628 + const char *const path = "sock"; 7629 + int srv_fd, cli_fd, status; 7630 + pid_t child_pid; 7631 + 7632 + srv_fd = set_up_named_unix_server(_metadata, SOCK_STREAM, path); 7633 + 7634 + child_pid = fork(); 7635 + ASSERT_LE(0, child_pid); 7636 + if (!child_pid) { 7637 + enforce_fs(_metadata, ACCESS_ALL, NULL); 7638 + 7639 + cli_fd = socket(AF_UNIX, SOCK_STREAM, 0); 7640 + ASSERT_LE(0, cli_fd); 7641 + EXPECT_EQ(EACCES, 7642 + test_connect_named_unix(_metadata, cli_fd, path)); 7643 + 7644 + EXPECT_EQ(0, close(cli_fd)); 7645 + _exit(_metadata->exit_code); 7646 + } 7647 + 7648 + ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0)); 7649 + EXPECT_EQ(1, WIFEXITED(status)); 7650 + EXPECT_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); 7651 + 7652 + EXPECT_EQ(0, matches_log_fs_extra(_metadata, self->audit_fd, 7653 + "fs\\.resolve_unix", path, NULL)); 7654 + 7655 + EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 7656 + EXPECT_EQ(0, records.access); 7657 + EXPECT_EQ(1, records.domain); 7658 + 7659 + EXPECT_EQ(0, close(srv_fd)); 7660 + } 7661 + 7713 7662 TEST_F(audit_layout1, mount) 7714 7663 { 7715 7664 struct audit_records records; 7716 7665 7717 - drop_access_rights(_metadata, 7718 - &(struct landlock_ruleset_attr){ 7719 - .handled_access_fs = 7720 - LANDLOCK_ACCESS_FS_EXECUTE, 7721 - }); 7666 + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_EXECUTE, NULL); 7722 7667 7723 7668 set_cap(_metadata, CAP_SYS_ADMIN); 7724 7669 EXPECT_EQ(-1, mount(NULL, dir_s3d2, NULL, MS_RDONLY, NULL));
+1 -1
tools/testing/selftests/landlock/net_test.c
··· 1356 1356 &net_port, 0)) 1357 1357 { 1358 1358 TH_LOG("Failed to add rule with access 0x%llx: %s", 1359 - access, strerror(errno)); 1359 + (unsigned long long)access, strerror(errno)); 1360 1360 } 1361 1361 } 1362 1362 EXPECT_EQ(0, close(ruleset_fd));
-1
tools/testing/selftests/landlock/ptrace_test.c
··· 342 342 /* Makes sure there is no superfluous logged records. */ 343 343 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 344 344 EXPECT_EQ(0, records.access); 345 - EXPECT_EQ(0, records.domain); 346 345 347 346 yama_ptrace_scope = get_yama_ptrace_scope(); 348 347 ASSERT_LE(0, yama_ptrace_scope);
-1
tools/testing/selftests/landlock/scoped_abstract_unix_test.c
··· 312 312 /* Makes sure there is no superfluous logged records. */ 313 313 EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); 314 314 EXPECT_EQ(0, records.access); 315 - EXPECT_EQ(0, records.domain); 316 315 317 316 ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC)); 318 317 ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));
+77
tools/testing/selftests/landlock/tsync_test.c
··· 247 247 EXPECT_EQ(0, close(ruleset_fd)); 248 248 } 249 249 250 + /* clang-format off */ 251 + FIXTURE(tsync_without_ruleset) {}; 252 + /* clang-format on */ 253 + 254 + FIXTURE_VARIANT(tsync_without_ruleset) 255 + { 256 + const __u32 flags; 257 + const int expected_errno; 258 + }; 259 + 260 + /* clang-format off */ 261 + FIXTURE_VARIANT_ADD(tsync_without_ruleset, tsync_only) { 262 + /* clang-format on */ 263 + .flags = LANDLOCK_RESTRICT_SELF_TSYNC, 264 + .expected_errno = EBADF, 265 + }; 266 + 267 + /* clang-format off */ 268 + FIXTURE_VARIANT_ADD(tsync_without_ruleset, subdomains_off_same_exec_off) { 269 + /* clang-format on */ 270 + .flags = LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF | 271 + LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF | 272 + LANDLOCK_RESTRICT_SELF_TSYNC, 273 + .expected_errno = EBADF, 274 + }; 275 + 276 + /* clang-format off */ 277 + FIXTURE_VARIANT_ADD(tsync_without_ruleset, subdomains_off_new_exec_on) { 278 + /* clang-format on */ 279 + .flags = LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF | 280 + LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON | 281 + LANDLOCK_RESTRICT_SELF_TSYNC, 282 + .expected_errno = EBADF, 283 + }; 284 + 285 + /* clang-format off */ 286 + FIXTURE_VARIANT_ADD(tsync_without_ruleset, all_flags) { 287 + /* clang-format on */ 288 + .flags = LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF | 289 + LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON | 290 + LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF | 291 + LANDLOCK_RESTRICT_SELF_TSYNC, 292 + .expected_errno = EBADF, 293 + }; 294 + 295 + /* clang-format off */ 296 + FIXTURE_VARIANT_ADD(tsync_without_ruleset, subdomains_off) { 297 + /* clang-format on */ 298 + .flags = LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF | 299 + LANDLOCK_RESTRICT_SELF_TSYNC, 300 + .expected_errno = 0, 301 + }; 302 + 303 + FIXTURE_SETUP(tsync_without_ruleset) 304 + { 305 + disable_caps(_metadata); 306 + } 307 + 308 + FIXTURE_TEARDOWN(tsync_without_ruleset) 309 + { 310 + } 311 + 312 + TEST_F(tsync_without_ruleset, check) 313 + { 314 + int ret; 315 + 316 + ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); 317 + 318 + ret = landlock_restrict_self(-1, variant->flags); 319 + if (variant->expected_errno) { 320 + EXPECT_EQ(-1, ret); 321 + EXPECT_EQ(variant->expected_errno, errno); 322 + } else { 323 + EXPECT_EQ(0, ret); 324 + } 325 + } 326 + 250 327 TEST_HARNESS_MAIN