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-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mic/linux

Pull landlock updates from Mickaël Salaün:
"A Landlock ruleset can now handle two new access rights:
LANDLOCK_ACCESS_NET_BIND_TCP and LANDLOCK_ACCESS_NET_CONNECT_TCP. When
handled, the related actions are denied unless explicitly allowed by a
Landlock network rule for a specific port.

The related patch series has been reviewed for almost two years, it
has evolved a lot and we now have reached a decent design, code and
testing. The refactored kernel code and the new test helpers also
bring the foundation to support more network protocols.

Test coverage for security/landlock is 92.4% of 710 lines according to
gcc/gcov-13, and it was 93.1% of 597 lines before this series. The
decrease in coverage is due to code refactoring to make the ruleset
management more generic (i.e. dealing with inodes and ports) that also
added new WARN_ON_ONCE() checks not possible to test from user space.

syzkaller has been updated accordingly [4], and such patched instance
(tailored to Landlock) has been running for a month, covering all the
new network-related code [5]"

Link: https://lore.kernel.org/r/20231026014751.414649-1-konstantin.meskhidze@huawei.com [1]
Link: https://lore.kernel.org/r/CAHC9VhS1wwgH6NNd+cJz4MYogPiRV8NyPDd1yj5SpaxeUB4UVg@mail.gmail.com [2]
Link: https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next-history.git/commit/?id=c8dc5ee69d3a [3]
Link: https://github.com/google/syzkaller/pull/4266 [4]
Link: https://storage.googleapis.com/syzbot-assets/82e8608dec36/ci-upstream-linux-next-kasan-gce-root-ab577164.html#security%2flandlock%2fnet.c [5]

* tag 'landlock-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mic/linux:
selftests/landlock: Add tests for FS topology changes with network rules
landlock: Document network support
samples/landlock: Support TCP restrictions
selftests/landlock: Add network tests
selftests/landlock: Share enforce_ruleset() helper
landlock: Support network rules with TCP bind and connect
landlock: Refactor landlock_add_rule() syscall
landlock: Refactor layer helpers
landlock: Move and rename layer helpers
landlock: Refactor merge/inherit_ruleset helpers
landlock: Refactor landlock_find_rule/insert_rule helpers
landlock: Allow FS topology changes for domains without such rule type
landlock: Make ruleset's access masks more generic

+2967 -352
+74 -25
Documentation/userspace-api/landlock.rst
··· 8 8 ===================================== 9 9 10 10 :Author: Mickaël Salaün 11 - :Date: October 2022 11 + :Date: October 2023 12 12 13 13 The goal of Landlock is to enable to restrict ambient rights (e.g. global 14 - filesystem access) for a set of processes. Because Landlock is a stackable 15 - LSM, it makes possible to create safe security sandboxes as new security layers 16 - in addition to the existing system-wide access-controls. This kind of sandbox 17 - is expected to help mitigate the security impact of bugs or 14 + filesystem or network access) for a set of processes. Because Landlock 15 + is a stackable LSM, it makes possible to create safe security sandboxes as new 16 + security layers in addition to the existing system-wide access-controls. This 17 + kind of sandbox is expected to help mitigate the security impact of bugs or 18 18 unexpected/malicious behaviors in user space applications. Landlock empowers 19 19 any process, including unprivileged ones, to securely restrict themselves. 20 20 ··· 28 28 Landlock rules 29 29 ============== 30 30 31 - A Landlock rule describes an action on an object. An object is currently a 32 - file hierarchy, and the related filesystem actions are defined with `access 33 - rights`_. A set of rules is aggregated in a ruleset, which can then restrict 31 + A Landlock rule describes an action on an object which the process intends to 32 + perform. A set of rules is aggregated in a ruleset, which can then restrict 34 33 the thread enforcing it, and its future children. 34 + 35 + The two existing types of rules are: 36 + 37 + Filesystem rules 38 + For these rules, the object is a file hierarchy, 39 + and the related filesystem actions are defined with 40 + `filesystem access rights`. 41 + 42 + Network rules (since ABI v4) 43 + For these rules, the object is a TCP port, 44 + and the related actions are defined with `network access rights`. 35 45 36 46 Defining and enforcing a security policy 37 47 ---------------------------------------- 38 48 39 - We first need to define the ruleset that will contain our rules. For this 40 - example, the ruleset will contain rules that only allow read actions, but write 41 - actions will be denied. The ruleset then needs to handle both of these kind of 42 - actions. This is required for backward and forward compatibility (i.e. the 43 - kernel and user space may not know each other's supported restrictions), hence 44 - the need to be explicit about the denied-by-default access rights. 49 + We first need to define the ruleset that will contain our rules. 50 + 51 + For this example, the ruleset will contain rules that only allow filesystem 52 + read actions and establish a specific TCP connection. Filesystem write 53 + actions and other TCP actions will be denied. 54 + 55 + The ruleset then needs to handle both these kinds of actions. This is 56 + required for backward and forward compatibility (i.e. the kernel and user 57 + space may not know each other's supported restrictions), hence the need 58 + to be explicit about the denied-by-default access rights. 45 59 46 60 .. code-block:: c 47 61 ··· 76 62 LANDLOCK_ACCESS_FS_MAKE_SYM | 77 63 LANDLOCK_ACCESS_FS_REFER | 78 64 LANDLOCK_ACCESS_FS_TRUNCATE, 65 + .handled_access_net = 66 + LANDLOCK_ACCESS_NET_BIND_TCP | 67 + LANDLOCK_ACCESS_NET_CONNECT_TCP, 79 68 }; 80 69 81 70 Because we may not know on which kernel version an application will be ··· 87 70 using. To avoid binary enforcement (i.e. either all security features or 88 71 none), we can leverage a dedicated Landlock command to get the current version 89 72 of the Landlock ABI and adapt the handled accesses. Let's check if we should 90 - remove the ``LANDLOCK_ACCESS_FS_REFER`` or ``LANDLOCK_ACCESS_FS_TRUNCATE`` 91 - access rights, which are only supported starting with the second and third 92 - version of the ABI. 73 + remove access rights which are only supported in higher versions of the ABI. 93 74 94 75 .. code-block:: c 95 76 ··· 107 92 case 2: 108 93 /* Removes LANDLOCK_ACCESS_FS_TRUNCATE for ABI < 3 */ 109 94 ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE; 95 + __attribute__((fallthrough)); 96 + case 3: 97 + /* Removes network support for ABI < 4 */ 98 + ruleset_attr.handled_access_net &= 99 + ~(LANDLOCK_ACCESS_NET_BIND_TCP | 100 + LANDLOCK_ACCESS_NET_CONNECT_TCP); 110 101 } 111 102 112 103 This enables to create an inclusive ruleset that will contain our rules. ··· 164 143 ABI version. In this example, this is not required because all of the requested 165 144 ``allowed_access`` rights are already available in ABI 1. 166 145 167 - We now have a ruleset with one rule allowing read access to ``/usr`` while 168 - denying all other handled accesses for the filesystem. The next step is to 169 - restrict the current thread from gaining more privileges (e.g. thanks to a SUID 170 - binary). 146 + For network access-control, we can add a set of rules that allow to use a port 147 + number for a specific action: HTTPS connections. 148 + 149 + .. code-block:: c 150 + 151 + struct landlock_net_port_attr net_port = { 152 + .allowed_access = LANDLOCK_ACCESS_NET_CONNECT_TCP, 153 + .port = 443, 154 + }; 155 + 156 + err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 157 + &net_port, 0); 158 + 159 + The next step is to restrict the current thread from gaining more privileges 160 + (e.g. through a SUID binary). We now have a ruleset with the first rule 161 + allowing read access to ``/usr`` while denying all other handled accesses for 162 + the filesystem, and a second rule allowing HTTPS connections. 171 163 172 164 .. code-block:: c 173 165 ··· 389 355 ------------- 390 356 391 357 .. kernel-doc:: include/uapi/linux/landlock.h 392 - :identifiers: fs_access 358 + :identifiers: fs_access net_access 393 359 394 360 Creating a new ruleset 395 361 ---------------------- ··· 408 374 409 375 .. kernel-doc:: include/uapi/linux/landlock.h 410 376 :identifiers: landlock_rule_type landlock_path_beneath_attr 377 + landlock_net_port_attr 411 378 412 379 Enforcing a ruleset 413 380 ------------------- ··· 422 387 Filesystem topology modification 423 388 -------------------------------- 424 389 425 - As for file renaming and linking, a sandboxed thread cannot modify its 426 - filesystem topology, whether via :manpage:`mount(2)` or 427 - :manpage:`pivot_root(2)`. However, :manpage:`chroot(2)` calls are not denied. 390 + Threads sandboxed with filesystem restrictions cannot modify filesystem 391 + topology, whether via :manpage:`mount(2)` or :manpage:`pivot_root(2)`. 392 + However, :manpage:`chroot(2)` calls are not denied. 428 393 429 394 Special filesystems 430 395 ------------------- ··· 486 451 Starting with the Landlock ABI version 3, it is now possible to securely control 487 452 truncation thanks to the new ``LANDLOCK_ACCESS_FS_TRUNCATE`` access right. 488 453 454 + Network support (ABI < 4) 455 + ------------------------- 456 + 457 + Starting with the Landlock ABI version 4, it is now possible to restrict TCP 458 + bind and connect actions to only a set of allowed ports thanks to the new 459 + ``LANDLOCK_ACCESS_NET_BIND_TCP`` and ``LANDLOCK_ACCESS_NET_CONNECT_TCP`` 460 + access rights. 461 + 489 462 .. _kernel_support: 490 463 491 464 Kernel support ··· 511 468 still enable it by adding ``lsm=landlock,[...]`` to 512 469 Documentation/admin-guide/kernel-parameters.rst thanks to the bootloader 513 470 configuration. 471 + 472 + To be able to explicitly allow TCP operations (e.g., adding a network rule with 473 + ``LANDLOCK_ACCESS_NET_BIND_TCP``), the kernel must support TCP 474 + (``CONFIG_INET=y``). Otherwise, sys_landlock_add_rule() returns an 475 + ``EAFNOSUPPORT`` error, which can safely be ignored because this kind of TCP 476 + operation is already not possible. 514 477 515 478 Questions and answers 516 479 =====================
+55
include/uapi/linux/landlock.h
··· 31 31 * this access right. 32 32 */ 33 33 __u64 handled_access_fs; 34 + /** 35 + * @handled_access_net: Bitmask of actions (cf. `Network flags`_) 36 + * that is handled by this ruleset and should then be forbidden if no 37 + * rule explicitly allow them. 38 + */ 39 + __u64 handled_access_net; 34 40 }; 35 41 36 42 /* ··· 60 54 * landlock_path_beneath_attr . 61 55 */ 62 56 LANDLOCK_RULE_PATH_BENEATH = 1, 57 + /** 58 + * @LANDLOCK_RULE_NET_PORT: Type of a &struct 59 + * landlock_net_port_attr . 60 + */ 61 + LANDLOCK_RULE_NET_PORT, 63 62 }; 64 63 65 64 /** ··· 89 78 * Cf. security/landlock/syscalls.c:build_check_abi() 90 79 */ 91 80 } __attribute__((packed)); 81 + 82 + /** 83 + * struct landlock_net_port_attr - Network port definition 84 + * 85 + * Argument of sys_landlock_add_rule(). 86 + */ 87 + struct landlock_net_port_attr { 88 + /** 89 + * @allowed_access: Bitmask of allowed access network for a port 90 + * (cf. `Network flags`_). 91 + */ 92 + __u64 allowed_access; 93 + /** 94 + * @port: Network port in host endianness. 95 + * 96 + * It should be noted that port 0 passed to :manpage:`bind(2)` will 97 + * bind to an available port from a specific port range. This can be 98 + * configured thanks to the ``/proc/sys/net/ipv4/ip_local_port_range`` 99 + * sysctl (also used for IPv6). A Landlock rule with port 0 and the 100 + * ``LANDLOCK_ACCESS_NET_BIND_TCP`` right means that requesting to bind 101 + * on port 0 is allowed and it will automatically translate to binding 102 + * on the related port range. 103 + */ 104 + __u64 port; 105 + }; 92 106 93 107 /** 94 108 * DOC: fs_access ··· 225 189 #define LANDLOCK_ACCESS_FS_TRUNCATE (1ULL << 14) 226 190 /* clang-format on */ 227 191 192 + /** 193 + * DOC: net_access 194 + * 195 + * Network flags 196 + * ~~~~~~~~~~~~~~~~ 197 + * 198 + * These flags enable to restrict a sandboxed process to a set of network 199 + * actions. This is supported since the Landlock ABI version 4. 200 + * 201 + * TCP sockets with allowed actions: 202 + * 203 + * - %LANDLOCK_ACCESS_NET_BIND_TCP: Bind a TCP socket to a local port. 204 + * - %LANDLOCK_ACCESS_NET_CONNECT_TCP: Connect an active TCP socket to 205 + * a remote port. 206 + */ 207 + /* clang-format off */ 208 + #define LANDLOCK_ACCESS_NET_BIND_TCP (1ULL << 0) 209 + #define LANDLOCK_ACCESS_NET_CONNECT_TCP (1ULL << 1) 210 + /* clang-format on */ 228 211 #endif /* _UAPI_LINUX_LANDLOCK_H */
+100 -15
samples/landlock/sandboxer.c
··· 8 8 */ 9 9 10 10 #define _GNU_SOURCE 11 + #define __SANE_USERSPACE_TYPES__ 12 + #include <arpa/inet.h> 11 13 #include <errno.h> 12 14 #include <fcntl.h> 13 15 #include <linux/landlock.h> ··· 53 51 54 52 #define ENV_FS_RO_NAME "LL_FS_RO" 55 53 #define ENV_FS_RW_NAME "LL_FS_RW" 56 - #define ENV_PATH_TOKEN ":" 54 + #define ENV_TCP_BIND_NAME "LL_TCP_BIND" 55 + #define ENV_TCP_CONNECT_NAME "LL_TCP_CONNECT" 56 + #define ENV_DELIMITER ":" 57 57 58 58 static int parse_path(char *env_path, const char ***const path_list) 59 59 { ··· 64 60 if (env_path) { 65 61 num_paths++; 66 62 for (i = 0; env_path[i]; i++) { 67 - if (env_path[i] == ENV_PATH_TOKEN[0]) 63 + if (env_path[i] == ENV_DELIMITER[0]) 68 64 num_paths++; 69 65 } 70 66 } 71 67 *path_list = malloc(num_paths * sizeof(**path_list)); 72 68 for (i = 0; i < num_paths; i++) 73 - (*path_list)[i] = strsep(&env_path, ENV_PATH_TOKEN); 69 + (*path_list)[i] = strsep(&env_path, ENV_DELIMITER); 74 70 75 71 return num_paths; 76 72 } ··· 85 81 86 82 /* clang-format on */ 87 83 88 - static int populate_ruleset(const char *const env_var, const int ruleset_fd, 89 - const __u64 allowed_access) 84 + static int populate_ruleset_fs(const char *const env_var, const int ruleset_fd, 85 + const __u64 allowed_access) 90 86 { 91 87 int num_paths, i, ret = 1; 92 88 char *env_path_name; ··· 147 143 return ret; 148 144 } 149 145 146 + static int populate_ruleset_net(const char *const env_var, const int ruleset_fd, 147 + const __u64 allowed_access) 148 + { 149 + int ret = 1; 150 + char *env_port_name, *strport; 151 + struct landlock_net_port_attr net_port = { 152 + .allowed_access = allowed_access, 153 + .port = 0, 154 + }; 155 + 156 + env_port_name = getenv(env_var); 157 + if (!env_port_name) 158 + return 0; 159 + env_port_name = strdup(env_port_name); 160 + unsetenv(env_var); 161 + 162 + while ((strport = strsep(&env_port_name, ENV_DELIMITER))) { 163 + net_port.port = atoi(strport); 164 + if (landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 165 + &net_port, 0)) { 166 + fprintf(stderr, 167 + "Failed to update the ruleset with port \"%llu\": %s\n", 168 + net_port.port, strerror(errno)); 169 + goto out_free_name; 170 + } 171 + } 172 + ret = 0; 173 + 174 + out_free_name: 175 + free(env_port_name); 176 + return ret; 177 + } 178 + 150 179 /* clang-format off */ 151 180 152 181 #define ACCESS_FS_ROUGHLY_READ ( \ ··· 203 166 204 167 /* clang-format on */ 205 168 206 - #define LANDLOCK_ABI_LAST 3 169 + #define LANDLOCK_ABI_LAST 4 207 170 208 171 int main(const int argc, char *const argv[], char *const *const envp) 209 172 { 210 173 const char *cmd_path; 211 174 char *const *cmd_argv; 212 175 int ruleset_fd, abi; 176 + char *env_port_name; 213 177 __u64 access_fs_ro = ACCESS_FS_ROUGHLY_READ, 214 178 access_fs_rw = ACCESS_FS_ROUGHLY_READ | ACCESS_FS_ROUGHLY_WRITE; 179 + 215 180 struct landlock_ruleset_attr ruleset_attr = { 216 181 .handled_access_fs = access_fs_rw, 182 + .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | 183 + LANDLOCK_ACCESS_NET_CONNECT_TCP, 217 184 }; 218 185 219 186 if (argc < 2) { 220 187 fprintf(stderr, 221 - "usage: %s=\"...\" %s=\"...\" %s <cmd> [args]...\n\n", 222 - ENV_FS_RO_NAME, ENV_FS_RW_NAME, argv[0]); 188 + "usage: %s=\"...\" %s=\"...\" %s=\"...\" %s=\"...\"%s " 189 + "<cmd> [args]...\n\n", 190 + ENV_FS_RO_NAME, ENV_FS_RW_NAME, ENV_TCP_BIND_NAME, 191 + ENV_TCP_CONNECT_NAME, argv[0]); 223 192 fprintf(stderr, 224 193 "Launch a command in a restricted environment.\n\n"); 225 - fprintf(stderr, "Environment variables containing paths, " 226 - "each separated by a colon:\n"); 194 + fprintf(stderr, 195 + "Environment variables containing paths and ports " 196 + "each separated by a colon:\n"); 227 197 fprintf(stderr, 228 198 "* %s: list of paths allowed to be used in a read-only way.\n", 229 199 ENV_FS_RO_NAME); 230 200 fprintf(stderr, 231 - "* %s: list of paths allowed to be used in a read-write way.\n", 201 + "* %s: list of paths allowed to be used in a read-write way.\n\n", 232 202 ENV_FS_RW_NAME); 203 + fprintf(stderr, 204 + "Environment variables containing ports are optional " 205 + "and could be skipped.\n"); 206 + fprintf(stderr, 207 + "* %s: list of ports allowed to bind (server).\n", 208 + ENV_TCP_BIND_NAME); 209 + fprintf(stderr, 210 + "* %s: list of ports allowed to connect (client).\n", 211 + ENV_TCP_CONNECT_NAME); 233 212 fprintf(stderr, 234 213 "\nexample:\n" 235 214 "%s=\"/bin:/lib:/usr:/proc:/etc:/dev/urandom\" " 236 215 "%s=\"/dev/null:/dev/full:/dev/zero:/dev/pts:/tmp\" " 216 + "%s=\"9418\" " 217 + "%s=\"80:443\" " 237 218 "%s bash -i\n\n", 238 - ENV_FS_RO_NAME, ENV_FS_RW_NAME, argv[0]); 219 + ENV_FS_RO_NAME, ENV_FS_RW_NAME, ENV_TCP_BIND_NAME, 220 + ENV_TCP_CONNECT_NAME, argv[0]); 239 221 fprintf(stderr, 240 222 "This sandboxer can use Landlock features " 241 223 "up to ABI version %d.\n", ··· 311 255 case 2: 312 256 /* Removes LANDLOCK_ACCESS_FS_TRUNCATE for ABI < 3 */ 313 257 ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE; 314 - 258 + __attribute__((fallthrough)); 259 + case 3: 260 + /* Removes network support for ABI < 4 */ 261 + ruleset_attr.handled_access_net &= 262 + ~(LANDLOCK_ACCESS_NET_BIND_TCP | 263 + LANDLOCK_ACCESS_NET_CONNECT_TCP); 315 264 fprintf(stderr, 316 265 "Hint: You should update the running kernel " 317 266 "to leverage Landlock features " ··· 335 274 access_fs_ro &= ruleset_attr.handled_access_fs; 336 275 access_fs_rw &= ruleset_attr.handled_access_fs; 337 276 277 + /* Removes bind access attribute if not supported by a user. */ 278 + env_port_name = getenv(ENV_TCP_BIND_NAME); 279 + if (!env_port_name) { 280 + ruleset_attr.handled_access_net &= 281 + ~LANDLOCK_ACCESS_NET_BIND_TCP; 282 + } 283 + /* Removes connect access attribute if not supported by a user. */ 284 + env_port_name = getenv(ENV_TCP_CONNECT_NAME); 285 + if (!env_port_name) { 286 + ruleset_attr.handled_access_net &= 287 + ~LANDLOCK_ACCESS_NET_CONNECT_TCP; 288 + } 289 + 338 290 ruleset_fd = 339 291 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 340 292 if (ruleset_fd < 0) { 341 293 perror("Failed to create a ruleset"); 342 294 return 1; 343 295 } 344 - if (populate_ruleset(ENV_FS_RO_NAME, ruleset_fd, access_fs_ro)) { 296 + 297 + if (populate_ruleset_fs(ENV_FS_RO_NAME, ruleset_fd, access_fs_ro)) { 345 298 goto err_close_ruleset; 346 299 } 347 - if (populate_ruleset(ENV_FS_RW_NAME, ruleset_fd, access_fs_rw)) { 300 + if (populate_ruleset_fs(ENV_FS_RW_NAME, ruleset_fd, access_fs_rw)) { 348 301 goto err_close_ruleset; 349 302 } 303 + 304 + if (populate_ruleset_net(ENV_TCP_BIND_NAME, ruleset_fd, 305 + LANDLOCK_ACCESS_NET_BIND_TCP)) { 306 + goto err_close_ruleset; 307 + } 308 + if (populate_ruleset_net(ENV_TCP_CONNECT_NAME, ruleset_fd, 309 + LANDLOCK_ACCESS_NET_CONNECT_TCP)) { 310 + goto err_close_ruleset; 311 + } 312 + 350 313 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 351 314 perror("Failed to restrict privileges"); 352 315 goto err_close_ruleset;
+1
security/landlock/Kconfig
··· 3 3 config SECURITY_LANDLOCK 4 4 bool "Landlock support" 5 5 depends on SECURITY 6 + select SECURITY_NETWORK 6 7 select SECURITY_PATH 7 8 help 8 9 Landlock is a sandboxing mechanism that enables processes to restrict
+2
security/landlock/Makefile
··· 2 2 3 3 landlock-y := setup.o syscalls.o object.o ruleset.o \ 4 4 cred.o ptrace.o fs.o 5 + 6 + landlock-$(CONFIG_INET) += net.o
+74 -158
security/landlock/fs.c
··· 151 151 /* clang-format on */ 152 152 153 153 /* 154 - * All access rights that are denied by default whether they are handled or not 155 - * by a ruleset/layer. This must be ORed with all ruleset->fs_access_masks[] 156 - * entries when we need to get the absolute handled access masks. 157 - */ 158 - /* clang-format off */ 159 - #define ACCESS_INITIALLY_DENIED ( \ 160 - LANDLOCK_ACCESS_FS_REFER) 161 - /* clang-format on */ 162 - 163 - /* 164 154 * @path: Should have been checked by get_path_from_fd(). 165 155 */ 166 156 int landlock_append_fs_rule(struct landlock_ruleset *const ruleset, ··· 158 168 access_mask_t access_rights) 159 169 { 160 170 int err; 161 - struct landlock_object *object; 171 + struct landlock_id id = { 172 + .type = LANDLOCK_KEY_INODE, 173 + }; 162 174 163 175 /* Files only get access rights that make sense. */ 164 176 if (!d_is_dir(path->dentry) && ··· 170 178 return -EINVAL; 171 179 172 180 /* Transforms relative access rights to absolute ones. */ 173 - access_rights |= 174 - LANDLOCK_MASK_ACCESS_FS & 175 - ~(ruleset->fs_access_masks[0] | ACCESS_INITIALLY_DENIED); 176 - object = get_inode_object(d_backing_inode(path->dentry)); 177 - if (IS_ERR(object)) 178 - return PTR_ERR(object); 181 + access_rights |= LANDLOCK_MASK_ACCESS_FS & 182 + ~landlock_get_fs_access_mask(ruleset, 0); 183 + id.key.object = get_inode_object(d_backing_inode(path->dentry)); 184 + if (IS_ERR(id.key.object)) 185 + return PTR_ERR(id.key.object); 179 186 mutex_lock(&ruleset->lock); 180 - err = landlock_insert_rule(ruleset, object, access_rights); 187 + err = landlock_insert_rule(ruleset, id, access_rights); 181 188 mutex_unlock(&ruleset->lock); 182 189 /* 183 190 * No need to check for an error because landlock_insert_rule() 184 191 * increments the refcount for the new object if needed. 185 192 */ 186 - landlock_put_object(object); 193 + landlock_put_object(id.key.object); 187 194 return err; 188 195 } 189 196 ··· 199 208 { 200 209 const struct landlock_rule *rule; 201 210 const struct inode *inode; 211 + struct landlock_id id = { 212 + .type = LANDLOCK_KEY_INODE, 213 + }; 202 214 203 215 /* Ignores nonexistent leafs. */ 204 216 if (d_is_negative(dentry)) ··· 209 215 210 216 inode = d_backing_inode(dentry); 211 217 rcu_read_lock(); 212 - rule = landlock_find_rule( 213 - domain, rcu_dereference(landlock_inode(inode)->object)); 218 + id.key.object = rcu_dereference(landlock_inode(inode)->object); 219 + rule = landlock_find_rule(domain, id); 214 220 rcu_read_unlock(); 215 221 return rule; 216 - } 217 - 218 - /* 219 - * @layer_masks is read and may be updated according to the access request and 220 - * the matching rule. 221 - * 222 - * Returns true if the request is allowed (i.e. relevant layer masks for the 223 - * request are empty). 224 - */ 225 - static inline bool 226 - unmask_layers(const struct landlock_rule *const rule, 227 - const access_mask_t access_request, 228 - layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS]) 229 - { 230 - size_t layer_level; 231 - 232 - if (!access_request || !layer_masks) 233 - return true; 234 - if (!rule) 235 - return false; 236 - 237 - /* 238 - * An access is granted if, for each policy layer, at least one rule 239 - * encountered on the pathwalk grants the requested access, 240 - * regardless of its position in the layer stack. We must then check 241 - * the remaining layers for each inode, from the first added layer to 242 - * the last one. When there is multiple requested accesses, for each 243 - * policy layer, the full set of requested accesses may not be granted 244 - * by only one rule, but by the union (binary OR) of multiple rules. 245 - * E.g. /a/b <execute> + /a <read> => /a/b <execute + read> 246 - */ 247 - for (layer_level = 0; layer_level < rule->num_layers; layer_level++) { 248 - const struct landlock_layer *const layer = 249 - &rule->layers[layer_level]; 250 - const layer_mask_t layer_bit = BIT_ULL(layer->level - 1); 251 - const unsigned long access_req = access_request; 252 - unsigned long access_bit; 253 - bool is_empty; 254 - 255 - /* 256 - * Records in @layer_masks which layer grants access to each 257 - * requested access. 258 - */ 259 - is_empty = true; 260 - for_each_set_bit(access_bit, &access_req, 261 - ARRAY_SIZE(*layer_masks)) { 262 - if (layer->access & BIT_ULL(access_bit)) 263 - (*layer_masks)[access_bit] &= ~layer_bit; 264 - is_empty = is_empty && !(*layer_masks)[access_bit]; 265 - } 266 - if (is_empty) 267 - return true; 268 - } 269 - return false; 270 222 } 271 223 272 224 /* ··· 227 287 unlikely(IS_PRIVATE(d_backing_inode(dentry)))); 228 288 } 229 289 230 - static inline access_mask_t 231 - get_handled_accesses(const struct landlock_ruleset *const domain) 290 + static access_mask_t 291 + get_raw_handled_fs_accesses(const struct landlock_ruleset *const domain) 232 292 { 233 - access_mask_t access_dom = ACCESS_INITIALLY_DENIED; 293 + access_mask_t access_dom = 0; 234 294 size_t layer_level; 235 295 236 296 for (layer_level = 0; layer_level < domain->num_layers; layer_level++) 237 - access_dom |= domain->fs_access_masks[layer_level]; 238 - return access_dom & LANDLOCK_MASK_ACCESS_FS; 297 + access_dom |= 298 + landlock_get_raw_fs_access_mask(domain, layer_level); 299 + return access_dom; 239 300 } 240 301 241 - /** 242 - * init_layer_masks - Initialize layer masks from an access request 243 - * 244 - * Populates @layer_masks such that for each access right in @access_request, 245 - * the bits for all the layers are set where this access right is handled. 246 - * 247 - * @domain: The domain that defines the current restrictions. 248 - * @access_request: The requested access rights to check. 249 - * @layer_masks: The layer masks to populate. 250 - * 251 - * Returns: An access mask where each access right bit is set which is handled 252 - * in any of the active layers in @domain. 253 - */ 254 - static inline access_mask_t 255 - init_layer_masks(const struct landlock_ruleset *const domain, 256 - const access_mask_t access_request, 257 - layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS]) 302 + static access_mask_t 303 + get_handled_fs_accesses(const struct landlock_ruleset *const domain) 258 304 { 259 - access_mask_t handled_accesses = 0; 260 - size_t layer_level; 305 + /* Handles all initially denied by default access rights. */ 306 + return get_raw_handled_fs_accesses(domain) | 307 + LANDLOCK_ACCESS_FS_INITIALLY_DENIED; 308 + } 261 309 262 - memset(layer_masks, 0, sizeof(*layer_masks)); 263 - /* An empty access request can happen because of O_WRONLY | O_RDWR. */ 264 - if (!access_request) 265 - return 0; 310 + static const struct landlock_ruleset *get_current_fs_domain(void) 311 + { 312 + const struct landlock_ruleset *const dom = 313 + landlock_get_current_domain(); 266 314 267 - /* Saves all handled accesses per layer. */ 268 - for (layer_level = 0; layer_level < domain->num_layers; layer_level++) { 269 - const unsigned long access_req = access_request; 270 - unsigned long access_bit; 315 + if (!dom || !get_raw_handled_fs_accesses(dom)) 316 + return NULL; 271 317 272 - for_each_set_bit(access_bit, &access_req, 273 - ARRAY_SIZE(*layer_masks)) { 274 - /* 275 - * Artificially handles all initially denied by default 276 - * access rights. 277 - */ 278 - if (BIT_ULL(access_bit) & 279 - (domain->fs_access_masks[layer_level] | 280 - ACCESS_INITIALLY_DENIED)) { 281 - (*layer_masks)[access_bit] |= 282 - BIT_ULL(layer_level); 283 - handled_accesses |= BIT_ULL(access_bit); 284 - } 285 - } 286 - } 287 - return handled_accesses; 318 + return dom; 288 319 } 289 320 290 321 /* ··· 430 519 * a superset of the meaningful requested accesses). 431 520 */ 432 521 access_masked_parent1 = access_masked_parent2 = 433 - get_handled_accesses(domain); 522 + get_handled_fs_accesses(domain); 434 523 is_dom_check = true; 435 524 } else { 436 525 if (WARN_ON_ONCE(dentry_child1 || dentry_child2)) ··· 442 531 } 443 532 444 533 if (unlikely(dentry_child1)) { 445 - unmask_layers(find_rule(domain, dentry_child1), 446 - init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS, 447 - &_layer_masks_child1), 448 - &_layer_masks_child1); 534 + landlock_unmask_layers( 535 + find_rule(domain, dentry_child1), 536 + landlock_init_layer_masks( 537 + domain, LANDLOCK_MASK_ACCESS_FS, 538 + &_layer_masks_child1, LANDLOCK_KEY_INODE), 539 + &_layer_masks_child1, ARRAY_SIZE(_layer_masks_child1)); 449 540 layer_masks_child1 = &_layer_masks_child1; 450 541 child1_is_directory = d_is_dir(dentry_child1); 451 542 } 452 543 if (unlikely(dentry_child2)) { 453 - unmask_layers(find_rule(domain, dentry_child2), 454 - init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS, 455 - &_layer_masks_child2), 456 - &_layer_masks_child2); 544 + landlock_unmask_layers( 545 + find_rule(domain, dentry_child2), 546 + landlock_init_layer_masks( 547 + domain, LANDLOCK_MASK_ACCESS_FS, 548 + &_layer_masks_child2, LANDLOCK_KEY_INODE), 549 + &_layer_masks_child2, ARRAY_SIZE(_layer_masks_child2)); 457 550 layer_masks_child2 = &_layer_masks_child2; 458 551 child2_is_directory = d_is_dir(dentry_child2); 459 552 } ··· 509 594 } 510 595 511 596 rule = find_rule(domain, walker_path.dentry); 512 - allowed_parent1 = unmask_layers(rule, access_masked_parent1, 513 - layer_masks_parent1); 514 - allowed_parent2 = unmask_layers(rule, access_masked_parent2, 515 - layer_masks_parent2); 597 + allowed_parent1 = landlock_unmask_layers( 598 + rule, access_masked_parent1, layer_masks_parent1, 599 + ARRAY_SIZE(*layer_masks_parent1)); 600 + allowed_parent2 = landlock_unmask_layers( 601 + rule, access_masked_parent2, layer_masks_parent2, 602 + ARRAY_SIZE(*layer_masks_parent2)); 516 603 517 604 /* Stops when a rule from each layer grants access. */ 518 605 if (allowed_parent1 && allowed_parent2) 519 606 break; 520 - 521 607 jump_up: 522 608 if (walker_path.dentry == walker_path.mnt->mnt_root) { 523 609 if (follow_up(&walker_path)) { ··· 557 641 { 558 642 layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {}; 559 643 560 - access_request = init_layer_masks(domain, access_request, &layer_masks); 644 + access_request = landlock_init_layer_masks( 645 + domain, access_request, &layer_masks, LANDLOCK_KEY_INODE); 561 646 if (is_access_to_paths_allowed(domain, path, access_request, 562 647 &layer_masks, NULL, 0, NULL, NULL)) 563 648 return 0; ··· 568 651 static inline int current_check_access_path(const struct path *const path, 569 652 const access_mask_t access_request) 570 653 { 571 - const struct landlock_ruleset *const dom = 572 - landlock_get_current_domain(); 654 + const struct landlock_ruleset *const dom = get_current_fs_domain(); 573 655 574 656 if (!dom) 575 657 return 0; ··· 643 727 if (is_nouser_or_private(dir)) 644 728 return true; 645 729 646 - access_dom = init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS, 647 - layer_masks_dom); 730 + access_dom = landlock_init_layer_masks(domain, LANDLOCK_MASK_ACCESS_FS, 731 + layer_masks_dom, 732 + LANDLOCK_KEY_INODE); 648 733 649 734 dget(dir); 650 735 while (true) { 651 736 struct dentry *parent_dentry; 652 737 653 738 /* Gets all layers allowing all domain accesses. */ 654 - if (unmask_layers(find_rule(domain, dir), access_dom, 655 - layer_masks_dom)) { 739 + if (landlock_unmask_layers(find_rule(domain, dir), access_dom, 740 + layer_masks_dom, 741 + ARRAY_SIZE(*layer_masks_dom))) { 656 742 /* 657 743 * Stops when all handled accesses are allowed by at 658 744 * least one rule in each layer. ··· 733 815 struct dentry *const new_dentry, 734 816 const bool removable, const bool exchange) 735 817 { 736 - const struct landlock_ruleset *const dom = 737 - landlock_get_current_domain(); 818 + const struct landlock_ruleset *const dom = get_current_fs_domain(); 738 819 bool allow_parent1, allow_parent2; 739 820 access_mask_t access_request_parent1, access_request_parent2; 740 821 struct path mnt_dir; ··· 767 850 * The LANDLOCK_ACCESS_FS_REFER access right is not required 768 851 * for same-directory referer (i.e. no reparenting). 769 852 */ 770 - access_request_parent1 = init_layer_masks( 853 + access_request_parent1 = landlock_init_layer_masks( 771 854 dom, access_request_parent1 | access_request_parent2, 772 - &layer_masks_parent1); 855 + &layer_masks_parent1, LANDLOCK_KEY_INODE); 773 856 if (is_access_to_paths_allowed( 774 857 dom, new_dir, access_request_parent1, 775 858 &layer_masks_parent1, NULL, 0, NULL, NULL)) ··· 967 1050 const struct path *const path, const char *const type, 968 1051 const unsigned long flags, void *const data) 969 1052 { 970 - if (!landlock_get_current_domain()) 1053 + if (!get_current_fs_domain()) 971 1054 return 0; 972 1055 return -EPERM; 973 1056 } ··· 975 1058 static int hook_move_mount(const struct path *const from_path, 976 1059 const struct path *const to_path) 977 1060 { 978 - if (!landlock_get_current_domain()) 1061 + if (!get_current_fs_domain()) 979 1062 return 0; 980 1063 return -EPERM; 981 1064 } ··· 986 1069 */ 987 1070 static int hook_sb_umount(struct vfsmount *const mnt, const int flags) 988 1071 { 989 - if (!landlock_get_current_domain()) 1072 + if (!get_current_fs_domain()) 990 1073 return 0; 991 1074 return -EPERM; 992 1075 } 993 1076 994 1077 static int hook_sb_remount(struct super_block *const sb, void *const mnt_opts) 995 1078 { 996 - if (!landlock_get_current_domain()) 1079 + if (!get_current_fs_domain()) 997 1080 return 0; 998 1081 return -EPERM; 999 1082 } ··· 1009 1092 static int hook_sb_pivotroot(const struct path *const old_path, 1010 1093 const struct path *const new_path) 1011 1094 { 1012 - if (!landlock_get_current_domain()) 1095 + if (!get_current_fs_domain()) 1013 1096 return 0; 1014 1097 return -EPERM; 1015 1098 } ··· 1045 1128 struct dentry *const dentry, const umode_t mode, 1046 1129 const unsigned int dev) 1047 1130 { 1048 - const struct landlock_ruleset *const dom = 1049 - landlock_get_current_domain(); 1131 + const struct landlock_ruleset *const dom = get_current_fs_domain(); 1050 1132 1051 1133 if (!dom) 1052 1134 return 0; ··· 1124 1208 layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {}; 1125 1209 access_mask_t open_access_request, full_access_request, allowed_access; 1126 1210 const access_mask_t optional_access = LANDLOCK_ACCESS_FS_TRUNCATE; 1127 - const struct landlock_ruleset *const dom = 1128 - landlock_get_current_domain(); 1211 + const struct landlock_ruleset *const dom = get_current_fs_domain(); 1129 1212 1130 1213 if (!dom) 1131 1214 return 0; ··· 1144 1229 1145 1230 if (is_access_to_paths_allowed( 1146 1231 dom, &file->f_path, 1147 - init_layer_masks(dom, full_access_request, &layer_masks), 1232 + landlock_init_layer_masks(dom, full_access_request, 1233 + &layer_masks, LANDLOCK_KEY_INODE), 1148 1234 &layer_masks, NULL, 0, NULL, NULL)) { 1149 1235 allowed_access = full_access_request; 1150 1236 } else {
+6
security/landlock/limits.h
··· 21 21 #define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_TRUNCATE 22 22 #define LANDLOCK_MASK_ACCESS_FS ((LANDLOCK_LAST_ACCESS_FS << 1) - 1) 23 23 #define LANDLOCK_NUM_ACCESS_FS __const_hweight64(LANDLOCK_MASK_ACCESS_FS) 24 + #define LANDLOCK_SHIFT_ACCESS_FS 0 25 + 26 + #define LANDLOCK_LAST_ACCESS_NET LANDLOCK_ACCESS_NET_CONNECT_TCP 27 + #define LANDLOCK_MASK_ACCESS_NET ((LANDLOCK_LAST_ACCESS_NET << 1) - 1) 28 + #define LANDLOCK_NUM_ACCESS_NET __const_hweight64(LANDLOCK_MASK_ACCESS_NET) 29 + #define LANDLOCK_SHIFT_ACCESS_NET LANDLOCK_NUM_ACCESS_FS 24 30 25 31 /* clang-format on */ 26 32
+200
security/landlock/net.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Landlock LSM - Network management and hooks 4 + * 5 + * Copyright © 2022-2023 Huawei Tech. Co., Ltd. 6 + * Copyright © 2022-2023 Microsoft Corporation 7 + */ 8 + 9 + #include <linux/in.h> 10 + #include <linux/net.h> 11 + #include <linux/socket.h> 12 + #include <net/ipv6.h> 13 + 14 + #include "common.h" 15 + #include "cred.h" 16 + #include "limits.h" 17 + #include "net.h" 18 + #include "ruleset.h" 19 + 20 + int landlock_append_net_rule(struct landlock_ruleset *const ruleset, 21 + const u16 port, access_mask_t access_rights) 22 + { 23 + int err; 24 + const struct landlock_id id = { 25 + .key.data = (__force uintptr_t)htons(port), 26 + .type = LANDLOCK_KEY_NET_PORT, 27 + }; 28 + 29 + BUILD_BUG_ON(sizeof(port) > sizeof(id.key.data)); 30 + 31 + /* Transforms relative access rights to absolute ones. */ 32 + access_rights |= LANDLOCK_MASK_ACCESS_NET & 33 + ~landlock_get_net_access_mask(ruleset, 0); 34 + 35 + mutex_lock(&ruleset->lock); 36 + err = landlock_insert_rule(ruleset, id, access_rights); 37 + mutex_unlock(&ruleset->lock); 38 + 39 + return err; 40 + } 41 + 42 + static access_mask_t 43 + get_raw_handled_net_accesses(const struct landlock_ruleset *const domain) 44 + { 45 + access_mask_t access_dom = 0; 46 + size_t layer_level; 47 + 48 + for (layer_level = 0; layer_level < domain->num_layers; layer_level++) 49 + access_dom |= landlock_get_net_access_mask(domain, layer_level); 50 + return access_dom; 51 + } 52 + 53 + static const struct landlock_ruleset *get_current_net_domain(void) 54 + { 55 + const struct landlock_ruleset *const dom = 56 + landlock_get_current_domain(); 57 + 58 + if (!dom || !get_raw_handled_net_accesses(dom)) 59 + return NULL; 60 + 61 + return dom; 62 + } 63 + 64 + static int current_check_access_socket(struct socket *const sock, 65 + struct sockaddr *const address, 66 + const int addrlen, 67 + const access_mask_t access_request) 68 + { 69 + __be16 port; 70 + layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_NET] = {}; 71 + const struct landlock_rule *rule; 72 + access_mask_t handled_access; 73 + struct landlock_id id = { 74 + .type = LANDLOCK_KEY_NET_PORT, 75 + }; 76 + const struct landlock_ruleset *const dom = get_current_net_domain(); 77 + 78 + if (!dom) 79 + return 0; 80 + if (WARN_ON_ONCE(dom->num_layers < 1)) 81 + return -EACCES; 82 + 83 + /* Checks if it's a (potential) TCP socket. */ 84 + if (sock->type != SOCK_STREAM) 85 + return 0; 86 + 87 + /* Checks for minimal header length to safely read sa_family. */ 88 + if (addrlen < offsetofend(typeof(*address), sa_family)) 89 + return -EINVAL; 90 + 91 + switch (address->sa_family) { 92 + case AF_UNSPEC: 93 + case AF_INET: 94 + if (addrlen < sizeof(struct sockaddr_in)) 95 + return -EINVAL; 96 + port = ((struct sockaddr_in *)address)->sin_port; 97 + break; 98 + 99 + #if IS_ENABLED(CONFIG_IPV6) 100 + case AF_INET6: 101 + if (addrlen < SIN6_LEN_RFC2133) 102 + return -EINVAL; 103 + port = ((struct sockaddr_in6 *)address)->sin6_port; 104 + break; 105 + #endif /* IS_ENABLED(CONFIG_IPV6) */ 106 + 107 + default: 108 + return 0; 109 + } 110 + 111 + /* Specific AF_UNSPEC handling. */ 112 + if (address->sa_family == AF_UNSPEC) { 113 + /* 114 + * Connecting to an address with AF_UNSPEC dissolves the TCP 115 + * association, which have the same effect as closing the 116 + * connection while retaining the socket object (i.e., the file 117 + * descriptor). As for dropping privileges, closing 118 + * connections is always allowed. 119 + * 120 + * For a TCP access control system, this request is legitimate. 121 + * Let the network stack handle potential inconsistencies and 122 + * return -EINVAL if needed. 123 + */ 124 + if (access_request == LANDLOCK_ACCESS_NET_CONNECT_TCP) 125 + return 0; 126 + 127 + /* 128 + * For compatibility reason, accept AF_UNSPEC for bind 129 + * accesses (mapped to AF_INET) only if the address is 130 + * INADDR_ANY (cf. __inet_bind). Checking the address is 131 + * required to not wrongfully return -EACCES instead of 132 + * -EAFNOSUPPORT. 133 + * 134 + * We could return 0 and let the network stack handle these 135 + * checks, but it is safer to return a proper error and test 136 + * consistency thanks to kselftest. 137 + */ 138 + if (access_request == LANDLOCK_ACCESS_NET_BIND_TCP) { 139 + /* addrlen has already been checked for AF_UNSPEC. */ 140 + const struct sockaddr_in *const sockaddr = 141 + (struct sockaddr_in *)address; 142 + 143 + if (sock->sk->__sk_common.skc_family != AF_INET) 144 + return -EINVAL; 145 + 146 + if (sockaddr->sin_addr.s_addr != htonl(INADDR_ANY)) 147 + return -EAFNOSUPPORT; 148 + } 149 + } else { 150 + /* 151 + * Checks sa_family consistency to not wrongfully return 152 + * -EACCES instead of -EINVAL. Valid sa_family changes are 153 + * only (from AF_INET or AF_INET6) to AF_UNSPEC. 154 + * 155 + * We could return 0 and let the network stack handle this 156 + * check, but it is safer to return a proper error and test 157 + * consistency thanks to kselftest. 158 + */ 159 + if (address->sa_family != sock->sk->__sk_common.skc_family) 160 + return -EINVAL; 161 + } 162 + 163 + id.key.data = (__force uintptr_t)port; 164 + BUILD_BUG_ON(sizeof(port) > sizeof(id.key.data)); 165 + 166 + rule = landlock_find_rule(dom, id); 167 + handled_access = landlock_init_layer_masks( 168 + dom, access_request, &layer_masks, LANDLOCK_KEY_NET_PORT); 169 + if (landlock_unmask_layers(rule, handled_access, &layer_masks, 170 + ARRAY_SIZE(layer_masks))) 171 + return 0; 172 + 173 + return -EACCES; 174 + } 175 + 176 + static int hook_socket_bind(struct socket *const sock, 177 + struct sockaddr *const address, const int addrlen) 178 + { 179 + return current_check_access_socket(sock, address, addrlen, 180 + LANDLOCK_ACCESS_NET_BIND_TCP); 181 + } 182 + 183 + static int hook_socket_connect(struct socket *const sock, 184 + struct sockaddr *const address, 185 + const int addrlen) 186 + { 187 + return current_check_access_socket(sock, address, addrlen, 188 + LANDLOCK_ACCESS_NET_CONNECT_TCP); 189 + } 190 + 191 + static struct security_hook_list landlock_hooks[] __ro_after_init = { 192 + LSM_HOOK_INIT(socket_bind, hook_socket_bind), 193 + LSM_HOOK_INIT(socket_connect, hook_socket_connect), 194 + }; 195 + 196 + __init void landlock_add_net_hooks(void) 197 + { 198 + security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks), 199 + LANDLOCK_NAME); 200 + }
+33
security/landlock/net.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Landlock LSM - Network management and hooks 4 + * 5 + * Copyright © 2022-2023 Huawei Tech. Co., Ltd. 6 + */ 7 + 8 + #ifndef _SECURITY_LANDLOCK_NET_H 9 + #define _SECURITY_LANDLOCK_NET_H 10 + 11 + #include "common.h" 12 + #include "ruleset.h" 13 + #include "setup.h" 14 + 15 + #if IS_ENABLED(CONFIG_INET) 16 + __init void landlock_add_net_hooks(void); 17 + 18 + int landlock_append_net_rule(struct landlock_ruleset *const ruleset, 19 + const u16 port, access_mask_t access_rights); 20 + #else /* IS_ENABLED(CONFIG_INET) */ 21 + static inline void landlock_add_net_hooks(void) 22 + { 23 + } 24 + 25 + static inline int 26 + landlock_append_net_rule(struct landlock_ruleset *const ruleset, const u16 port, 27 + access_mask_t access_rights) 28 + { 29 + return -EAFNOSUPPORT; 30 + } 31 + #endif /* IS_ENABLED(CONFIG_INET) */ 32 + 33 + #endif /* _SECURITY_LANDLOCK_NET_H */
+334 -71
security/landlock/ruleset.c
··· 29 29 struct landlock_ruleset *new_ruleset; 30 30 31 31 new_ruleset = 32 - kzalloc(struct_size(new_ruleset, fs_access_masks, num_layers), 32 + kzalloc(struct_size(new_ruleset, access_masks, num_layers), 33 33 GFP_KERNEL_ACCOUNT); 34 34 if (!new_ruleset) 35 35 return ERR_PTR(-ENOMEM); 36 36 refcount_set(&new_ruleset->usage, 1); 37 37 mutex_init(&new_ruleset->lock); 38 - new_ruleset->root = RB_ROOT; 38 + new_ruleset->root_inode = RB_ROOT; 39 + 40 + #if IS_ENABLED(CONFIG_INET) 41 + new_ruleset->root_net_port = RB_ROOT; 42 + #endif /* IS_ENABLED(CONFIG_INET) */ 43 + 39 44 new_ruleset->num_layers = num_layers; 40 45 /* 41 46 * hierarchy = NULL 42 47 * num_rules = 0 43 - * fs_access_masks[] = 0 48 + * access_masks[] = 0 44 49 */ 45 50 return new_ruleset; 46 51 } 47 52 48 53 struct landlock_ruleset * 49 - landlock_create_ruleset(const access_mask_t fs_access_mask) 54 + landlock_create_ruleset(const access_mask_t fs_access_mask, 55 + const access_mask_t net_access_mask) 50 56 { 51 57 struct landlock_ruleset *new_ruleset; 52 58 53 59 /* Informs about useless ruleset. */ 54 - if (!fs_access_mask) 60 + if (!fs_access_mask && !net_access_mask) 55 61 return ERR_PTR(-ENOMSG); 56 62 new_ruleset = create_ruleset(1); 57 - if (!IS_ERR(new_ruleset)) 58 - new_ruleset->fs_access_masks[0] = fs_access_mask; 63 + if (IS_ERR(new_ruleset)) 64 + return new_ruleset; 65 + if (fs_access_mask) 66 + landlock_add_fs_access_mask(new_ruleset, fs_access_mask, 0); 67 + if (net_access_mask) 68 + landlock_add_net_access_mask(new_ruleset, net_access_mask, 0); 59 69 return new_ruleset; 60 70 } 61 71 ··· 78 68 BUILD_BUG_ON(rule.num_layers < LANDLOCK_MAX_NUM_LAYERS); 79 69 } 80 70 71 + static bool is_object_pointer(const enum landlock_key_type key_type) 72 + { 73 + switch (key_type) { 74 + case LANDLOCK_KEY_INODE: 75 + return true; 76 + 77 + #if IS_ENABLED(CONFIG_INET) 78 + case LANDLOCK_KEY_NET_PORT: 79 + return false; 80 + #endif /* IS_ENABLED(CONFIG_INET) */ 81 + 82 + default: 83 + WARN_ON_ONCE(1); 84 + return false; 85 + } 86 + } 87 + 81 88 static struct landlock_rule * 82 - create_rule(struct landlock_object *const object, 89 + create_rule(const struct landlock_id id, 83 90 const struct landlock_layer (*const layers)[], const u32 num_layers, 84 91 const struct landlock_layer *const new_layer) 85 92 { ··· 117 90 if (!new_rule) 118 91 return ERR_PTR(-ENOMEM); 119 92 RB_CLEAR_NODE(&new_rule->node); 120 - landlock_get_object(object); 121 - new_rule->object = object; 93 + if (is_object_pointer(id.type)) { 94 + /* This should be catched by insert_rule(). */ 95 + WARN_ON_ONCE(!id.key.object); 96 + landlock_get_object(id.key.object); 97 + } 98 + 99 + new_rule->key = id.key; 122 100 new_rule->num_layers = new_num_layers; 123 101 /* Copies the original layer stack. */ 124 102 memcpy(new_rule->layers, layers, ··· 134 102 return new_rule; 135 103 } 136 104 137 - static void free_rule(struct landlock_rule *const rule) 105 + static struct rb_root *get_root(struct landlock_ruleset *const ruleset, 106 + const enum landlock_key_type key_type) 107 + { 108 + switch (key_type) { 109 + case LANDLOCK_KEY_INODE: 110 + return &ruleset->root_inode; 111 + 112 + #if IS_ENABLED(CONFIG_INET) 113 + case LANDLOCK_KEY_NET_PORT: 114 + return &ruleset->root_net_port; 115 + #endif /* IS_ENABLED(CONFIG_INET) */ 116 + 117 + default: 118 + WARN_ON_ONCE(1); 119 + return ERR_PTR(-EINVAL); 120 + } 121 + } 122 + 123 + static void free_rule(struct landlock_rule *const rule, 124 + const enum landlock_key_type key_type) 138 125 { 139 126 might_sleep(); 140 127 if (!rule) 141 128 return; 142 - landlock_put_object(rule->object); 129 + if (is_object_pointer(key_type)) 130 + landlock_put_object(rule->key.object); 143 131 kfree(rule); 144 132 } 145 133 ··· 169 117 .num_rules = ~0, 170 118 .num_layers = ~0, 171 119 }; 172 - typeof(ruleset.fs_access_masks[0]) fs_access_mask = ~0; 120 + typeof(ruleset.access_masks[0]) access_masks = ~0; 173 121 174 122 BUILD_BUG_ON(ruleset.num_rules < LANDLOCK_MAX_NUM_RULES); 175 123 BUILD_BUG_ON(ruleset.num_layers < LANDLOCK_MAX_NUM_LAYERS); 176 - BUILD_BUG_ON(fs_access_mask < LANDLOCK_MASK_ACCESS_FS); 124 + BUILD_BUG_ON(access_masks < 125 + ((LANDLOCK_MASK_ACCESS_FS << LANDLOCK_SHIFT_ACCESS_FS) | 126 + (LANDLOCK_MASK_ACCESS_NET << LANDLOCK_SHIFT_ACCESS_NET))); 177 127 } 178 128 179 129 /** 180 130 * insert_rule - Create and insert a rule in a ruleset 181 131 * 182 132 * @ruleset: The ruleset to be updated. 183 - * @object: The object to build the new rule with. The underlying kernel 184 - * object must be held by the caller. 133 + * @id: The ID to build the new rule with. The underlying kernel object, if 134 + * any, must be held by the caller. 185 135 * @layers: One or multiple layers to be copied into the new rule. 186 136 * @num_layers: The number of @layers entries. 187 137 * ··· 197 143 * access rights. 198 144 */ 199 145 static int insert_rule(struct landlock_ruleset *const ruleset, 200 - struct landlock_object *const object, 146 + const struct landlock_id id, 201 147 const struct landlock_layer (*const layers)[], 202 - size_t num_layers) 148 + const size_t num_layers) 203 149 { 204 150 struct rb_node **walker_node; 205 151 struct rb_node *parent_node = NULL; 206 152 struct landlock_rule *new_rule; 153 + struct rb_root *root; 207 154 208 155 might_sleep(); 209 156 lockdep_assert_held(&ruleset->lock); 210 - if (WARN_ON_ONCE(!object || !layers)) 157 + if (WARN_ON_ONCE(!layers)) 211 158 return -ENOENT; 212 - walker_node = &(ruleset->root.rb_node); 159 + 160 + if (is_object_pointer(id.type) && WARN_ON_ONCE(!id.key.object)) 161 + return -ENOENT; 162 + 163 + root = get_root(ruleset, id.type); 164 + if (IS_ERR(root)) 165 + return PTR_ERR(root); 166 + 167 + walker_node = &root->rb_node; 213 168 while (*walker_node) { 214 169 struct landlock_rule *const this = 215 170 rb_entry(*walker_node, struct landlock_rule, node); 216 171 217 - if (this->object != object) { 172 + if (this->key.data != id.key.data) { 218 173 parent_node = *walker_node; 219 - if (this->object < object) 174 + if (this->key.data < id.key.data) 220 175 walker_node = &((*walker_node)->rb_right); 221 176 else 222 177 walker_node = &((*walker_node)->rb_left); ··· 257 194 * Intersects access rights when it is a merge between a 258 195 * ruleset and a domain. 259 196 */ 260 - new_rule = create_rule(object, &this->layers, this->num_layers, 197 + new_rule = create_rule(id, &this->layers, this->num_layers, 261 198 &(*layers)[0]); 262 199 if (IS_ERR(new_rule)) 263 200 return PTR_ERR(new_rule); 264 - rb_replace_node(&this->node, &new_rule->node, &ruleset->root); 265 - free_rule(this); 201 + rb_replace_node(&this->node, &new_rule->node, root); 202 + free_rule(this, id.type); 266 203 return 0; 267 204 } 268 205 269 - /* There is no match for @object. */ 206 + /* There is no match for @id. */ 270 207 build_check_ruleset(); 271 208 if (ruleset->num_rules >= LANDLOCK_MAX_NUM_RULES) 272 209 return -E2BIG; 273 - new_rule = create_rule(object, layers, num_layers, NULL); 210 + new_rule = create_rule(id, layers, num_layers, NULL); 274 211 if (IS_ERR(new_rule)) 275 212 return PTR_ERR(new_rule); 276 213 rb_link_node(&new_rule->node, parent_node, walker_node); 277 - rb_insert_color(&new_rule->node, &ruleset->root); 214 + rb_insert_color(&new_rule->node, root); 278 215 ruleset->num_rules++; 279 216 return 0; 280 217 } ··· 292 229 293 230 /* @ruleset must be locked by the caller. */ 294 231 int landlock_insert_rule(struct landlock_ruleset *const ruleset, 295 - struct landlock_object *const object, 232 + const struct landlock_id id, 296 233 const access_mask_t access) 297 234 { 298 235 struct landlock_layer layers[] = { { ··· 302 239 } }; 303 240 304 241 build_check_layer(); 305 - return insert_rule(ruleset, object, &layers, ARRAY_SIZE(layers)); 242 + return insert_rule(ruleset, id, &layers, ARRAY_SIZE(layers)); 306 243 } 307 244 308 245 static inline void get_hierarchy(struct landlock_hierarchy *const hierarchy) ··· 321 258 } 322 259 } 323 260 261 + static int merge_tree(struct landlock_ruleset *const dst, 262 + struct landlock_ruleset *const src, 263 + const enum landlock_key_type key_type) 264 + { 265 + struct landlock_rule *walker_rule, *next_rule; 266 + struct rb_root *src_root; 267 + int err = 0; 268 + 269 + might_sleep(); 270 + lockdep_assert_held(&dst->lock); 271 + lockdep_assert_held(&src->lock); 272 + 273 + src_root = get_root(src, key_type); 274 + if (IS_ERR(src_root)) 275 + return PTR_ERR(src_root); 276 + 277 + /* Merges the @src tree. */ 278 + rbtree_postorder_for_each_entry_safe(walker_rule, next_rule, src_root, 279 + node) { 280 + struct landlock_layer layers[] = { { 281 + .level = dst->num_layers, 282 + } }; 283 + const struct landlock_id id = { 284 + .key = walker_rule->key, 285 + .type = key_type, 286 + }; 287 + 288 + if (WARN_ON_ONCE(walker_rule->num_layers != 1)) 289 + return -EINVAL; 290 + 291 + if (WARN_ON_ONCE(walker_rule->layers[0].level != 0)) 292 + return -EINVAL; 293 + 294 + layers[0].access = walker_rule->layers[0].access; 295 + 296 + err = insert_rule(dst, id, &layers, ARRAY_SIZE(layers)); 297 + if (err) 298 + return err; 299 + } 300 + return err; 301 + } 302 + 324 303 static int merge_ruleset(struct landlock_ruleset *const dst, 325 304 struct landlock_ruleset *const src) 326 305 { 327 - struct landlock_rule *walker_rule, *next_rule; 328 306 int err = 0; 329 307 330 308 might_sleep(); ··· 385 281 err = -EINVAL; 386 282 goto out_unlock; 387 283 } 388 - dst->fs_access_masks[dst->num_layers - 1] = src->fs_access_masks[0]; 284 + dst->access_masks[dst->num_layers - 1] = src->access_masks[0]; 389 285 390 - /* Merges the @src tree. */ 391 - rbtree_postorder_for_each_entry_safe(walker_rule, next_rule, &src->root, 392 - node) { 393 - struct landlock_layer layers[] = { { 394 - .level = dst->num_layers, 395 - } }; 286 + /* Merges the @src inode tree. */ 287 + err = merge_tree(dst, src, LANDLOCK_KEY_INODE); 288 + if (err) 289 + goto out_unlock; 396 290 397 - if (WARN_ON_ONCE(walker_rule->num_layers != 1)) { 398 - err = -EINVAL; 399 - goto out_unlock; 400 - } 401 - if (WARN_ON_ONCE(walker_rule->layers[0].level != 0)) { 402 - err = -EINVAL; 403 - goto out_unlock; 404 - } 405 - layers[0].access = walker_rule->layers[0].access; 406 - err = insert_rule(dst, walker_rule->object, &layers, 407 - ARRAY_SIZE(layers)); 408 - if (err) 409 - goto out_unlock; 410 - } 291 + #if IS_ENABLED(CONFIG_INET) 292 + /* Merges the @src network port tree. */ 293 + err = merge_tree(dst, src, LANDLOCK_KEY_NET_PORT); 294 + if (err) 295 + goto out_unlock; 296 + #endif /* IS_ENABLED(CONFIG_INET) */ 411 297 412 298 out_unlock: 413 299 mutex_unlock(&src->lock); ··· 405 311 return err; 406 312 } 407 313 314 + static int inherit_tree(struct landlock_ruleset *const parent, 315 + struct landlock_ruleset *const child, 316 + const enum landlock_key_type key_type) 317 + { 318 + struct landlock_rule *walker_rule, *next_rule; 319 + struct rb_root *parent_root; 320 + int err = 0; 321 + 322 + might_sleep(); 323 + lockdep_assert_held(&parent->lock); 324 + lockdep_assert_held(&child->lock); 325 + 326 + parent_root = get_root(parent, key_type); 327 + if (IS_ERR(parent_root)) 328 + return PTR_ERR(parent_root); 329 + 330 + /* Copies the @parent inode or network tree. */ 331 + rbtree_postorder_for_each_entry_safe(walker_rule, next_rule, 332 + parent_root, node) { 333 + const struct landlock_id id = { 334 + .key = walker_rule->key, 335 + .type = key_type, 336 + }; 337 + 338 + err = insert_rule(child, id, &walker_rule->layers, 339 + walker_rule->num_layers); 340 + if (err) 341 + return err; 342 + } 343 + return err; 344 + } 345 + 408 346 static int inherit_ruleset(struct landlock_ruleset *const parent, 409 347 struct landlock_ruleset *const child) 410 348 { 411 - struct landlock_rule *walker_rule, *next_rule; 412 349 int err = 0; 413 350 414 351 might_sleep(); ··· 450 325 mutex_lock(&child->lock); 451 326 mutex_lock_nested(&parent->lock, SINGLE_DEPTH_NESTING); 452 327 453 - /* Copies the @parent tree. */ 454 - rbtree_postorder_for_each_entry_safe(walker_rule, next_rule, 455 - &parent->root, node) { 456 - err = insert_rule(child, walker_rule->object, 457 - &walker_rule->layers, 458 - walker_rule->num_layers); 459 - if (err) 460 - goto out_unlock; 461 - } 328 + /* Copies the @parent inode tree. */ 329 + err = inherit_tree(parent, child, LANDLOCK_KEY_INODE); 330 + if (err) 331 + goto out_unlock; 332 + 333 + #if IS_ENABLED(CONFIG_INET) 334 + /* Copies the @parent network port tree. */ 335 + err = inherit_tree(parent, child, LANDLOCK_KEY_NET_PORT); 336 + if (err) 337 + goto out_unlock; 338 + #endif /* IS_ENABLED(CONFIG_INET) */ 462 339 463 340 if (WARN_ON_ONCE(child->num_layers <= parent->num_layers)) { 464 341 err = -EINVAL; 465 342 goto out_unlock; 466 343 } 467 344 /* Copies the parent layer stack and leaves a space for the new layer. */ 468 - memcpy(child->fs_access_masks, parent->fs_access_masks, 469 - flex_array_size(parent, fs_access_masks, parent->num_layers)); 345 + memcpy(child->access_masks, parent->access_masks, 346 + flex_array_size(parent, access_masks, parent->num_layers)); 470 347 471 348 if (WARN_ON_ONCE(!parent->hierarchy)) { 472 349 err = -EINVAL; ··· 488 361 struct landlock_rule *freeme, *next; 489 362 490 363 might_sleep(); 491 - rbtree_postorder_for_each_entry_safe(freeme, next, &ruleset->root, node) 492 - free_rule(freeme); 364 + rbtree_postorder_for_each_entry_safe(freeme, next, &ruleset->root_inode, 365 + node) 366 + free_rule(freeme, LANDLOCK_KEY_INODE); 367 + 368 + #if IS_ENABLED(CONFIG_INET) 369 + rbtree_postorder_for_each_entry_safe(freeme, next, 370 + &ruleset->root_net_port, node) 371 + free_rule(freeme, LANDLOCK_KEY_NET_PORT); 372 + #endif /* IS_ENABLED(CONFIG_INET) */ 373 + 493 374 put_hierarchy(ruleset->hierarchy); 494 375 kfree(ruleset); 495 376 } ··· 588 453 */ 589 454 const struct landlock_rule * 590 455 landlock_find_rule(const struct landlock_ruleset *const ruleset, 591 - const struct landlock_object *const object) 456 + const struct landlock_id id) 592 457 { 458 + const struct rb_root *root; 593 459 const struct rb_node *node; 594 460 595 - if (!object) 461 + root = get_root((struct landlock_ruleset *)ruleset, id.type); 462 + if (IS_ERR(root)) 596 463 return NULL; 597 - node = ruleset->root.rb_node; 464 + node = root->rb_node; 465 + 598 466 while (node) { 599 467 struct landlock_rule *this = 600 468 rb_entry(node, struct landlock_rule, node); 601 469 602 - if (this->object == object) 470 + if (this->key.data == id.key.data) 603 471 return this; 604 - if (this->object < object) 472 + if (this->key.data < id.key.data) 605 473 node = node->rb_right; 606 474 else 607 475 node = node->rb_left; 608 476 } 609 477 return NULL; 478 + } 479 + 480 + /* 481 + * @layer_masks is read and may be updated according to the access request and 482 + * the matching rule. 483 + * @masks_array_size must be equal to ARRAY_SIZE(*layer_masks). 484 + * 485 + * Returns true if the request is allowed (i.e. relevant layer masks for the 486 + * request are empty). 487 + */ 488 + bool landlock_unmask_layers(const struct landlock_rule *const rule, 489 + const access_mask_t access_request, 490 + layer_mask_t (*const layer_masks)[], 491 + const size_t masks_array_size) 492 + { 493 + size_t layer_level; 494 + 495 + if (!access_request || !layer_masks) 496 + return true; 497 + if (!rule) 498 + return false; 499 + 500 + /* 501 + * An access is granted if, for each policy layer, at least one rule 502 + * encountered on the pathwalk grants the requested access, 503 + * regardless of its position in the layer stack. We must then check 504 + * the remaining layers for each inode, from the first added layer to 505 + * the last one. When there is multiple requested accesses, for each 506 + * policy layer, the full set of requested accesses may not be granted 507 + * by only one rule, but by the union (binary OR) of multiple rules. 508 + * E.g. /a/b <execute> + /a <read> => /a/b <execute + read> 509 + */ 510 + for (layer_level = 0; layer_level < rule->num_layers; layer_level++) { 511 + const struct landlock_layer *const layer = 512 + &rule->layers[layer_level]; 513 + const layer_mask_t layer_bit = BIT_ULL(layer->level - 1); 514 + const unsigned long access_req = access_request; 515 + unsigned long access_bit; 516 + bool is_empty; 517 + 518 + /* 519 + * Records in @layer_masks which layer grants access to each 520 + * requested access. 521 + */ 522 + is_empty = true; 523 + for_each_set_bit(access_bit, &access_req, masks_array_size) { 524 + if (layer->access & BIT_ULL(access_bit)) 525 + (*layer_masks)[access_bit] &= ~layer_bit; 526 + is_empty = is_empty && !(*layer_masks)[access_bit]; 527 + } 528 + if (is_empty) 529 + return true; 530 + } 531 + return false; 532 + } 533 + 534 + typedef access_mask_t 535 + get_access_mask_t(const struct landlock_ruleset *const ruleset, 536 + const u16 layer_level); 537 + 538 + /** 539 + * landlock_init_layer_masks - Initialize layer masks from an access request 540 + * 541 + * Populates @layer_masks such that for each access right in @access_request, 542 + * the bits for all the layers are set where this access right is handled. 543 + * 544 + * @domain: The domain that defines the current restrictions. 545 + * @access_request: The requested access rights to check. 546 + * @layer_masks: It must contain %LANDLOCK_NUM_ACCESS_FS or 547 + * %LANDLOCK_NUM_ACCESS_NET elements according to @key_type. 548 + * @key_type: The key type to switch between access masks of different types. 549 + * 550 + * Returns: An access mask where each access right bit is set which is handled 551 + * in any of the active layers in @domain. 552 + */ 553 + access_mask_t 554 + landlock_init_layer_masks(const struct landlock_ruleset *const domain, 555 + const access_mask_t access_request, 556 + layer_mask_t (*const layer_masks)[], 557 + const enum landlock_key_type key_type) 558 + { 559 + access_mask_t handled_accesses = 0; 560 + size_t layer_level, num_access; 561 + get_access_mask_t *get_access_mask; 562 + 563 + switch (key_type) { 564 + case LANDLOCK_KEY_INODE: 565 + get_access_mask = landlock_get_fs_access_mask; 566 + num_access = LANDLOCK_NUM_ACCESS_FS; 567 + break; 568 + 569 + #if IS_ENABLED(CONFIG_INET) 570 + case LANDLOCK_KEY_NET_PORT: 571 + get_access_mask = landlock_get_net_access_mask; 572 + num_access = LANDLOCK_NUM_ACCESS_NET; 573 + break; 574 + #endif /* IS_ENABLED(CONFIG_INET) */ 575 + 576 + default: 577 + WARN_ON_ONCE(1); 578 + return 0; 579 + } 580 + 581 + memset(layer_masks, 0, 582 + array_size(sizeof((*layer_masks)[0]), num_access)); 583 + 584 + /* An empty access request can happen because of O_WRONLY | O_RDWR. */ 585 + if (!access_request) 586 + return 0; 587 + 588 + /* Saves all handled accesses per layer. */ 589 + for (layer_level = 0; layer_level < domain->num_layers; layer_level++) { 590 + const unsigned long access_req = access_request; 591 + unsigned long access_bit; 592 + 593 + for_each_set_bit(access_bit, &access_req, num_access) { 594 + if (BIT_ULL(access_bit) & 595 + get_access_mask(domain, layer_level)) { 596 + (*layer_masks)[access_bit] |= 597 + BIT_ULL(layer_level); 598 + handled_accesses |= BIT_ULL(access_bit); 599 + } 600 + } 601 + } 602 + return handled_accesses; 610 603 }
+164 -21
security/landlock/ruleset.h
··· 15 15 #include <linux/rbtree.h> 16 16 #include <linux/refcount.h> 17 17 #include <linux/workqueue.h> 18 + #include <uapi/linux/landlock.h> 18 19 19 20 #include "limits.h" 20 21 #include "object.h" 21 22 23 + /* 24 + * All access rights that are denied by default whether they are handled or not 25 + * by a ruleset/layer. This must be ORed with all ruleset->access_masks[] 26 + * entries when we need to get the absolute handled access masks. 27 + */ 28 + /* clang-format off */ 29 + #define LANDLOCK_ACCESS_FS_INITIALLY_DENIED ( \ 30 + LANDLOCK_ACCESS_FS_REFER) 31 + /* clang-format on */ 32 + 22 33 typedef u16 access_mask_t; 23 34 /* Makes sure all filesystem access rights can be stored. */ 24 35 static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_FS); 36 + /* Makes sure all network access rights can be stored. */ 37 + static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_NET); 25 38 /* Makes sure for_each_set_bit() and for_each_clear_bit() calls are OK. */ 26 39 static_assert(sizeof(unsigned long) >= sizeof(access_mask_t)); 40 + 41 + /* Ruleset access masks. */ 42 + typedef u32 access_masks_t; 43 + /* Makes sure all ruleset access rights can be stored. */ 44 + static_assert(BITS_PER_TYPE(access_masks_t) >= 45 + LANDLOCK_NUM_ACCESS_FS + LANDLOCK_NUM_ACCESS_NET); 27 46 28 47 typedef u16 layer_mask_t; 29 48 /* Makes sure all layers can be checked. */ ··· 64 45 }; 65 46 66 47 /** 48 + * union landlock_key - Key of a ruleset's red-black tree 49 + */ 50 + union landlock_key { 51 + /** 52 + * @object: Pointer to identify a kernel object (e.g. an inode). 53 + */ 54 + struct landlock_object *object; 55 + /** 56 + * @data: Raw data to identify an arbitrary 32-bit value 57 + * (e.g. a TCP port). 58 + */ 59 + uintptr_t data; 60 + }; 61 + 62 + /** 63 + * enum landlock_key_type - Type of &union landlock_key 64 + */ 65 + enum landlock_key_type { 66 + /** 67 + * @LANDLOCK_KEY_INODE: Type of &landlock_ruleset.root_inode's node 68 + * keys. 69 + */ 70 + LANDLOCK_KEY_INODE = 1, 71 + /** 72 + * @LANDLOCK_KEY_NET_PORT: Type of &landlock_ruleset.root_net_port's 73 + * node keys. 74 + */ 75 + LANDLOCK_KEY_NET_PORT, 76 + }; 77 + 78 + /** 79 + * struct landlock_id - Unique rule identifier for a ruleset 80 + */ 81 + struct landlock_id { 82 + /** 83 + * @key: Identifies either a kernel object (e.g. an inode) or 84 + * a raw value (e.g. a TCP port). 85 + */ 86 + union landlock_key key; 87 + /** 88 + * @type: Type of a landlock_ruleset's root tree. 89 + */ 90 + const enum landlock_key_type type; 91 + }; 92 + 93 + /** 67 94 * struct landlock_rule - Access rights tied to an object 68 95 */ 69 96 struct landlock_rule { ··· 118 53 */ 119 54 struct rb_node node; 120 55 /** 121 - * @object: Pointer to identify a kernel object (e.g. an inode). This 122 - * is used as a key for this ruleset element. This pointer is set once 123 - * and never modified. It always points to an allocated object because 124 - * each rule increments the refcount of its object. 56 + * @key: A union to identify either a kernel object (e.g. an inode) or 57 + * a raw data value (e.g. a network socket port). This is used as a key 58 + * for this ruleset element. The pointer is set once and never 59 + * modified. It always points to an allocated object because each rule 60 + * increments the refcount of its object. 125 61 */ 126 - struct landlock_object *object; 62 + union landlock_key key; 127 63 /** 128 64 * @num_layers: Number of entries in @layers. 129 65 */ ··· 160 94 */ 161 95 struct landlock_ruleset { 162 96 /** 163 - * @root: Root of a red-black tree containing &struct landlock_rule 164 - * nodes. Once a ruleset is tied to a process (i.e. as a domain), this 165 - * tree is immutable until @usage reaches zero. 97 + * @root_inode: Root of a red-black tree containing &struct 98 + * landlock_rule nodes with inode object. Once a ruleset is tied to a 99 + * process (i.e. as a domain), this tree is immutable until @usage 100 + * reaches zero. 166 101 */ 167 - struct rb_root root; 102 + struct rb_root root_inode; 103 + 104 + #if IS_ENABLED(CONFIG_INET) 105 + /** 106 + * @root_net_port: Root of a red-black tree containing &struct 107 + * landlock_rule nodes with network port. Once a ruleset is tied to a 108 + * process (i.e. as a domain), this tree is immutable until @usage 109 + * reaches zero. 110 + */ 111 + struct rb_root root_net_port; 112 + #endif /* IS_ENABLED(CONFIG_INET) */ 113 + 168 114 /** 169 115 * @hierarchy: Enables hierarchy identification even when a parent 170 116 * domain vanishes. This is needed for the ptrace protection. ··· 188 110 * section. This is only used by 189 111 * landlock_put_ruleset_deferred() when @usage reaches zero. 190 112 * The fields @lock, @usage, @num_rules, @num_layers and 191 - * @fs_access_masks are then unused. 113 + * @access_masks are then unused. 192 114 */ 193 115 struct work_struct work_free; 194 116 struct { ··· 215 137 */ 216 138 u32 num_layers; 217 139 /** 218 - * @fs_access_masks: Contains the subset of filesystem 219 - * actions that are restricted by a ruleset. A domain 220 - * saves all layers of merged rulesets in a stack 221 - * (FAM), starting from the first layer to the last 222 - * one. These layers are used when merging rulesets, 223 - * for user space backward compatibility (i.e. 224 - * future-proof), and to properly handle merged 140 + * @access_masks: Contains the subset of filesystem and 141 + * network actions that are restricted by a ruleset. 142 + * A domain saves all layers of merged rulesets in a 143 + * stack (FAM), starting from the first layer to the 144 + * last one. These layers are used when merging 145 + * rulesets, for user space backward compatibility 146 + * (i.e. future-proof), and to properly handle merged 225 147 * rulesets without overlapping access rights. These 226 148 * layers are set once and never changed for the 227 149 * lifetime of the ruleset. 228 150 */ 229 - access_mask_t fs_access_masks[]; 151 + access_masks_t access_masks[]; 230 152 }; 231 153 }; 232 154 }; 233 155 234 156 struct landlock_ruleset * 235 - landlock_create_ruleset(const access_mask_t fs_access_mask); 157 + landlock_create_ruleset(const access_mask_t access_mask_fs, 158 + const access_mask_t access_mask_net); 236 159 237 160 void landlock_put_ruleset(struct landlock_ruleset *const ruleset); 238 161 void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset); 239 162 240 163 int landlock_insert_rule(struct landlock_ruleset *const ruleset, 241 - struct landlock_object *const object, 164 + const struct landlock_id id, 242 165 const access_mask_t access); 243 166 244 167 struct landlock_ruleset * ··· 248 169 249 170 const struct landlock_rule * 250 171 landlock_find_rule(const struct landlock_ruleset *const ruleset, 251 - const struct landlock_object *const object); 172 + const struct landlock_id id); 252 173 253 174 static inline void landlock_get_ruleset(struct landlock_ruleset *const ruleset) 254 175 { 255 176 if (ruleset) 256 177 refcount_inc(&ruleset->usage); 257 178 } 179 + 180 + static inline void 181 + landlock_add_fs_access_mask(struct landlock_ruleset *const ruleset, 182 + const access_mask_t fs_access_mask, 183 + const u16 layer_level) 184 + { 185 + access_mask_t fs_mask = fs_access_mask & LANDLOCK_MASK_ACCESS_FS; 186 + 187 + /* Should already be checked in sys_landlock_create_ruleset(). */ 188 + WARN_ON_ONCE(fs_access_mask != fs_mask); 189 + ruleset->access_masks[layer_level] |= 190 + (fs_mask << LANDLOCK_SHIFT_ACCESS_FS); 191 + } 192 + 193 + static inline void 194 + landlock_add_net_access_mask(struct landlock_ruleset *const ruleset, 195 + const access_mask_t net_access_mask, 196 + const u16 layer_level) 197 + { 198 + access_mask_t net_mask = net_access_mask & LANDLOCK_MASK_ACCESS_NET; 199 + 200 + /* Should already be checked in sys_landlock_create_ruleset(). */ 201 + WARN_ON_ONCE(net_access_mask != net_mask); 202 + ruleset->access_masks[layer_level] |= 203 + (net_mask << LANDLOCK_SHIFT_ACCESS_NET); 204 + } 205 + 206 + static inline access_mask_t 207 + landlock_get_raw_fs_access_mask(const struct landlock_ruleset *const ruleset, 208 + const u16 layer_level) 209 + { 210 + return (ruleset->access_masks[layer_level] >> 211 + LANDLOCK_SHIFT_ACCESS_FS) & 212 + LANDLOCK_MASK_ACCESS_FS; 213 + } 214 + 215 + static inline access_mask_t 216 + landlock_get_fs_access_mask(const struct landlock_ruleset *const ruleset, 217 + const u16 layer_level) 218 + { 219 + /* Handles all initially denied by default access rights. */ 220 + return landlock_get_raw_fs_access_mask(ruleset, layer_level) | 221 + LANDLOCK_ACCESS_FS_INITIALLY_DENIED; 222 + } 223 + 224 + static inline access_mask_t 225 + landlock_get_net_access_mask(const struct landlock_ruleset *const ruleset, 226 + const u16 layer_level) 227 + { 228 + return (ruleset->access_masks[layer_level] >> 229 + LANDLOCK_SHIFT_ACCESS_NET) & 230 + LANDLOCK_MASK_ACCESS_NET; 231 + } 232 + 233 + bool landlock_unmask_layers(const struct landlock_rule *const rule, 234 + const access_mask_t access_request, 235 + layer_mask_t (*const layer_masks)[], 236 + const size_t masks_array_size); 237 + 238 + access_mask_t 239 + landlock_init_layer_masks(const struct landlock_ruleset *const domain, 240 + const access_mask_t access_request, 241 + layer_mask_t (*const layer_masks)[], 242 + const enum landlock_key_type key_type); 258 243 259 244 #endif /* _SECURITY_LANDLOCK_RULESET_H */
+2
security/landlock/setup.c
··· 12 12 #include "common.h" 13 13 #include "cred.h" 14 14 #include "fs.h" 15 + #include "net.h" 15 16 #include "ptrace.h" 16 17 #include "setup.h" 17 18 ··· 30 29 landlock_add_cred_hooks(); 31 30 landlock_add_ptrace_hooks(); 32 31 landlock_add_fs_hooks(); 32 + landlock_add_net_hooks(); 33 33 landlock_initialized = true; 34 34 pr_info("Up and running.\n"); 35 35 return 0;
+107 -51
security/landlock/syscalls.c
··· 29 29 #include "cred.h" 30 30 #include "fs.h" 31 31 #include "limits.h" 32 + #include "net.h" 32 33 #include "ruleset.h" 33 34 #include "setup.h" 34 35 ··· 75 74 { 76 75 struct landlock_ruleset_attr ruleset_attr; 77 76 struct landlock_path_beneath_attr path_beneath_attr; 78 - size_t ruleset_size, path_beneath_size; 77 + struct landlock_net_port_attr net_port_attr; 78 + size_t ruleset_size, path_beneath_size, net_port_size; 79 79 80 80 /* 81 81 * For each user space ABI structures, first checks that there is no ··· 84 82 * struct size. 85 83 */ 86 84 ruleset_size = sizeof(ruleset_attr.handled_access_fs); 85 + ruleset_size += sizeof(ruleset_attr.handled_access_net); 87 86 BUILD_BUG_ON(sizeof(ruleset_attr) != ruleset_size); 88 - BUILD_BUG_ON(sizeof(ruleset_attr) != 8); 87 + BUILD_BUG_ON(sizeof(ruleset_attr) != 16); 89 88 90 89 path_beneath_size = sizeof(path_beneath_attr.allowed_access); 91 90 path_beneath_size += sizeof(path_beneath_attr.parent_fd); 92 91 BUILD_BUG_ON(sizeof(path_beneath_attr) != path_beneath_size); 93 92 BUILD_BUG_ON(sizeof(path_beneath_attr) != 12); 93 + 94 + net_port_size = sizeof(net_port_attr.allowed_access); 95 + net_port_size += sizeof(net_port_attr.port); 96 + BUILD_BUG_ON(sizeof(net_port_attr) != net_port_size); 97 + BUILD_BUG_ON(sizeof(net_port_attr) != 16); 94 98 } 95 99 96 100 /* Ruleset handling */ ··· 137 129 .write = fop_dummy_write, 138 130 }; 139 131 140 - #define LANDLOCK_ABI_VERSION 3 132 + #define LANDLOCK_ABI_VERSION 4 141 133 142 134 /** 143 135 * sys_landlock_create_ruleset - Create a new ruleset ··· 196 188 LANDLOCK_MASK_ACCESS_FS) 197 189 return -EINVAL; 198 190 191 + /* Checks network content (and 32-bits cast). */ 192 + if ((ruleset_attr.handled_access_net | LANDLOCK_MASK_ACCESS_NET) != 193 + LANDLOCK_MASK_ACCESS_NET) 194 + return -EINVAL; 195 + 199 196 /* Checks arguments and transforms to kernel struct. */ 200 - ruleset = landlock_create_ruleset(ruleset_attr.handled_access_fs); 197 + ruleset = landlock_create_ruleset(ruleset_attr.handled_access_fs, 198 + ruleset_attr.handled_access_net); 201 199 if (IS_ERR(ruleset)) 202 200 return PTR_ERR(ruleset); 203 201 ··· 288 274 return err; 289 275 } 290 276 277 + static int add_rule_path_beneath(struct landlock_ruleset *const ruleset, 278 + const void __user *const rule_attr) 279 + { 280 + struct landlock_path_beneath_attr path_beneath_attr; 281 + struct path path; 282 + int res, err; 283 + access_mask_t mask; 284 + 285 + /* Copies raw user space buffer. */ 286 + res = copy_from_user(&path_beneath_attr, rule_attr, 287 + sizeof(path_beneath_attr)); 288 + if (res) 289 + return -EFAULT; 290 + 291 + /* 292 + * Informs about useless rule: empty allowed_access (i.e. deny rules) 293 + * are ignored in path walks. 294 + */ 295 + if (!path_beneath_attr.allowed_access) 296 + return -ENOMSG; 297 + 298 + /* Checks that allowed_access matches the @ruleset constraints. */ 299 + mask = landlock_get_raw_fs_access_mask(ruleset, 0); 300 + if ((path_beneath_attr.allowed_access | mask) != mask) 301 + return -EINVAL; 302 + 303 + /* Gets and checks the new rule. */ 304 + err = get_path_from_fd(path_beneath_attr.parent_fd, &path); 305 + if (err) 306 + return err; 307 + 308 + /* Imports the new rule. */ 309 + err = landlock_append_fs_rule(ruleset, &path, 310 + path_beneath_attr.allowed_access); 311 + path_put(&path); 312 + return err; 313 + } 314 + 315 + static int add_rule_net_port(struct landlock_ruleset *ruleset, 316 + const void __user *const rule_attr) 317 + { 318 + struct landlock_net_port_attr net_port_attr; 319 + int res; 320 + access_mask_t mask; 321 + 322 + /* Copies raw user space buffer. */ 323 + res = copy_from_user(&net_port_attr, rule_attr, sizeof(net_port_attr)); 324 + if (res) 325 + return -EFAULT; 326 + 327 + /* 328 + * Informs about useless rule: empty allowed_access (i.e. deny rules) 329 + * are ignored by network actions. 330 + */ 331 + if (!net_port_attr.allowed_access) 332 + return -ENOMSG; 333 + 334 + /* Checks that allowed_access matches the @ruleset constraints. */ 335 + mask = landlock_get_net_access_mask(ruleset, 0); 336 + if ((net_port_attr.allowed_access | mask) != mask) 337 + return -EINVAL; 338 + 339 + /* Denies inserting a rule with port greater than 65535. */ 340 + if (net_port_attr.port > U16_MAX) 341 + return -EINVAL; 342 + 343 + /* Imports the new rule. */ 344 + return landlock_append_net_rule(ruleset, net_port_attr.port, 345 + net_port_attr.allowed_access); 346 + } 347 + 291 348 /** 292 349 * sys_landlock_add_rule - Add a new rule to a ruleset 293 350 * 294 351 * @ruleset_fd: File descriptor tied to the ruleset that should be extended 295 352 * with the new rule. 296 - * @rule_type: Identify the structure type pointed to by @rule_attr (only 297 - * %LANDLOCK_RULE_PATH_BENEATH for now). 353 + * @rule_type: Identify the structure type pointed to by @rule_attr: 354 + * %LANDLOCK_RULE_PATH_BENEATH or %LANDLOCK_RULE_NET_PORT. 298 355 * @rule_attr: Pointer to a rule (only of type &struct 299 356 * landlock_path_beneath_attr for now). 300 357 * @flags: Must be 0. ··· 376 291 * Possible returned errors are: 377 292 * 378 293 * - %EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time; 294 + * - %EAFNOSUPPORT: @rule_type is %LANDLOCK_RULE_NET_PORT but TCP/IP is not 295 + * supported by the running kernel; 379 296 * - %EINVAL: @flags is not 0, or inconsistent access in the rule (i.e. 380 - * &landlock_path_beneath_attr.allowed_access is not a subset of the 381 - * ruleset handled accesses); 297 + * &landlock_path_beneath_attr.allowed_access or 298 + * &landlock_net_port_attr.allowed_access is not a subset of the 299 + * ruleset handled accesses), or &landlock_net_port_attr.port is 300 + * greater than 65535; 382 301 * - %ENOMSG: Empty accesses (e.g. &landlock_path_beneath_attr.allowed_access); 383 302 * - %EBADF: @ruleset_fd is not a file descriptor for the current thread, or a 384 303 * member of @rule_attr is not a file descriptor as expected; ··· 395 306 const enum landlock_rule_type, rule_type, 396 307 const void __user *const, rule_attr, const __u32, flags) 397 308 { 398 - struct landlock_path_beneath_attr path_beneath_attr; 399 - struct path path; 400 309 struct landlock_ruleset *ruleset; 401 - int res, err; 310 + int err; 402 311 403 312 if (!landlock_initialized) 404 313 return -EOPNOTSUPP; ··· 410 323 if (IS_ERR(ruleset)) 411 324 return PTR_ERR(ruleset); 412 325 413 - if (rule_type != LANDLOCK_RULE_PATH_BENEATH) { 326 + switch (rule_type) { 327 + case LANDLOCK_RULE_PATH_BENEATH: 328 + err = add_rule_path_beneath(ruleset, rule_attr); 329 + break; 330 + case LANDLOCK_RULE_NET_PORT: 331 + err = add_rule_net_port(ruleset, rule_attr); 332 + break; 333 + default: 414 334 err = -EINVAL; 415 - goto out_put_ruleset; 335 + break; 416 336 } 417 - 418 - /* Copies raw user space buffer, only one type for now. */ 419 - res = copy_from_user(&path_beneath_attr, rule_attr, 420 - sizeof(path_beneath_attr)); 421 - if (res) { 422 - err = -EFAULT; 423 - goto out_put_ruleset; 424 - } 425 - 426 - /* 427 - * Informs about useless rule: empty allowed_access (i.e. deny rules) 428 - * are ignored in path walks. 429 - */ 430 - if (!path_beneath_attr.allowed_access) { 431 - err = -ENOMSG; 432 - goto out_put_ruleset; 433 - } 434 - /* 435 - * Checks that allowed_access matches the @ruleset constraints 436 - * (ruleset->fs_access_masks[0] is automatically upgraded to 64-bits). 437 - */ 438 - if ((path_beneath_attr.allowed_access | ruleset->fs_access_masks[0]) != 439 - ruleset->fs_access_masks[0]) { 440 - err = -EINVAL; 441 - goto out_put_ruleset; 442 - } 443 - 444 - /* Gets and checks the new rule. */ 445 - err = get_path_from_fd(path_beneath_attr.parent_fd, &path); 446 - if (err) 447 - goto out_put_ruleset; 448 - 449 - /* Imports the new rule. */ 450 - err = landlock_append_fs_rule(ruleset, &path, 451 - path_beneath_attr.allowed_access); 452 - path_put(&path); 453 - 454 - out_put_ruleset: 455 337 landlock_put_ruleset(ruleset); 456 338 return err; 457 339 }
+1 -1
tools/testing/selftests/landlock/base_test.c
··· 75 75 const struct landlock_ruleset_attr ruleset_attr = { 76 76 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE, 77 77 }; 78 - ASSERT_EQ(3, landlock_create_ruleset(NULL, 0, 78 + ASSERT_EQ(4, landlock_create_ruleset(NULL, 0, 79 79 LANDLOCK_CREATE_RULESET_VERSION)); 80 80 81 81 ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0,
+13
tools/testing/selftests/landlock/common.h
··· 112 112 cap_t cap_p; 113 113 /* Only these three capabilities are useful for the tests. */ 114 114 const cap_value_t caps[] = { 115 + /* clang-format off */ 115 116 CAP_DAC_OVERRIDE, 116 117 CAP_MKNOD, 117 118 CAP_SYS_ADMIN, 118 119 CAP_SYS_CHROOT, 120 + CAP_NET_BIND_SERVICE, 121 + /* clang-format on */ 119 122 }; 120 123 121 124 cap_p = cap_get_proc(); ··· 258 255 if (sendmsg(usock, &msg, 0) < 0) 259 256 return -errno; 260 257 return 0; 258 + } 259 + 260 + static void __maybe_unused 261 + enforce_ruleset(struct __test_metadata *const _metadata, const int ruleset_fd) 262 + { 263 + ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); 264 + ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0)) 265 + { 266 + TH_LOG("Failed to enforce ruleset: %s", strerror(errno)); 267 + } 261 268 }
+4
tools/testing/selftests/landlock/config
··· 1 1 CONFIG_CGROUPS=y 2 2 CONFIG_CGROUP_SCHED=y 3 + CONFIG_INET=y 4 + CONFIG_IPV6=y 5 + CONFIG_NET=y 6 + CONFIG_NET_NS=y 3 7 CONFIG_OVERLAY_FS=y 4 8 CONFIG_PROC_FS=y 5 9 CONFIG_SECURITY=y
+59 -10
tools/testing/selftests/landlock/fs_test.c
··· 677 677 return ruleset_fd; 678 678 } 679 679 680 - static void enforce_ruleset(struct __test_metadata *const _metadata, 681 - const int ruleset_fd) 682 - { 683 - ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); 684 - ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0)) 685 - { 686 - TH_LOG("Failed to enforce ruleset: %s", strerror(errno)); 687 - } 688 - } 689 - 690 680 TEST_F_FORK(layout0, proc_nsfs) 691 681 { 692 682 const struct rule rules[] = { ··· 1621 1631 set_cap(_metadata, CAP_SYS_ADMIN); 1622 1632 ASSERT_EQ(-1, syscall(__NR_move_mount, AT_FDCWD, dir_s3d2, AT_FDCWD, 1623 1633 dir_s1d2, 0)); 1634 + ASSERT_EQ(EPERM, errno); 1635 + clear_cap(_metadata, CAP_SYS_ADMIN); 1636 + } 1637 + 1638 + TEST_F_FORK(layout1, topology_changes_with_net_only) 1639 + { 1640 + const struct landlock_ruleset_attr ruleset_net = { 1641 + .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | 1642 + LANDLOCK_ACCESS_NET_CONNECT_TCP, 1643 + }; 1644 + int ruleset_fd; 1645 + 1646 + /* Add network restrictions. */ 1647 + ruleset_fd = 1648 + landlock_create_ruleset(&ruleset_net, sizeof(ruleset_net), 0); 1649 + ASSERT_LE(0, ruleset_fd); 1650 + enforce_ruleset(_metadata, ruleset_fd); 1651 + ASSERT_EQ(0, close(ruleset_fd)); 1652 + 1653 + /* Mount, remount, move_mount, umount, and pivot_root checks. */ 1654 + set_cap(_metadata, CAP_SYS_ADMIN); 1655 + ASSERT_EQ(0, mount_opt(&mnt_tmp, dir_s1d2)); 1656 + ASSERT_EQ(0, mount(NULL, dir_s1d2, NULL, MS_PRIVATE | MS_REC, NULL)); 1657 + ASSERT_EQ(0, syscall(__NR_move_mount, AT_FDCWD, dir_s1d2, AT_FDCWD, 1658 + dir_s2d2, 0)); 1659 + ASSERT_EQ(0, umount(dir_s2d2)); 1660 + ASSERT_EQ(0, syscall(__NR_pivot_root, dir_s3d2, dir_s3d3)); 1661 + ASSERT_EQ(0, chdir("/")); 1662 + clear_cap(_metadata, CAP_SYS_ADMIN); 1663 + } 1664 + 1665 + TEST_F_FORK(layout1, topology_changes_with_net_and_fs) 1666 + { 1667 + const struct landlock_ruleset_attr ruleset_net_fs = { 1668 + .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | 1669 + LANDLOCK_ACCESS_NET_CONNECT_TCP, 1670 + .handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE, 1671 + }; 1672 + int ruleset_fd; 1673 + 1674 + /* Add network and filesystem restrictions. */ 1675 + ruleset_fd = landlock_create_ruleset(&ruleset_net_fs, 1676 + sizeof(ruleset_net_fs), 0); 1677 + ASSERT_LE(0, ruleset_fd); 1678 + enforce_ruleset(_metadata, ruleset_fd); 1679 + ASSERT_EQ(0, close(ruleset_fd)); 1680 + 1681 + /* Mount, remount, move_mount, umount, and pivot_root checks. */ 1682 + set_cap(_metadata, CAP_SYS_ADMIN); 1683 + ASSERT_EQ(-1, mount_opt(&mnt_tmp, dir_s1d2)); 1684 + ASSERT_EQ(EPERM, errno); 1685 + ASSERT_EQ(-1, mount(NULL, dir_s3d2, NULL, MS_PRIVATE | MS_REC, NULL)); 1686 + ASSERT_EQ(EPERM, errno); 1687 + ASSERT_EQ(-1, syscall(__NR_move_mount, AT_FDCWD, dir_s3d2, AT_FDCWD, 1688 + dir_s2d2, 0)); 1689 + ASSERT_EQ(EPERM, errno); 1690 + ASSERT_EQ(-1, umount(dir_s3d2)); 1691 + ASSERT_EQ(EPERM, errno); 1692 + ASSERT_EQ(-1, syscall(__NR_pivot_root, dir_s3d2, dir_s3d3)); 1624 1693 ASSERT_EQ(EPERM, errno); 1625 1694 clear_cap(_metadata, CAP_SYS_ADMIN); 1626 1695 }
+1738
tools/testing/selftests/landlock/net_test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Landlock tests - Network 4 + * 5 + * Copyright © 2022-2023 Huawei Tech. Co., Ltd. 6 + * Copyright © 2023 Microsoft Corporation 7 + */ 8 + 9 + #define _GNU_SOURCE 10 + #include <arpa/inet.h> 11 + #include <errno.h> 12 + #include <fcntl.h> 13 + #include <linux/landlock.h> 14 + #include <linux/in.h> 15 + #include <sched.h> 16 + #include <stdint.h> 17 + #include <string.h> 18 + #include <sys/prctl.h> 19 + #include <sys/socket.h> 20 + #include <sys/un.h> 21 + 22 + #include "common.h" 23 + 24 + const short sock_port_start = (1 << 10); 25 + 26 + static const char loopback_ipv4[] = "127.0.0.1"; 27 + static const char loopback_ipv6[] = "::1"; 28 + 29 + /* Number pending connections queue to be hold. */ 30 + const short backlog = 10; 31 + 32 + enum sandbox_type { 33 + NO_SANDBOX, 34 + /* This may be used to test rules that allow *and* deny accesses. */ 35 + TCP_SANDBOX, 36 + }; 37 + 38 + struct protocol_variant { 39 + int domain; 40 + int type; 41 + }; 42 + 43 + struct service_fixture { 44 + struct protocol_variant protocol; 45 + /* port is also stored in ipv4_addr.sin_port or ipv6_addr.sin6_port */ 46 + unsigned short port; 47 + union { 48 + struct sockaddr_in ipv4_addr; 49 + struct sockaddr_in6 ipv6_addr; 50 + struct { 51 + struct sockaddr_un unix_addr; 52 + socklen_t unix_addr_len; 53 + }; 54 + }; 55 + }; 56 + 57 + static int set_service(struct service_fixture *const srv, 58 + const struct protocol_variant prot, 59 + const unsigned short index) 60 + { 61 + memset(srv, 0, sizeof(*srv)); 62 + 63 + /* 64 + * Copies all protocol properties in case of the variant only contains 65 + * a subset of them. 66 + */ 67 + srv->protocol = prot; 68 + 69 + /* Checks for port overflow. */ 70 + if (index > 2) 71 + return 1; 72 + srv->port = sock_port_start << (2 * index); 73 + 74 + switch (prot.domain) { 75 + case AF_UNSPEC: 76 + case AF_INET: 77 + srv->ipv4_addr.sin_family = prot.domain; 78 + srv->ipv4_addr.sin_port = htons(srv->port); 79 + srv->ipv4_addr.sin_addr.s_addr = inet_addr(loopback_ipv4); 80 + return 0; 81 + 82 + case AF_INET6: 83 + srv->ipv6_addr.sin6_family = prot.domain; 84 + srv->ipv6_addr.sin6_port = htons(srv->port); 85 + inet_pton(AF_INET6, loopback_ipv6, &srv->ipv6_addr.sin6_addr); 86 + return 0; 87 + 88 + case AF_UNIX: 89 + srv->unix_addr.sun_family = prot.domain; 90 + sprintf(srv->unix_addr.sun_path, 91 + "_selftests-landlock-net-tid%d-index%d", gettid(), 92 + index); 93 + srv->unix_addr_len = SUN_LEN(&srv->unix_addr); 94 + srv->unix_addr.sun_path[0] = '\0'; 95 + return 0; 96 + } 97 + return 1; 98 + } 99 + 100 + static void setup_loopback(struct __test_metadata *const _metadata) 101 + { 102 + set_cap(_metadata, CAP_SYS_ADMIN); 103 + ASSERT_EQ(0, unshare(CLONE_NEWNET)); 104 + ASSERT_EQ(0, system("ip link set dev lo up")); 105 + clear_cap(_metadata, CAP_SYS_ADMIN); 106 + } 107 + 108 + static bool is_restricted(const struct protocol_variant *const prot, 109 + const enum sandbox_type sandbox) 110 + { 111 + switch (prot->domain) { 112 + case AF_INET: 113 + case AF_INET6: 114 + switch (prot->type) { 115 + case SOCK_STREAM: 116 + return sandbox == TCP_SANDBOX; 117 + } 118 + break; 119 + } 120 + return false; 121 + } 122 + 123 + static int socket_variant(const struct service_fixture *const srv) 124 + { 125 + int ret; 126 + 127 + ret = socket(srv->protocol.domain, srv->protocol.type | SOCK_CLOEXEC, 128 + 0); 129 + if (ret < 0) 130 + return -errno; 131 + return ret; 132 + } 133 + 134 + #ifndef SIN6_LEN_RFC2133 135 + #define SIN6_LEN_RFC2133 24 136 + #endif 137 + 138 + static socklen_t get_addrlen(const struct service_fixture *const srv, 139 + const bool minimal) 140 + { 141 + switch (srv->protocol.domain) { 142 + case AF_UNSPEC: 143 + case AF_INET: 144 + return sizeof(srv->ipv4_addr); 145 + 146 + case AF_INET6: 147 + if (minimal) 148 + return SIN6_LEN_RFC2133; 149 + return sizeof(srv->ipv6_addr); 150 + 151 + case AF_UNIX: 152 + if (minimal) 153 + return sizeof(srv->unix_addr) - 154 + sizeof(srv->unix_addr.sun_path); 155 + return srv->unix_addr_len; 156 + 157 + default: 158 + return 0; 159 + } 160 + } 161 + 162 + static void set_port(struct service_fixture *const srv, uint16_t port) 163 + { 164 + switch (srv->protocol.domain) { 165 + case AF_UNSPEC: 166 + case AF_INET: 167 + srv->ipv4_addr.sin_port = htons(port); 168 + return; 169 + 170 + case AF_INET6: 171 + srv->ipv6_addr.sin6_port = htons(port); 172 + return; 173 + 174 + default: 175 + return; 176 + } 177 + } 178 + 179 + static uint16_t get_binded_port(int socket_fd, 180 + const struct protocol_variant *const prot) 181 + { 182 + struct sockaddr_in ipv4_addr; 183 + struct sockaddr_in6 ipv6_addr; 184 + socklen_t ipv4_addr_len, ipv6_addr_len; 185 + 186 + /* Gets binded port. */ 187 + switch (prot->domain) { 188 + case AF_UNSPEC: 189 + case AF_INET: 190 + ipv4_addr_len = sizeof(ipv4_addr); 191 + getsockname(socket_fd, &ipv4_addr, &ipv4_addr_len); 192 + return ntohs(ipv4_addr.sin_port); 193 + 194 + case AF_INET6: 195 + ipv6_addr_len = sizeof(ipv6_addr); 196 + getsockname(socket_fd, &ipv6_addr, &ipv6_addr_len); 197 + return ntohs(ipv6_addr.sin6_port); 198 + 199 + default: 200 + return 0; 201 + } 202 + } 203 + 204 + static int bind_variant_addrlen(const int sock_fd, 205 + const struct service_fixture *const srv, 206 + const socklen_t addrlen) 207 + { 208 + int ret; 209 + 210 + switch (srv->protocol.domain) { 211 + case AF_UNSPEC: 212 + case AF_INET: 213 + ret = bind(sock_fd, &srv->ipv4_addr, addrlen); 214 + break; 215 + 216 + case AF_INET6: 217 + ret = bind(sock_fd, &srv->ipv6_addr, addrlen); 218 + break; 219 + 220 + case AF_UNIX: 221 + ret = bind(sock_fd, &srv->unix_addr, addrlen); 222 + break; 223 + 224 + default: 225 + errno = EAFNOSUPPORT; 226 + return -errno; 227 + } 228 + 229 + if (ret < 0) 230 + return -errno; 231 + return ret; 232 + } 233 + 234 + static int bind_variant(const int sock_fd, 235 + const struct service_fixture *const srv) 236 + { 237 + return bind_variant_addrlen(sock_fd, srv, get_addrlen(srv, false)); 238 + } 239 + 240 + static int connect_variant_addrlen(const int sock_fd, 241 + const struct service_fixture *const srv, 242 + const socklen_t addrlen) 243 + { 244 + int ret; 245 + 246 + switch (srv->protocol.domain) { 247 + case AF_UNSPEC: 248 + case AF_INET: 249 + ret = connect(sock_fd, &srv->ipv4_addr, addrlen); 250 + break; 251 + 252 + case AF_INET6: 253 + ret = connect(sock_fd, &srv->ipv6_addr, addrlen); 254 + break; 255 + 256 + case AF_UNIX: 257 + ret = connect(sock_fd, &srv->unix_addr, addrlen); 258 + break; 259 + 260 + default: 261 + errno = -EAFNOSUPPORT; 262 + return -errno; 263 + } 264 + 265 + if (ret < 0) 266 + return -errno; 267 + return ret; 268 + } 269 + 270 + static int connect_variant(const int sock_fd, 271 + const struct service_fixture *const srv) 272 + { 273 + return connect_variant_addrlen(sock_fd, srv, get_addrlen(srv, false)); 274 + } 275 + 276 + FIXTURE(protocol) 277 + { 278 + struct service_fixture srv0, srv1, srv2, unspec_any0, unspec_srv0; 279 + }; 280 + 281 + FIXTURE_VARIANT(protocol) 282 + { 283 + const enum sandbox_type sandbox; 284 + const struct protocol_variant prot; 285 + }; 286 + 287 + FIXTURE_SETUP(protocol) 288 + { 289 + const struct protocol_variant prot_unspec = { 290 + .domain = AF_UNSPEC, 291 + .type = SOCK_STREAM, 292 + }; 293 + 294 + disable_caps(_metadata); 295 + 296 + ASSERT_EQ(0, set_service(&self->srv0, variant->prot, 0)); 297 + ASSERT_EQ(0, set_service(&self->srv1, variant->prot, 1)); 298 + ASSERT_EQ(0, set_service(&self->srv2, variant->prot, 2)); 299 + 300 + ASSERT_EQ(0, set_service(&self->unspec_srv0, prot_unspec, 0)); 301 + 302 + ASSERT_EQ(0, set_service(&self->unspec_any0, prot_unspec, 0)); 303 + self->unspec_any0.ipv4_addr.sin_addr.s_addr = htonl(INADDR_ANY); 304 + 305 + setup_loopback(_metadata); 306 + }; 307 + 308 + FIXTURE_TEARDOWN(protocol) 309 + { 310 + } 311 + 312 + /* clang-format off */ 313 + FIXTURE_VARIANT_ADD(protocol, no_sandbox_with_ipv4_tcp) { 314 + /* clang-format on */ 315 + .sandbox = NO_SANDBOX, 316 + .prot = { 317 + .domain = AF_INET, 318 + .type = SOCK_STREAM, 319 + }, 320 + }; 321 + 322 + /* clang-format off */ 323 + FIXTURE_VARIANT_ADD(protocol, no_sandbox_with_ipv6_tcp) { 324 + /* clang-format on */ 325 + .sandbox = NO_SANDBOX, 326 + .prot = { 327 + .domain = AF_INET6, 328 + .type = SOCK_STREAM, 329 + }, 330 + }; 331 + 332 + /* clang-format off */ 333 + FIXTURE_VARIANT_ADD(protocol, no_sandbox_with_ipv4_udp) { 334 + /* clang-format on */ 335 + .sandbox = NO_SANDBOX, 336 + .prot = { 337 + .domain = AF_INET, 338 + .type = SOCK_DGRAM, 339 + }, 340 + }; 341 + 342 + /* clang-format off */ 343 + FIXTURE_VARIANT_ADD(protocol, no_sandbox_with_ipv6_udp) { 344 + /* clang-format on */ 345 + .sandbox = NO_SANDBOX, 346 + .prot = { 347 + .domain = AF_INET6, 348 + .type = SOCK_DGRAM, 349 + }, 350 + }; 351 + 352 + /* clang-format off */ 353 + FIXTURE_VARIANT_ADD(protocol, no_sandbox_with_unix_stream) { 354 + /* clang-format on */ 355 + .sandbox = NO_SANDBOX, 356 + .prot = { 357 + .domain = AF_UNIX, 358 + .type = SOCK_STREAM, 359 + }, 360 + }; 361 + 362 + /* clang-format off */ 363 + FIXTURE_VARIANT_ADD(protocol, no_sandbox_with_unix_datagram) { 364 + /* clang-format on */ 365 + .sandbox = NO_SANDBOX, 366 + .prot = { 367 + .domain = AF_UNIX, 368 + .type = SOCK_DGRAM, 369 + }, 370 + }; 371 + 372 + /* clang-format off */ 373 + FIXTURE_VARIANT_ADD(protocol, tcp_sandbox_with_ipv4_tcp) { 374 + /* clang-format on */ 375 + .sandbox = TCP_SANDBOX, 376 + .prot = { 377 + .domain = AF_INET, 378 + .type = SOCK_STREAM, 379 + }, 380 + }; 381 + 382 + /* clang-format off */ 383 + FIXTURE_VARIANT_ADD(protocol, tcp_sandbox_with_ipv6_tcp) { 384 + /* clang-format on */ 385 + .sandbox = TCP_SANDBOX, 386 + .prot = { 387 + .domain = AF_INET6, 388 + .type = SOCK_STREAM, 389 + }, 390 + }; 391 + 392 + /* clang-format off */ 393 + FIXTURE_VARIANT_ADD(protocol, tcp_sandbox_with_ipv4_udp) { 394 + /* clang-format on */ 395 + .sandbox = TCP_SANDBOX, 396 + .prot = { 397 + .domain = AF_INET, 398 + .type = SOCK_DGRAM, 399 + }, 400 + }; 401 + 402 + /* clang-format off */ 403 + FIXTURE_VARIANT_ADD(protocol, tcp_sandbox_with_ipv6_udp) { 404 + /* clang-format on */ 405 + .sandbox = TCP_SANDBOX, 406 + .prot = { 407 + .domain = AF_INET6, 408 + .type = SOCK_DGRAM, 409 + }, 410 + }; 411 + 412 + /* clang-format off */ 413 + FIXTURE_VARIANT_ADD(protocol, tcp_sandbox_with_unix_stream) { 414 + /* clang-format on */ 415 + .sandbox = TCP_SANDBOX, 416 + .prot = { 417 + .domain = AF_UNIX, 418 + .type = SOCK_STREAM, 419 + }, 420 + }; 421 + 422 + /* clang-format off */ 423 + FIXTURE_VARIANT_ADD(protocol, tcp_sandbox_with_unix_datagram) { 424 + /* clang-format on */ 425 + .sandbox = TCP_SANDBOX, 426 + .prot = { 427 + .domain = AF_UNIX, 428 + .type = SOCK_DGRAM, 429 + }, 430 + }; 431 + 432 + static void test_bind_and_connect(struct __test_metadata *const _metadata, 433 + const struct service_fixture *const srv, 434 + const bool deny_bind, const bool deny_connect) 435 + { 436 + char buf = '\0'; 437 + int inval_fd, bind_fd, client_fd, status, ret; 438 + pid_t child; 439 + 440 + /* Starts invalid addrlen tests with bind. */ 441 + inval_fd = socket_variant(srv); 442 + ASSERT_LE(0, inval_fd) 443 + { 444 + TH_LOG("Failed to create socket: %s", strerror(errno)); 445 + } 446 + 447 + /* Tries to bind with zero as addrlen. */ 448 + EXPECT_EQ(-EINVAL, bind_variant_addrlen(inval_fd, srv, 0)); 449 + 450 + /* Tries to bind with too small addrlen. */ 451 + EXPECT_EQ(-EINVAL, bind_variant_addrlen(inval_fd, srv, 452 + get_addrlen(srv, true) - 1)); 453 + 454 + /* Tries to bind with minimal addrlen. */ 455 + ret = bind_variant_addrlen(inval_fd, srv, get_addrlen(srv, true)); 456 + if (deny_bind) { 457 + EXPECT_EQ(-EACCES, ret); 458 + } else { 459 + EXPECT_EQ(0, ret) 460 + { 461 + TH_LOG("Failed to bind to socket: %s", strerror(errno)); 462 + } 463 + } 464 + EXPECT_EQ(0, close(inval_fd)); 465 + 466 + /* Starts invalid addrlen tests with connect. */ 467 + inval_fd = socket_variant(srv); 468 + ASSERT_LE(0, inval_fd); 469 + 470 + /* Tries to connect with zero as addrlen. */ 471 + EXPECT_EQ(-EINVAL, connect_variant_addrlen(inval_fd, srv, 0)); 472 + 473 + /* Tries to connect with too small addrlen. */ 474 + EXPECT_EQ(-EINVAL, connect_variant_addrlen(inval_fd, srv, 475 + get_addrlen(srv, true) - 1)); 476 + 477 + /* Tries to connect with minimal addrlen. */ 478 + ret = connect_variant_addrlen(inval_fd, srv, get_addrlen(srv, true)); 479 + if (srv->protocol.domain == AF_UNIX) { 480 + EXPECT_EQ(-EINVAL, ret); 481 + } else if (deny_connect) { 482 + EXPECT_EQ(-EACCES, ret); 483 + } else if (srv->protocol.type == SOCK_STREAM) { 484 + /* No listening server, whatever the value of deny_bind. */ 485 + EXPECT_EQ(-ECONNREFUSED, ret); 486 + } else { 487 + EXPECT_EQ(0, ret) 488 + { 489 + TH_LOG("Failed to connect to socket: %s", 490 + strerror(errno)); 491 + } 492 + } 493 + EXPECT_EQ(0, close(inval_fd)); 494 + 495 + /* Starts connection tests. */ 496 + bind_fd = socket_variant(srv); 497 + ASSERT_LE(0, bind_fd); 498 + 499 + ret = bind_variant(bind_fd, srv); 500 + if (deny_bind) { 501 + EXPECT_EQ(-EACCES, ret); 502 + } else { 503 + EXPECT_EQ(0, ret); 504 + 505 + /* Creates a listening socket. */ 506 + if (srv->protocol.type == SOCK_STREAM) 507 + EXPECT_EQ(0, listen(bind_fd, backlog)); 508 + } 509 + 510 + child = fork(); 511 + ASSERT_LE(0, child); 512 + if (child == 0) { 513 + int connect_fd, ret; 514 + 515 + /* Closes listening socket for the child. */ 516 + EXPECT_EQ(0, close(bind_fd)); 517 + 518 + /* Starts connection tests. */ 519 + connect_fd = socket_variant(srv); 520 + ASSERT_LE(0, connect_fd); 521 + ret = connect_variant(connect_fd, srv); 522 + if (deny_connect) { 523 + EXPECT_EQ(-EACCES, ret); 524 + } else if (deny_bind) { 525 + /* No listening server. */ 526 + EXPECT_EQ(-ECONNREFUSED, ret); 527 + } else { 528 + EXPECT_EQ(0, ret); 529 + EXPECT_EQ(1, write(connect_fd, ".", 1)); 530 + } 531 + 532 + EXPECT_EQ(0, close(connect_fd)); 533 + _exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE); 534 + return; 535 + } 536 + 537 + /* Accepts connection from the child. */ 538 + client_fd = bind_fd; 539 + if (!deny_bind && !deny_connect) { 540 + if (srv->protocol.type == SOCK_STREAM) { 541 + client_fd = accept(bind_fd, NULL, 0); 542 + ASSERT_LE(0, client_fd); 543 + } 544 + 545 + EXPECT_EQ(1, read(client_fd, &buf, 1)); 546 + EXPECT_EQ('.', buf); 547 + } 548 + 549 + EXPECT_EQ(child, waitpid(child, &status, 0)); 550 + EXPECT_EQ(1, WIFEXITED(status)); 551 + EXPECT_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); 552 + 553 + /* Closes connection, if any. */ 554 + if (client_fd != bind_fd) 555 + EXPECT_LE(0, close(client_fd)); 556 + 557 + /* Closes listening socket. */ 558 + EXPECT_EQ(0, close(bind_fd)); 559 + } 560 + 561 + TEST_F(protocol, bind) 562 + { 563 + if (variant->sandbox == TCP_SANDBOX) { 564 + const struct landlock_ruleset_attr ruleset_attr = { 565 + .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | 566 + LANDLOCK_ACCESS_NET_CONNECT_TCP, 567 + }; 568 + const struct landlock_net_port_attr tcp_bind_connect_p0 = { 569 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP | 570 + LANDLOCK_ACCESS_NET_CONNECT_TCP, 571 + .port = self->srv0.port, 572 + }; 573 + const struct landlock_net_port_attr tcp_connect_p1 = { 574 + .allowed_access = LANDLOCK_ACCESS_NET_CONNECT_TCP, 575 + .port = self->srv1.port, 576 + }; 577 + int ruleset_fd; 578 + 579 + ruleset_fd = landlock_create_ruleset(&ruleset_attr, 580 + sizeof(ruleset_attr), 0); 581 + ASSERT_LE(0, ruleset_fd); 582 + 583 + /* Allows connect and bind for the first port. */ 584 + ASSERT_EQ(0, 585 + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 586 + &tcp_bind_connect_p0, 0)); 587 + 588 + /* Allows connect and denies bind for the second port. */ 589 + ASSERT_EQ(0, 590 + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 591 + &tcp_connect_p1, 0)); 592 + 593 + enforce_ruleset(_metadata, ruleset_fd); 594 + EXPECT_EQ(0, close(ruleset_fd)); 595 + } 596 + 597 + /* Binds a socket to the first port. */ 598 + test_bind_and_connect(_metadata, &self->srv0, false, false); 599 + 600 + /* Binds a socket to the second port. */ 601 + test_bind_and_connect(_metadata, &self->srv1, 602 + is_restricted(&variant->prot, variant->sandbox), 603 + false); 604 + 605 + /* Binds a socket to the third port. */ 606 + test_bind_and_connect(_metadata, &self->srv2, 607 + is_restricted(&variant->prot, variant->sandbox), 608 + is_restricted(&variant->prot, variant->sandbox)); 609 + } 610 + 611 + TEST_F(protocol, connect) 612 + { 613 + if (variant->sandbox == TCP_SANDBOX) { 614 + const struct landlock_ruleset_attr ruleset_attr = { 615 + .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | 616 + LANDLOCK_ACCESS_NET_CONNECT_TCP, 617 + }; 618 + const struct landlock_net_port_attr tcp_bind_connect_p0 = { 619 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP | 620 + LANDLOCK_ACCESS_NET_CONNECT_TCP, 621 + .port = self->srv0.port, 622 + }; 623 + const struct landlock_net_port_attr tcp_bind_p1 = { 624 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP, 625 + .port = self->srv1.port, 626 + }; 627 + int ruleset_fd; 628 + 629 + ruleset_fd = landlock_create_ruleset(&ruleset_attr, 630 + sizeof(ruleset_attr), 0); 631 + ASSERT_LE(0, ruleset_fd); 632 + 633 + /* Allows connect and bind for the first port. */ 634 + ASSERT_EQ(0, 635 + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 636 + &tcp_bind_connect_p0, 0)); 637 + 638 + /* Allows bind and denies connect for the second port. */ 639 + ASSERT_EQ(0, 640 + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 641 + &tcp_bind_p1, 0)); 642 + 643 + enforce_ruleset(_metadata, ruleset_fd); 644 + EXPECT_EQ(0, close(ruleset_fd)); 645 + } 646 + 647 + test_bind_and_connect(_metadata, &self->srv0, false, false); 648 + 649 + test_bind_and_connect(_metadata, &self->srv1, false, 650 + is_restricted(&variant->prot, variant->sandbox)); 651 + 652 + test_bind_and_connect(_metadata, &self->srv2, 653 + is_restricted(&variant->prot, variant->sandbox), 654 + is_restricted(&variant->prot, variant->sandbox)); 655 + } 656 + 657 + TEST_F(protocol, bind_unspec) 658 + { 659 + const struct landlock_ruleset_attr ruleset_attr = { 660 + .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP, 661 + }; 662 + const struct landlock_net_port_attr tcp_bind = { 663 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP, 664 + .port = self->srv0.port, 665 + }; 666 + int bind_fd, ret; 667 + 668 + if (variant->sandbox == TCP_SANDBOX) { 669 + const int ruleset_fd = landlock_create_ruleset( 670 + &ruleset_attr, sizeof(ruleset_attr), 0); 671 + ASSERT_LE(0, ruleset_fd); 672 + 673 + /* Allows bind. */ 674 + ASSERT_EQ(0, 675 + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 676 + &tcp_bind, 0)); 677 + enforce_ruleset(_metadata, ruleset_fd); 678 + EXPECT_EQ(0, close(ruleset_fd)); 679 + } 680 + 681 + bind_fd = socket_variant(&self->srv0); 682 + ASSERT_LE(0, bind_fd); 683 + 684 + /* Allowed bind on AF_UNSPEC/INADDR_ANY. */ 685 + ret = bind_variant(bind_fd, &self->unspec_any0); 686 + if (variant->prot.domain == AF_INET) { 687 + EXPECT_EQ(0, ret) 688 + { 689 + TH_LOG("Failed to bind to unspec/any socket: %s", 690 + strerror(errno)); 691 + } 692 + } else { 693 + EXPECT_EQ(-EINVAL, ret); 694 + } 695 + EXPECT_EQ(0, close(bind_fd)); 696 + 697 + if (variant->sandbox == TCP_SANDBOX) { 698 + const int ruleset_fd = landlock_create_ruleset( 699 + &ruleset_attr, sizeof(ruleset_attr), 0); 700 + ASSERT_LE(0, ruleset_fd); 701 + 702 + /* Denies bind. */ 703 + enforce_ruleset(_metadata, ruleset_fd); 704 + EXPECT_EQ(0, close(ruleset_fd)); 705 + } 706 + 707 + bind_fd = socket_variant(&self->srv0); 708 + ASSERT_LE(0, bind_fd); 709 + 710 + /* Denied bind on AF_UNSPEC/INADDR_ANY. */ 711 + ret = bind_variant(bind_fd, &self->unspec_any0); 712 + if (variant->prot.domain == AF_INET) { 713 + if (is_restricted(&variant->prot, variant->sandbox)) { 714 + EXPECT_EQ(-EACCES, ret); 715 + } else { 716 + EXPECT_EQ(0, ret); 717 + } 718 + } else { 719 + EXPECT_EQ(-EINVAL, ret); 720 + } 721 + EXPECT_EQ(0, close(bind_fd)); 722 + 723 + /* Checks bind with AF_UNSPEC and the loopback address. */ 724 + bind_fd = socket_variant(&self->srv0); 725 + ASSERT_LE(0, bind_fd); 726 + ret = bind_variant(bind_fd, &self->unspec_srv0); 727 + if (variant->prot.domain == AF_INET) { 728 + EXPECT_EQ(-EAFNOSUPPORT, ret); 729 + } else { 730 + EXPECT_EQ(-EINVAL, ret) 731 + { 732 + TH_LOG("Wrong bind error: %s", strerror(errno)); 733 + } 734 + } 735 + EXPECT_EQ(0, close(bind_fd)); 736 + } 737 + 738 + TEST_F(protocol, connect_unspec) 739 + { 740 + const struct landlock_ruleset_attr ruleset_attr = { 741 + .handled_access_net = LANDLOCK_ACCESS_NET_CONNECT_TCP, 742 + }; 743 + const struct landlock_net_port_attr tcp_connect = { 744 + .allowed_access = LANDLOCK_ACCESS_NET_CONNECT_TCP, 745 + .port = self->srv0.port, 746 + }; 747 + int bind_fd, client_fd, status; 748 + pid_t child; 749 + 750 + /* Specific connection tests. */ 751 + bind_fd = socket_variant(&self->srv0); 752 + ASSERT_LE(0, bind_fd); 753 + EXPECT_EQ(0, bind_variant(bind_fd, &self->srv0)); 754 + if (self->srv0.protocol.type == SOCK_STREAM) 755 + EXPECT_EQ(0, listen(bind_fd, backlog)); 756 + 757 + child = fork(); 758 + ASSERT_LE(0, child); 759 + if (child == 0) { 760 + int connect_fd, ret; 761 + 762 + /* Closes listening socket for the child. */ 763 + EXPECT_EQ(0, close(bind_fd)); 764 + 765 + connect_fd = socket_variant(&self->srv0); 766 + ASSERT_LE(0, connect_fd); 767 + EXPECT_EQ(0, connect_variant(connect_fd, &self->srv0)); 768 + 769 + /* Tries to connect again, or set peer. */ 770 + ret = connect_variant(connect_fd, &self->srv0); 771 + if (self->srv0.protocol.type == SOCK_STREAM) { 772 + EXPECT_EQ(-EISCONN, ret); 773 + } else { 774 + EXPECT_EQ(0, ret); 775 + } 776 + 777 + if (variant->sandbox == TCP_SANDBOX) { 778 + const int ruleset_fd = landlock_create_ruleset( 779 + &ruleset_attr, sizeof(ruleset_attr), 0); 780 + ASSERT_LE(0, ruleset_fd); 781 + 782 + /* Allows connect. */ 783 + ASSERT_EQ(0, landlock_add_rule(ruleset_fd, 784 + LANDLOCK_RULE_NET_PORT, 785 + &tcp_connect, 0)); 786 + enforce_ruleset(_metadata, ruleset_fd); 787 + EXPECT_EQ(0, close(ruleset_fd)); 788 + } 789 + 790 + /* Disconnects already connected socket, or set peer. */ 791 + ret = connect_variant(connect_fd, &self->unspec_any0); 792 + if (self->srv0.protocol.domain == AF_UNIX && 793 + self->srv0.protocol.type == SOCK_STREAM) { 794 + EXPECT_EQ(-EINVAL, ret); 795 + } else { 796 + EXPECT_EQ(0, ret); 797 + } 798 + 799 + /* Tries to reconnect, or set peer. */ 800 + ret = connect_variant(connect_fd, &self->srv0); 801 + if (self->srv0.protocol.domain == AF_UNIX && 802 + self->srv0.protocol.type == SOCK_STREAM) { 803 + EXPECT_EQ(-EISCONN, ret); 804 + } else { 805 + EXPECT_EQ(0, ret); 806 + } 807 + 808 + if (variant->sandbox == TCP_SANDBOX) { 809 + const int ruleset_fd = landlock_create_ruleset( 810 + &ruleset_attr, sizeof(ruleset_attr), 0); 811 + ASSERT_LE(0, ruleset_fd); 812 + 813 + /* Denies connect. */ 814 + enforce_ruleset(_metadata, ruleset_fd); 815 + EXPECT_EQ(0, close(ruleset_fd)); 816 + } 817 + 818 + ret = connect_variant(connect_fd, &self->unspec_any0); 819 + if (self->srv0.protocol.domain == AF_UNIX && 820 + self->srv0.protocol.type == SOCK_STREAM) { 821 + EXPECT_EQ(-EINVAL, ret); 822 + } else { 823 + /* Always allowed to disconnect. */ 824 + EXPECT_EQ(0, ret); 825 + } 826 + 827 + EXPECT_EQ(0, close(connect_fd)); 828 + _exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE); 829 + return; 830 + } 831 + 832 + client_fd = bind_fd; 833 + if (self->srv0.protocol.type == SOCK_STREAM) { 834 + client_fd = accept(bind_fd, NULL, 0); 835 + ASSERT_LE(0, client_fd); 836 + } 837 + 838 + EXPECT_EQ(child, waitpid(child, &status, 0)); 839 + EXPECT_EQ(1, WIFEXITED(status)); 840 + EXPECT_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); 841 + 842 + /* Closes connection, if any. */ 843 + if (client_fd != bind_fd) 844 + EXPECT_LE(0, close(client_fd)); 845 + 846 + /* Closes listening socket. */ 847 + EXPECT_EQ(0, close(bind_fd)); 848 + } 849 + 850 + FIXTURE(ipv4) 851 + { 852 + struct service_fixture srv0, srv1; 853 + }; 854 + 855 + FIXTURE_VARIANT(ipv4) 856 + { 857 + const enum sandbox_type sandbox; 858 + const int type; 859 + }; 860 + 861 + /* clang-format off */ 862 + FIXTURE_VARIANT_ADD(ipv4, no_sandbox_with_tcp) { 863 + /* clang-format on */ 864 + .sandbox = NO_SANDBOX, 865 + .type = SOCK_STREAM, 866 + }; 867 + 868 + /* clang-format off */ 869 + FIXTURE_VARIANT_ADD(ipv4, tcp_sandbox_with_tcp) { 870 + /* clang-format on */ 871 + .sandbox = TCP_SANDBOX, 872 + .type = SOCK_STREAM, 873 + }; 874 + 875 + /* clang-format off */ 876 + FIXTURE_VARIANT_ADD(ipv4, no_sandbox_with_udp) { 877 + /* clang-format on */ 878 + .sandbox = NO_SANDBOX, 879 + .type = SOCK_DGRAM, 880 + }; 881 + 882 + /* clang-format off */ 883 + FIXTURE_VARIANT_ADD(ipv4, tcp_sandbox_with_udp) { 884 + /* clang-format on */ 885 + .sandbox = TCP_SANDBOX, 886 + .type = SOCK_DGRAM, 887 + }; 888 + 889 + FIXTURE_SETUP(ipv4) 890 + { 891 + const struct protocol_variant prot = { 892 + .domain = AF_INET, 893 + .type = variant->type, 894 + }; 895 + 896 + disable_caps(_metadata); 897 + 898 + set_service(&self->srv0, prot, 0); 899 + set_service(&self->srv1, prot, 1); 900 + 901 + setup_loopback(_metadata); 902 + }; 903 + 904 + FIXTURE_TEARDOWN(ipv4) 905 + { 906 + } 907 + 908 + TEST_F(ipv4, from_unix_to_inet) 909 + { 910 + int unix_stream_fd, unix_dgram_fd; 911 + 912 + if (variant->sandbox == TCP_SANDBOX) { 913 + const struct landlock_ruleset_attr ruleset_attr = { 914 + .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | 915 + LANDLOCK_ACCESS_NET_CONNECT_TCP, 916 + }; 917 + const struct landlock_net_port_attr tcp_bind_connect_p0 = { 918 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP | 919 + LANDLOCK_ACCESS_NET_CONNECT_TCP, 920 + .port = self->srv0.port, 921 + }; 922 + int ruleset_fd; 923 + 924 + /* Denies connect and bind to check errno value. */ 925 + ruleset_fd = landlock_create_ruleset(&ruleset_attr, 926 + sizeof(ruleset_attr), 0); 927 + ASSERT_LE(0, ruleset_fd); 928 + 929 + /* Allows connect and bind for srv0. */ 930 + ASSERT_EQ(0, 931 + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 932 + &tcp_bind_connect_p0, 0)); 933 + 934 + enforce_ruleset(_metadata, ruleset_fd); 935 + EXPECT_EQ(0, close(ruleset_fd)); 936 + } 937 + 938 + unix_stream_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); 939 + ASSERT_LE(0, unix_stream_fd); 940 + 941 + unix_dgram_fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); 942 + ASSERT_LE(0, unix_dgram_fd); 943 + 944 + /* Checks unix stream bind and connect for srv0. */ 945 + EXPECT_EQ(-EINVAL, bind_variant(unix_stream_fd, &self->srv0)); 946 + EXPECT_EQ(-EINVAL, connect_variant(unix_stream_fd, &self->srv0)); 947 + 948 + /* Checks unix stream bind and connect for srv1. */ 949 + EXPECT_EQ(-EINVAL, bind_variant(unix_stream_fd, &self->srv1)) 950 + { 951 + TH_LOG("Wrong bind error: %s", strerror(errno)); 952 + } 953 + EXPECT_EQ(-EINVAL, connect_variant(unix_stream_fd, &self->srv1)); 954 + 955 + /* Checks unix datagram bind and connect for srv0. */ 956 + EXPECT_EQ(-EINVAL, bind_variant(unix_dgram_fd, &self->srv0)); 957 + EXPECT_EQ(-EINVAL, connect_variant(unix_dgram_fd, &self->srv0)); 958 + 959 + /* Checks unix datagram bind and connect for srv1. */ 960 + EXPECT_EQ(-EINVAL, bind_variant(unix_dgram_fd, &self->srv1)); 961 + EXPECT_EQ(-EINVAL, connect_variant(unix_dgram_fd, &self->srv1)); 962 + } 963 + 964 + FIXTURE(tcp_layers) 965 + { 966 + struct service_fixture srv0, srv1; 967 + }; 968 + 969 + FIXTURE_VARIANT(tcp_layers) 970 + { 971 + const size_t num_layers; 972 + const int domain; 973 + }; 974 + 975 + FIXTURE_SETUP(tcp_layers) 976 + { 977 + const struct protocol_variant prot = { 978 + .domain = variant->domain, 979 + .type = SOCK_STREAM, 980 + }; 981 + 982 + disable_caps(_metadata); 983 + 984 + ASSERT_EQ(0, set_service(&self->srv0, prot, 0)); 985 + ASSERT_EQ(0, set_service(&self->srv1, prot, 1)); 986 + 987 + setup_loopback(_metadata); 988 + }; 989 + 990 + FIXTURE_TEARDOWN(tcp_layers) 991 + { 992 + } 993 + 994 + /* clang-format off */ 995 + FIXTURE_VARIANT_ADD(tcp_layers, no_sandbox_with_ipv4) { 996 + /* clang-format on */ 997 + .domain = AF_INET, 998 + .num_layers = 0, 999 + }; 1000 + 1001 + /* clang-format off */ 1002 + FIXTURE_VARIANT_ADD(tcp_layers, one_sandbox_with_ipv4) { 1003 + /* clang-format on */ 1004 + .domain = AF_INET, 1005 + .num_layers = 1, 1006 + }; 1007 + 1008 + /* clang-format off */ 1009 + FIXTURE_VARIANT_ADD(tcp_layers, two_sandboxes_with_ipv4) { 1010 + /* clang-format on */ 1011 + .domain = AF_INET, 1012 + .num_layers = 2, 1013 + }; 1014 + 1015 + /* clang-format off */ 1016 + FIXTURE_VARIANT_ADD(tcp_layers, three_sandboxes_with_ipv4) { 1017 + /* clang-format on */ 1018 + .domain = AF_INET, 1019 + .num_layers = 3, 1020 + }; 1021 + 1022 + /* clang-format off */ 1023 + FIXTURE_VARIANT_ADD(tcp_layers, no_sandbox_with_ipv6) { 1024 + /* clang-format on */ 1025 + .domain = AF_INET6, 1026 + .num_layers = 0, 1027 + }; 1028 + 1029 + /* clang-format off */ 1030 + FIXTURE_VARIANT_ADD(tcp_layers, one_sandbox_with_ipv6) { 1031 + /* clang-format on */ 1032 + .domain = AF_INET6, 1033 + .num_layers = 1, 1034 + }; 1035 + 1036 + /* clang-format off */ 1037 + FIXTURE_VARIANT_ADD(tcp_layers, two_sandboxes_with_ipv6) { 1038 + /* clang-format on */ 1039 + .domain = AF_INET6, 1040 + .num_layers = 2, 1041 + }; 1042 + 1043 + /* clang-format off */ 1044 + FIXTURE_VARIANT_ADD(tcp_layers, three_sandboxes_with_ipv6) { 1045 + /* clang-format on */ 1046 + .domain = AF_INET6, 1047 + .num_layers = 3, 1048 + }; 1049 + 1050 + TEST_F(tcp_layers, ruleset_overlap) 1051 + { 1052 + const struct landlock_ruleset_attr ruleset_attr = { 1053 + .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | 1054 + LANDLOCK_ACCESS_NET_CONNECT_TCP, 1055 + }; 1056 + const struct landlock_net_port_attr tcp_bind = { 1057 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP, 1058 + .port = self->srv0.port, 1059 + }; 1060 + const struct landlock_net_port_attr tcp_bind_connect = { 1061 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP | 1062 + LANDLOCK_ACCESS_NET_CONNECT_TCP, 1063 + .port = self->srv0.port, 1064 + }; 1065 + 1066 + if (variant->num_layers >= 1) { 1067 + int ruleset_fd; 1068 + 1069 + ruleset_fd = landlock_create_ruleset(&ruleset_attr, 1070 + sizeof(ruleset_attr), 0); 1071 + ASSERT_LE(0, ruleset_fd); 1072 + 1073 + /* Allows bind. */ 1074 + ASSERT_EQ(0, 1075 + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1076 + &tcp_bind, 0)); 1077 + /* Also allows bind, but allows connect too. */ 1078 + ASSERT_EQ(0, 1079 + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1080 + &tcp_bind_connect, 0)); 1081 + enforce_ruleset(_metadata, ruleset_fd); 1082 + EXPECT_EQ(0, close(ruleset_fd)); 1083 + } 1084 + 1085 + if (variant->num_layers >= 2) { 1086 + int ruleset_fd; 1087 + 1088 + /* Creates another ruleset layer. */ 1089 + ruleset_fd = landlock_create_ruleset(&ruleset_attr, 1090 + sizeof(ruleset_attr), 0); 1091 + ASSERT_LE(0, ruleset_fd); 1092 + 1093 + /* Only allows bind. */ 1094 + ASSERT_EQ(0, 1095 + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1096 + &tcp_bind, 0)); 1097 + enforce_ruleset(_metadata, ruleset_fd); 1098 + EXPECT_EQ(0, close(ruleset_fd)); 1099 + } 1100 + 1101 + if (variant->num_layers >= 3) { 1102 + int ruleset_fd; 1103 + 1104 + /* Creates another ruleset layer. */ 1105 + ruleset_fd = landlock_create_ruleset(&ruleset_attr, 1106 + sizeof(ruleset_attr), 0); 1107 + ASSERT_LE(0, ruleset_fd); 1108 + 1109 + /* Try to allow bind and connect. */ 1110 + ASSERT_EQ(0, 1111 + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1112 + &tcp_bind_connect, 0)); 1113 + enforce_ruleset(_metadata, ruleset_fd); 1114 + EXPECT_EQ(0, close(ruleset_fd)); 1115 + } 1116 + 1117 + /* 1118 + * Forbids to connect to the socket because only one ruleset layer 1119 + * allows connect. 1120 + */ 1121 + test_bind_and_connect(_metadata, &self->srv0, false, 1122 + variant->num_layers >= 2); 1123 + } 1124 + 1125 + TEST_F(tcp_layers, ruleset_expand) 1126 + { 1127 + if (variant->num_layers >= 1) { 1128 + const struct landlock_ruleset_attr ruleset_attr = { 1129 + .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP, 1130 + }; 1131 + /* Allows bind for srv0. */ 1132 + const struct landlock_net_port_attr bind_srv0 = { 1133 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP, 1134 + .port = self->srv0.port, 1135 + }; 1136 + int ruleset_fd; 1137 + 1138 + ruleset_fd = landlock_create_ruleset(&ruleset_attr, 1139 + sizeof(ruleset_attr), 0); 1140 + ASSERT_LE(0, ruleset_fd); 1141 + ASSERT_EQ(0, 1142 + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1143 + &bind_srv0, 0)); 1144 + enforce_ruleset(_metadata, ruleset_fd); 1145 + EXPECT_EQ(0, close(ruleset_fd)); 1146 + } 1147 + 1148 + if (variant->num_layers >= 2) { 1149 + /* Expands network mask with connect action. */ 1150 + const struct landlock_ruleset_attr ruleset_attr = { 1151 + .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | 1152 + LANDLOCK_ACCESS_NET_CONNECT_TCP, 1153 + }; 1154 + /* Allows bind for srv0 and connect to srv0. */ 1155 + const struct landlock_net_port_attr tcp_bind_connect_p0 = { 1156 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP | 1157 + LANDLOCK_ACCESS_NET_CONNECT_TCP, 1158 + .port = self->srv0.port, 1159 + }; 1160 + /* Try to allow bind for srv1. */ 1161 + const struct landlock_net_port_attr tcp_bind_p1 = { 1162 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP, 1163 + .port = self->srv1.port, 1164 + }; 1165 + int ruleset_fd; 1166 + 1167 + ruleset_fd = landlock_create_ruleset(&ruleset_attr, 1168 + sizeof(ruleset_attr), 0); 1169 + ASSERT_LE(0, ruleset_fd); 1170 + ASSERT_EQ(0, 1171 + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1172 + &tcp_bind_connect_p0, 0)); 1173 + ASSERT_EQ(0, 1174 + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1175 + &tcp_bind_p1, 0)); 1176 + enforce_ruleset(_metadata, ruleset_fd); 1177 + EXPECT_EQ(0, close(ruleset_fd)); 1178 + } 1179 + 1180 + if (variant->num_layers >= 3) { 1181 + const struct landlock_ruleset_attr ruleset_attr = { 1182 + .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | 1183 + LANDLOCK_ACCESS_NET_CONNECT_TCP, 1184 + }; 1185 + /* Allows connect to srv0, without bind rule. */ 1186 + const struct landlock_net_port_attr tcp_bind_p0 = { 1187 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP, 1188 + .port = self->srv0.port, 1189 + }; 1190 + int ruleset_fd; 1191 + 1192 + ruleset_fd = landlock_create_ruleset(&ruleset_attr, 1193 + sizeof(ruleset_attr), 0); 1194 + ASSERT_LE(0, ruleset_fd); 1195 + ASSERT_EQ(0, 1196 + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1197 + &tcp_bind_p0, 0)); 1198 + enforce_ruleset(_metadata, ruleset_fd); 1199 + EXPECT_EQ(0, close(ruleset_fd)); 1200 + } 1201 + 1202 + test_bind_and_connect(_metadata, &self->srv0, false, 1203 + variant->num_layers >= 3); 1204 + 1205 + test_bind_and_connect(_metadata, &self->srv1, variant->num_layers >= 1, 1206 + variant->num_layers >= 2); 1207 + } 1208 + 1209 + /* clang-format off */ 1210 + FIXTURE(mini) {}; 1211 + /* clang-format on */ 1212 + 1213 + FIXTURE_SETUP(mini) 1214 + { 1215 + disable_caps(_metadata); 1216 + 1217 + setup_loopback(_metadata); 1218 + }; 1219 + 1220 + FIXTURE_TEARDOWN(mini) 1221 + { 1222 + } 1223 + 1224 + /* clang-format off */ 1225 + 1226 + #define ACCESS_LAST LANDLOCK_ACCESS_NET_CONNECT_TCP 1227 + 1228 + #define ACCESS_ALL ( \ 1229 + LANDLOCK_ACCESS_NET_BIND_TCP | \ 1230 + LANDLOCK_ACCESS_NET_CONNECT_TCP) 1231 + 1232 + /* clang-format on */ 1233 + 1234 + TEST_F(mini, network_access_rights) 1235 + { 1236 + const struct landlock_ruleset_attr ruleset_attr = { 1237 + .handled_access_net = ACCESS_ALL, 1238 + }; 1239 + struct landlock_net_port_attr net_port = { 1240 + .port = sock_port_start, 1241 + }; 1242 + int ruleset_fd; 1243 + __u64 access; 1244 + 1245 + ruleset_fd = 1246 + landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 1247 + ASSERT_LE(0, ruleset_fd); 1248 + 1249 + for (access = 1; access <= ACCESS_LAST; access <<= 1) { 1250 + net_port.allowed_access = access; 1251 + EXPECT_EQ(0, 1252 + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1253 + &net_port, 0)) 1254 + { 1255 + TH_LOG("Failed to add rule with access 0x%llx: %s", 1256 + access, strerror(errno)); 1257 + } 1258 + } 1259 + EXPECT_EQ(0, close(ruleset_fd)); 1260 + } 1261 + 1262 + /* Checks invalid attribute, out of landlock network access range. */ 1263 + TEST_F(mini, unknown_access_rights) 1264 + { 1265 + __u64 access_mask; 1266 + 1267 + for (access_mask = 1ULL << 63; access_mask != ACCESS_LAST; 1268 + access_mask >>= 1) { 1269 + const struct landlock_ruleset_attr ruleset_attr = { 1270 + .handled_access_net = access_mask, 1271 + }; 1272 + 1273 + EXPECT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 1274 + sizeof(ruleset_attr), 0)); 1275 + EXPECT_EQ(EINVAL, errno); 1276 + } 1277 + } 1278 + 1279 + TEST_F(mini, inval) 1280 + { 1281 + const struct landlock_ruleset_attr ruleset_attr = { 1282 + .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP 1283 + }; 1284 + const struct landlock_net_port_attr tcp_bind_connect = { 1285 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP | 1286 + LANDLOCK_ACCESS_NET_CONNECT_TCP, 1287 + .port = sock_port_start, 1288 + }; 1289 + const struct landlock_net_port_attr tcp_denied = { 1290 + .allowed_access = 0, 1291 + .port = sock_port_start, 1292 + }; 1293 + const struct landlock_net_port_attr tcp_bind = { 1294 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP, 1295 + .port = sock_port_start, 1296 + }; 1297 + int ruleset_fd; 1298 + 1299 + ruleset_fd = 1300 + landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 1301 + ASSERT_LE(0, ruleset_fd); 1302 + 1303 + /* Checks unhandled allowed_access. */ 1304 + EXPECT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1305 + &tcp_bind_connect, 0)); 1306 + EXPECT_EQ(EINVAL, errno); 1307 + 1308 + /* Checks zero access value. */ 1309 + EXPECT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1310 + &tcp_denied, 0)); 1311 + EXPECT_EQ(ENOMSG, errno); 1312 + 1313 + /* Adds with legitimate values. */ 1314 + ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1315 + &tcp_bind, 0)); 1316 + } 1317 + 1318 + TEST_F(mini, tcp_port_overflow) 1319 + { 1320 + const struct landlock_ruleset_attr ruleset_attr = { 1321 + .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | 1322 + LANDLOCK_ACCESS_NET_CONNECT_TCP, 1323 + }; 1324 + const struct landlock_net_port_attr port_max_bind = { 1325 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP, 1326 + .port = UINT16_MAX, 1327 + }; 1328 + const struct landlock_net_port_attr port_max_connect = { 1329 + .allowed_access = LANDLOCK_ACCESS_NET_CONNECT_TCP, 1330 + .port = UINT16_MAX, 1331 + }; 1332 + const struct landlock_net_port_attr port_overflow1 = { 1333 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP, 1334 + .port = UINT16_MAX + 1, 1335 + }; 1336 + const struct landlock_net_port_attr port_overflow2 = { 1337 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP, 1338 + .port = UINT16_MAX + 2, 1339 + }; 1340 + const struct landlock_net_port_attr port_overflow3 = { 1341 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP, 1342 + .port = UINT32_MAX + 1UL, 1343 + }; 1344 + const struct landlock_net_port_attr port_overflow4 = { 1345 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP, 1346 + .port = UINT32_MAX + 2UL, 1347 + }; 1348 + const struct protocol_variant ipv4_tcp = { 1349 + .domain = AF_INET, 1350 + .type = SOCK_STREAM, 1351 + }; 1352 + struct service_fixture srv_denied, srv_max_allowed; 1353 + int ruleset_fd; 1354 + 1355 + ASSERT_EQ(0, set_service(&srv_denied, ipv4_tcp, 0)); 1356 + 1357 + /* Be careful to avoid port inconsistencies. */ 1358 + srv_max_allowed = srv_denied; 1359 + srv_max_allowed.port = port_max_bind.port; 1360 + srv_max_allowed.ipv4_addr.sin_port = htons(port_max_bind.port); 1361 + 1362 + ruleset_fd = 1363 + landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 1364 + ASSERT_LE(0, ruleset_fd); 1365 + 1366 + ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1367 + &port_max_bind, 0)); 1368 + 1369 + EXPECT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1370 + &port_overflow1, 0)); 1371 + EXPECT_EQ(EINVAL, errno); 1372 + 1373 + EXPECT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1374 + &port_overflow2, 0)); 1375 + EXPECT_EQ(EINVAL, errno); 1376 + 1377 + EXPECT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1378 + &port_overflow3, 0)); 1379 + EXPECT_EQ(EINVAL, errno); 1380 + 1381 + /* Interleaves with invalid rule additions. */ 1382 + ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1383 + &port_max_connect, 0)); 1384 + 1385 + EXPECT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1386 + &port_overflow4, 0)); 1387 + EXPECT_EQ(EINVAL, errno); 1388 + 1389 + enforce_ruleset(_metadata, ruleset_fd); 1390 + 1391 + test_bind_and_connect(_metadata, &srv_denied, true, true); 1392 + test_bind_and_connect(_metadata, &srv_max_allowed, false, false); 1393 + } 1394 + 1395 + FIXTURE(ipv4_tcp) 1396 + { 1397 + struct service_fixture srv0, srv1; 1398 + }; 1399 + 1400 + FIXTURE_SETUP(ipv4_tcp) 1401 + { 1402 + const struct protocol_variant ipv4_tcp = { 1403 + .domain = AF_INET, 1404 + .type = SOCK_STREAM, 1405 + }; 1406 + 1407 + disable_caps(_metadata); 1408 + 1409 + ASSERT_EQ(0, set_service(&self->srv0, ipv4_tcp, 0)); 1410 + ASSERT_EQ(0, set_service(&self->srv1, ipv4_tcp, 1)); 1411 + 1412 + setup_loopback(_metadata); 1413 + }; 1414 + 1415 + FIXTURE_TEARDOWN(ipv4_tcp) 1416 + { 1417 + } 1418 + 1419 + TEST_F(ipv4_tcp, port_endianness) 1420 + { 1421 + const struct landlock_ruleset_attr ruleset_attr = { 1422 + .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | 1423 + LANDLOCK_ACCESS_NET_CONNECT_TCP, 1424 + }; 1425 + const struct landlock_net_port_attr bind_host_endian_p0 = { 1426 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP, 1427 + /* Host port format. */ 1428 + .port = self->srv0.port, 1429 + }; 1430 + const struct landlock_net_port_attr connect_big_endian_p0 = { 1431 + .allowed_access = LANDLOCK_ACCESS_NET_CONNECT_TCP, 1432 + /* Big endian port format. */ 1433 + .port = htons(self->srv0.port), 1434 + }; 1435 + const struct landlock_net_port_attr bind_connect_host_endian_p1 = { 1436 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP | 1437 + LANDLOCK_ACCESS_NET_CONNECT_TCP, 1438 + /* Host port format. */ 1439 + .port = self->srv1.port, 1440 + }; 1441 + const unsigned int one = 1; 1442 + const char little_endian = *(const char *)&one; 1443 + int ruleset_fd; 1444 + 1445 + ruleset_fd = 1446 + landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 1447 + ASSERT_LE(0, ruleset_fd); 1448 + ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1449 + &bind_host_endian_p0, 0)); 1450 + ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1451 + &connect_big_endian_p0, 0)); 1452 + ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1453 + &bind_connect_host_endian_p1, 0)); 1454 + enforce_ruleset(_metadata, ruleset_fd); 1455 + 1456 + /* No restriction for big endinan CPU. */ 1457 + test_bind_and_connect(_metadata, &self->srv0, false, little_endian); 1458 + 1459 + /* No restriction for any CPU. */ 1460 + test_bind_and_connect(_metadata, &self->srv1, false, false); 1461 + } 1462 + 1463 + TEST_F(ipv4_tcp, with_fs) 1464 + { 1465 + const struct landlock_ruleset_attr ruleset_attr_fs_net = { 1466 + .handled_access_fs = LANDLOCK_ACCESS_FS_READ_DIR, 1467 + .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP, 1468 + }; 1469 + struct landlock_path_beneath_attr path_beneath = { 1470 + .allowed_access = LANDLOCK_ACCESS_FS_READ_DIR, 1471 + .parent_fd = -1, 1472 + }; 1473 + struct landlock_net_port_attr tcp_bind = { 1474 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP, 1475 + .port = self->srv0.port, 1476 + }; 1477 + int ruleset_fd, bind_fd, dir_fd; 1478 + 1479 + /* Creates ruleset both for filesystem and network access. */ 1480 + ruleset_fd = landlock_create_ruleset(&ruleset_attr_fs_net, 1481 + sizeof(ruleset_attr_fs_net), 0); 1482 + ASSERT_LE(0, ruleset_fd); 1483 + 1484 + /* Adds a filesystem rule. */ 1485 + path_beneath.parent_fd = open("/dev", O_PATH | O_DIRECTORY | O_CLOEXEC); 1486 + ASSERT_LE(0, path_beneath.parent_fd); 1487 + ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 1488 + &path_beneath, 0)); 1489 + EXPECT_EQ(0, close(path_beneath.parent_fd)); 1490 + 1491 + /* Adds a network rule. */ 1492 + ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1493 + &tcp_bind, 0)); 1494 + 1495 + enforce_ruleset(_metadata, ruleset_fd); 1496 + EXPECT_EQ(0, close(ruleset_fd)); 1497 + 1498 + /* Tests file access. */ 1499 + dir_fd = open("/dev", O_RDONLY); 1500 + EXPECT_LE(0, dir_fd); 1501 + EXPECT_EQ(0, close(dir_fd)); 1502 + 1503 + dir_fd = open("/", O_RDONLY); 1504 + EXPECT_EQ(-1, dir_fd); 1505 + EXPECT_EQ(EACCES, errno); 1506 + 1507 + /* Tests port binding. */ 1508 + bind_fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0); 1509 + ASSERT_LE(0, bind_fd); 1510 + EXPECT_EQ(0, bind_variant(bind_fd, &self->srv0)); 1511 + EXPECT_EQ(0, close(bind_fd)); 1512 + 1513 + bind_fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0); 1514 + ASSERT_LE(0, bind_fd); 1515 + EXPECT_EQ(-EACCES, bind_variant(bind_fd, &self->srv1)); 1516 + } 1517 + 1518 + FIXTURE(port_specific) 1519 + { 1520 + struct service_fixture srv0; 1521 + }; 1522 + 1523 + FIXTURE_VARIANT(port_specific) 1524 + { 1525 + const enum sandbox_type sandbox; 1526 + const struct protocol_variant prot; 1527 + }; 1528 + 1529 + /* clang-format off */ 1530 + FIXTURE_VARIANT_ADD(port_specific, no_sandbox_with_ipv4) { 1531 + /* clang-format on */ 1532 + .sandbox = NO_SANDBOX, 1533 + .prot = { 1534 + .domain = AF_INET, 1535 + .type = SOCK_STREAM, 1536 + }, 1537 + }; 1538 + 1539 + /* clang-format off */ 1540 + FIXTURE_VARIANT_ADD(port_specific, sandbox_with_ipv4) { 1541 + /* clang-format on */ 1542 + .sandbox = TCP_SANDBOX, 1543 + .prot = { 1544 + .domain = AF_INET, 1545 + .type = SOCK_STREAM, 1546 + }, 1547 + }; 1548 + 1549 + /* clang-format off */ 1550 + FIXTURE_VARIANT_ADD(port_specific, no_sandbox_with_ipv6) { 1551 + /* clang-format on */ 1552 + .sandbox = NO_SANDBOX, 1553 + .prot = { 1554 + .domain = AF_INET6, 1555 + .type = SOCK_STREAM, 1556 + }, 1557 + }; 1558 + 1559 + /* clang-format off */ 1560 + FIXTURE_VARIANT_ADD(port_specific, sandbox_with_ipv6) { 1561 + /* clang-format on */ 1562 + .sandbox = TCP_SANDBOX, 1563 + .prot = { 1564 + .domain = AF_INET6, 1565 + .type = SOCK_STREAM, 1566 + }, 1567 + }; 1568 + 1569 + FIXTURE_SETUP(port_specific) 1570 + { 1571 + disable_caps(_metadata); 1572 + 1573 + ASSERT_EQ(0, set_service(&self->srv0, variant->prot, 0)); 1574 + 1575 + setup_loopback(_metadata); 1576 + }; 1577 + 1578 + FIXTURE_TEARDOWN(port_specific) 1579 + { 1580 + } 1581 + 1582 + TEST_F(port_specific, bind_connect_zero) 1583 + { 1584 + int bind_fd, connect_fd, ret; 1585 + uint16_t port; 1586 + 1587 + /* Adds a rule layer with bind and connect actions. */ 1588 + if (variant->sandbox == TCP_SANDBOX) { 1589 + const struct landlock_ruleset_attr ruleset_attr = { 1590 + .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | 1591 + LANDLOCK_ACCESS_NET_CONNECT_TCP 1592 + }; 1593 + const struct landlock_net_port_attr tcp_bind_connect_zero = { 1594 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP | 1595 + LANDLOCK_ACCESS_NET_CONNECT_TCP, 1596 + .port = 0, 1597 + }; 1598 + int ruleset_fd; 1599 + 1600 + ruleset_fd = landlock_create_ruleset(&ruleset_attr, 1601 + sizeof(ruleset_attr), 0); 1602 + ASSERT_LE(0, ruleset_fd); 1603 + 1604 + /* Checks zero port value on bind and connect actions. */ 1605 + EXPECT_EQ(0, 1606 + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1607 + &tcp_bind_connect_zero, 0)); 1608 + 1609 + enforce_ruleset(_metadata, ruleset_fd); 1610 + EXPECT_EQ(0, close(ruleset_fd)); 1611 + } 1612 + 1613 + bind_fd = socket_variant(&self->srv0); 1614 + ASSERT_LE(0, bind_fd); 1615 + 1616 + connect_fd = socket_variant(&self->srv0); 1617 + ASSERT_LE(0, connect_fd); 1618 + 1619 + /* Sets address port to 0 for both protocol families. */ 1620 + set_port(&self->srv0, 0); 1621 + /* 1622 + * Binds on port 0, which selects a random port within 1623 + * ip_local_port_range. 1624 + */ 1625 + ret = bind_variant(bind_fd, &self->srv0); 1626 + EXPECT_EQ(0, ret); 1627 + 1628 + EXPECT_EQ(0, listen(bind_fd, backlog)); 1629 + 1630 + /* Connects on port 0. */ 1631 + ret = connect_variant(connect_fd, &self->srv0); 1632 + EXPECT_EQ(-ECONNREFUSED, ret); 1633 + 1634 + /* Sets binded port for both protocol families. */ 1635 + port = get_binded_port(bind_fd, &variant->prot); 1636 + EXPECT_NE(0, port); 1637 + set_port(&self->srv0, port); 1638 + /* Connects on the binded port. */ 1639 + ret = connect_variant(connect_fd, &self->srv0); 1640 + if (is_restricted(&variant->prot, variant->sandbox)) { 1641 + /* Denied by Landlock. */ 1642 + EXPECT_EQ(-EACCES, ret); 1643 + } else { 1644 + EXPECT_EQ(0, ret); 1645 + } 1646 + 1647 + EXPECT_EQ(0, close(connect_fd)); 1648 + EXPECT_EQ(0, close(bind_fd)); 1649 + } 1650 + 1651 + TEST_F(port_specific, bind_connect_1023) 1652 + { 1653 + int bind_fd, connect_fd, ret; 1654 + 1655 + /* Adds a rule layer with bind and connect actions. */ 1656 + if (variant->sandbox == TCP_SANDBOX) { 1657 + const struct landlock_ruleset_attr ruleset_attr = { 1658 + .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | 1659 + LANDLOCK_ACCESS_NET_CONNECT_TCP 1660 + }; 1661 + /* A rule with port value less than 1024. */ 1662 + const struct landlock_net_port_attr tcp_bind_connect_low_range = { 1663 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP | 1664 + LANDLOCK_ACCESS_NET_CONNECT_TCP, 1665 + .port = 1023, 1666 + }; 1667 + /* A rule with 1024 port. */ 1668 + const struct landlock_net_port_attr tcp_bind_connect = { 1669 + .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP | 1670 + LANDLOCK_ACCESS_NET_CONNECT_TCP, 1671 + .port = 1024, 1672 + }; 1673 + int ruleset_fd; 1674 + 1675 + ruleset_fd = landlock_create_ruleset(&ruleset_attr, 1676 + sizeof(ruleset_attr), 0); 1677 + ASSERT_LE(0, ruleset_fd); 1678 + 1679 + ASSERT_EQ(0, 1680 + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1681 + &tcp_bind_connect_low_range, 0)); 1682 + ASSERT_EQ(0, 1683 + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, 1684 + &tcp_bind_connect, 0)); 1685 + 1686 + enforce_ruleset(_metadata, ruleset_fd); 1687 + EXPECT_EQ(0, close(ruleset_fd)); 1688 + } 1689 + 1690 + bind_fd = socket_variant(&self->srv0); 1691 + ASSERT_LE(0, bind_fd); 1692 + 1693 + connect_fd = socket_variant(&self->srv0); 1694 + ASSERT_LE(0, connect_fd); 1695 + 1696 + /* Sets address port to 1023 for both protocol families. */ 1697 + set_port(&self->srv0, 1023); 1698 + /* Binds on port 1023. */ 1699 + ret = bind_variant(bind_fd, &self->srv0); 1700 + /* Denied by the system. */ 1701 + EXPECT_EQ(-EACCES, ret); 1702 + 1703 + /* Binds on port 1023. */ 1704 + set_cap(_metadata, CAP_NET_BIND_SERVICE); 1705 + ret = bind_variant(bind_fd, &self->srv0); 1706 + clear_cap(_metadata, CAP_NET_BIND_SERVICE); 1707 + EXPECT_EQ(0, ret); 1708 + EXPECT_EQ(0, listen(bind_fd, backlog)); 1709 + 1710 + /* Connects on the binded port 1023. */ 1711 + ret = connect_variant(connect_fd, &self->srv0); 1712 + EXPECT_EQ(0, ret); 1713 + 1714 + EXPECT_EQ(0, close(connect_fd)); 1715 + EXPECT_EQ(0, close(bind_fd)); 1716 + 1717 + bind_fd = socket_variant(&self->srv0); 1718 + ASSERT_LE(0, bind_fd); 1719 + 1720 + connect_fd = socket_variant(&self->srv0); 1721 + ASSERT_LE(0, connect_fd); 1722 + 1723 + /* Sets address port to 1024 for both protocol families. */ 1724 + set_port(&self->srv0, 1024); 1725 + /* Binds on port 1024. */ 1726 + ret = bind_variant(bind_fd, &self->srv0); 1727 + EXPECT_EQ(0, ret); 1728 + EXPECT_EQ(0, listen(bind_fd, backlog)); 1729 + 1730 + /* Connects on the binded port 1024. */ 1731 + ret = connect_variant(connect_fd, &self->srv0); 1732 + EXPECT_EQ(0, ret); 1733 + 1734 + EXPECT_EQ(0, close(connect_fd)); 1735 + EXPECT_EQ(0, close(bind_fd)); 1736 + } 1737 + 1738 + TEST_HARNESS_MAIN