History

landlock: Support network rules with TCP bind and connect

Add network rules support in the ruleset management helpers and the landlock_create_ruleset() syscall. Extend user space API to support network actions: * Add new network access rights: LANDLOCK_ACCESS_NET_BIND_TCP and LANDLOCK_ACCESS_NET_CONNECT_TCP. * Add a new network rule type: LANDLOCK_RULE_NET_PORT tied to struct landlock_net_port_attr. The allowed_access field contains the network access rights, and the port field contains the port value according to the controlled protocol. This field can take up to a 64-bit value but the maximum value depends on the related protocol (e.g. 16-bit value for TCP). Network port is in host endianness [1]. * Add a new handled_access_net field to struct landlock_ruleset_attr that contains network access rights. * Increment the Landlock ABI version to 4. Implement socket_bind() and socket_connect() LSM hooks, which enable to control TCP socket binding and connection to specific ports. Expand access_masks_t from u16 to u32 to be able to store network access rights alongside filesystem access rights for rulesets' handled access rights. Access rights are not tied to socket file descriptors but checked at bind() or connect() call time against the caller's Landlock domain. For the filesystem, a file descriptor is a direct access to a file/data. However, for network sockets, we cannot identify for which data or peer a newly created socket will give access to. Indeed, we need to wait for a connect or bind request to identify the use case for this socket. Likewise a directory file descriptor may enable to open another file (i.e. a new data item), but this opening is also restricted by the caller's domain, not the file descriptor's access rights [2]. [1] https://lore.kernel.org/r/278ab07f-7583-a4e0-3d37-1bacd091531d@digikod.net [2] https://lore.kernel.org/r/263c1eb3-602f-57fe-8450-3f138581bee7@digikod.net

Konstantin Meskhidze committed 3 years ago

Commit fff69fb1 parent 0e0fc7e11 files · +470 −25Browse files

Unified · Split

11 files
  1. include/uapi/linux/landlock.h +55 −0
  2. security/landlock/Kconfig +1 −0
  3. security/landlock/Makefile +2 −0
  4. security/landlock/limits.h +5 −0
  5. security/landlock/net.c +200 −0
  6. security/landlock/net.h +33 −0
  7. security/landlock/ruleset.c +56 −5
  8. security/landlock/ruleset.h +52 −10
  9. security/landlock/setup.c +2 −0
  10. security/landlock/syscalls.c +63 −9
  11. tools/testing/selftests/landlock/base_test.c +1 −1
include/uapi/linux/landlock.h+55−0
@@ -31,6 +31,12 @@ struct landlock_ruleset_attr { · 30 unmodified lines
3131 * this access right.
3232 */
3333 __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;
3440 };
3541
3642 /*
@@ -54,6 +60,11 @@ enum landlock_rule_type { · 17 unmodified lines
5460 * landlock_path_beneath_attr .
5561 */
5662 LANDLOCK_RULE_PATH_BENEATH = 1,
63+ /**
64+ * @LANDLOCK_RULE_NET_PORT: Type of a &struct
65+ * landlock_net_port_attr .
66+ */
67+ LANDLOCK_RULE_NET_PORT,
5768 };
5869
5970 /**
@@ -79,6 +90,31 @@ struct landlock_path_beneath_attr { · 19 unmodified lines
7990 */
8091 } __attribute__((packed));
8192
93+/**
94+ * struct landlock_net_port_attr - Network port definition
95+ *
96+ * Argument of sys_landlock_add_rule().
97+ */
98+struct landlock_net_port_attr {
99+ /**
100+ * @allowed_access: Bitmask of allowed access network for a port
101+ * (cf. `Network flags`_).
102+ */
103+ __u64 allowed_access;
104+ /**
105+ * @port: Network port in host endianness.
106+ *
107+ * It should be noted that port 0 passed to :manpage:`bind(2)` will
108+ * bind to an available port from a specific port range. This can be
109+ * configured thanks to the ``/proc/sys/net/ipv4/ip_local_port_range``
110+ * sysctl (also used for IPv6). A Landlock rule with port 0 and the
111+ * ``LANDLOCK_ACCESS_NET_BIND_TCP`` right means that requesting to bind
112+ * on port 0 is allowed and it will automatically translate to binding
113+ * on the related port range.
114+ */
115+ __u64 port;
116+};
117+
82118 /**
83119 * DOC: fs_access
84120 *
@@ -189,4 +225,23 @@ struct landlock_path_beneath_attr { · 104 unmodified lines
189225 #define LANDLOCK_ACCESS_FS_TRUNCATE (1ULL << 14)
190226 /* clang-format on */
191227
228+/**
229+ * DOC: net_access
230+ *
231+ * Network flags
232+ * ~~~~~~~~~~~~~~~~
233+ *
234+ * These flags enable to restrict a sandboxed process to a set of network
235+ * actions. This is supported since the Landlock ABI version 4.
236+ *
237+ * TCP sockets with allowed actions:
238+ *
239+ * - %LANDLOCK_ACCESS_NET_BIND_TCP: Bind a TCP socket to a local port.
240+ * - %LANDLOCK_ACCESS_NET_CONNECT_TCP: Connect an active TCP socket to
241+ * a remote port.
242+ */
243+/* clang-format off */
244+#define LANDLOCK_ACCESS_NET_BIND_TCP (1ULL << 0)
245+#define LANDLOCK_ACCESS_NET_CONNECT_TCP (1ULL << 1)
246+/* clang-format on */
192247 #endif /* _UAPI_LINUX_LANDLOCK_H */
security/landlock/Kconfig+1−0
@@ -3,6 +3,7 @@ · 2 unmodified lines
33 config SECURITY_LANDLOCK
44 bool "Landlock support"
55 depends on SECURITY
6+ select SECURITY_NETWORK
67 select SECURITY_PATH
78 help
89 Landlock is a sandboxing mechanism that enables processes to restrict
security/landlock/Makefile+2−0
@@ -2,3 +2,5 @@ obj-$(CONFIG_SECURITY_LANDLOCK) := landlock.o · 1 unmodified line
22
33 landlock-y := setup.o syscalls.o object.o ruleset.o \
44 cred.o ptrace.o fs.o
5+
6+landlock-$(CONFIG_INET) += net.o
security/landlock/limits.h+5−0
@@ -23,6 +23,11 @@ · 22 unmodified lines
2323 #define LANDLOCK_NUM_ACCESS_FS __const_hweight64(LANDLOCK_MASK_ACCESS_FS)
2424 #define LANDLOCK_SHIFT_ACCESS_FS 0
2525
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
30+
2631 /* clang-format on */
2732
2833 #endif /* _SECURITY_LANDLOCK_LIMITS_H */
security/landlock/net.c+200−0
@@ -0,0 +1,200 @@
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+}
security/landlock/net.h+33−0
@@ -0,0 +1,33 @@
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 */
security/landlock/ruleset.c+56−5
@@ -36,6 +36,11 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers) · 35 unmodified lines
3636 refcount_set(&new_ruleset->usage, 1);
3737 mutex_init(&new_ruleset->lock);
3838 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+
3944 new_ruleset->num_layers = num_layers;
4045 /*
4146 * hierarchy = NULL
@@ -46,16 +51,21 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers) · 4 unmodified lines
4651 }
4752
4853 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)
5056 {
5157 struct landlock_ruleset *new_ruleset;
5258
5359 /* Informs about useless ruleset. */
54− if (!fs_access_mask)
60+ if (!fs_access_mask && !net_access_mask)
5561 return ERR_PTR(-ENOMSG);
5662 new_ruleset = create_ruleset(1);
57− if (!IS_ERR(new_ruleset))
63+ if (IS_ERR(new_ruleset))
64+ return new_ruleset;
65+ if (fs_access_mask)
5866 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);
5969 return new_ruleset;
6070 }
6171
@@ -74,6 +84,11 @@ static bool is_object_pointer(const enum landlock_key_type key_type) · 12 unmodified lines
7484 case LANDLOCK_KEY_INODE:
7585 return true;
7686
87+#if IS_ENABLED(CONFIG_INET)
88+ case LANDLOCK_KEY_NET_PORT:
89+ return false;
90+#endif /* IS_ENABLED(CONFIG_INET) */
91+
7792 default:
7893 WARN_ON_ONCE(1);
7994 return false;
@@ -126,6 +141,11 @@ static struct rb_root *get_root(struct landlock_ruleset *const ruleset, · 46 unmodified lines
126141 case LANDLOCK_KEY_INODE:
127142 return &ruleset->root_inode;
128143
144+#if IS_ENABLED(CONFIG_INET)
145+ case LANDLOCK_KEY_NET_PORT:
146+ return &ruleset->root_net_port;
147+#endif /* IS_ENABLED(CONFIG_INET) */
148+
129149 default:
130150 WARN_ON_ONCE(1);
131151 return ERR_PTR(-EINVAL);
@@ -154,7 +174,8 @@ static void build_check_ruleset(void) · 22 unmodified lines
154174 BUILD_BUG_ON(ruleset.num_rules < LANDLOCK_MAX_NUM_RULES);
155175 BUILD_BUG_ON(ruleset.num_layers < LANDLOCK_MAX_NUM_LAYERS);
156176 BUILD_BUG_ON(access_masks <
157− (LANDLOCK_MASK_ACCESS_FS << LANDLOCK_SHIFT_ACCESS_FS));
177+ ((LANDLOCK_MASK_ACCESS_FS << LANDLOCK_SHIFT_ACCESS_FS) |
178+ (LANDLOCK_MASK_ACCESS_NET << LANDLOCK_SHIFT_ACCESS_NET)));
158179 }
159180
160181 /**
@@ -371,6 +392,13 @@ static int merge_ruleset(struct landlock_ruleset *const dst, · 210 unmodified lines
371392 if (err)
372393 goto out_unlock;
373394
395+#if IS_ENABLED(CONFIG_INET)
396+ /* Merges the @src network port tree. */
397+ err = merge_tree(dst, src, LANDLOCK_KEY_NET_PORT);
398+ if (err)
399+ goto out_unlock;
400+#endif /* IS_ENABLED(CONFIG_INET) */
401+
374402 out_unlock:
375403 mutex_unlock(&src->lock);
376404 mutex_unlock(&dst->lock);
@@ -427,6 +455,13 @@ static int inherit_ruleset(struct landlock_ruleset *const parent, · 50 unmodified lines
427455 if (err)
428456 goto out_unlock;
429457
458+#if IS_ENABLED(CONFIG_INET)
459+ /* Copies the @parent network port tree. */
460+ err = inherit_tree(parent, child, LANDLOCK_KEY_NET_PORT);
461+ if (err)
462+ goto out_unlock;
463+#endif /* IS_ENABLED(CONFIG_INET) */
464+
430465 if (WARN_ON_ONCE(child->num_layers <= parent->num_layers)) {
431466 err = -EINVAL;
432467 goto out_unlock;
@@ -456,6 +491,13 @@ static void free_ruleset(struct landlock_ruleset *const ruleset) · 23 unmodified lines
456491 rbtree_postorder_for_each_entry_safe(freeme, next, &ruleset->root_inode,
457492 node)
458493 free_rule(freeme, LANDLOCK_KEY_INODE);
494+
495+#if IS_ENABLED(CONFIG_INET)
496+ rbtree_postorder_for_each_entry_safe(freeme, next,
497+ &ruleset->root_net_port, node)
498+ free_rule(freeme, LANDLOCK_KEY_NET_PORT);
499+#endif /* IS_ENABLED(CONFIG_INET) */
500+
459501 put_hierarchy(ruleset->hierarchy);
460502 kfree(ruleset);
461503 }
@@ -636,7 +678,8 @@ get_access_mask_t(const struct landlock_ruleset *const ruleset, · 174 unmodified lines
636678 *
637679 * @domain: The domain that defines the current restrictions.
638680 * @access_request: The requested access rights to check.
639− * @layer_masks: The layer masks to populate.
681+ * @layer_masks: It must contain %LANDLOCK_NUM_ACCESS_FS or
682+ * %LANDLOCK_NUM_ACCESS_NET elements according to @key_type.
640683 * @key_type: The key type to switch between access masks of different types.
641684 *
642685 * Returns: An access mask where each access right bit is set which is handled
@@ -657,6 +700,14 @@ landlock_init_layer_masks(const struct landlock_ruleset *const domain, · 14 unmodified lines
657700 get_access_mask = landlock_get_fs_access_mask;
658701 num_access = LANDLOCK_NUM_ACCESS_FS;
659702 break;
703+
704+#if IS_ENABLED(CONFIG_INET)
705+ case LANDLOCK_KEY_NET_PORT:
706+ get_access_mask = landlock_get_net_access_mask;
707+ num_access = LANDLOCK_NUM_ACCESS_NET;
708+ break;
709+#endif /* IS_ENABLED(CONFIG_INET) */
710+
660711 default:
661712 WARN_ON_ONCE(1);
662713 return 0;
security/landlock/ruleset.h+52−10
@@ -33,13 +33,16 @@ · 32 unmodified lines
3333 typedef u16 access_mask_t;
3434 /* Makes sure all filesystem access rights can be stored. */
3535 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);
3638 /* Makes sure for_each_set_bit() and for_each_clear_bit() calls are OK. */
3739 static_assert(sizeof(unsigned long) >= sizeof(access_mask_t));
3840
3941 /* Ruleset access masks. */
40−typedef u16 access_masks_t;
42+typedef u32 access_masks_t;
4143 /* Makes sure all ruleset access rights can be stored. */
42−static_assert(BITS_PER_TYPE(access_masks_t) >= LANDLOCK_NUM_ACCESS_FS);
44+static_assert(BITS_PER_TYPE(access_masks_t) >=
45+ LANDLOCK_NUM_ACCESS_FS + LANDLOCK_NUM_ACCESS_NET);
4346
4447 typedef u16 layer_mask_t;
4548 /* Makes sure all layers can be checked. */
@@ -84,6 +87,11 @@ enum landlock_key_type { · 38 unmodified lines
8487 * keys.
8588 */
8689 LANDLOCK_KEY_INODE = 1,
90+ /**
91+ * @LANDLOCK_KEY_NET_PORT: Type of &landlock_ruleset.root_net_port's
92+ * node keys.
93+ */
94+ LANDLOCK_KEY_NET_PORT,
8795 };
8896
8997 /**
@@ -158,6 +166,17 @@ struct landlock_ruleset { · 68 unmodified lines
158166 * reaches zero.
159167 */
160168 struct rb_root root_inode;
169+
170+#if IS_ENABLED(CONFIG_INET)
171+ /**
172+ * @root_net_port: Root of a red-black tree containing &struct
173+ * landlock_rule nodes with network port. Once a ruleset is tied to a
174+ * process (i.e. as a domain), this tree is immutable until @usage
175+ * reaches zero.
176+ */
177+ struct rb_root root_net_port;
178+#endif /* IS_ENABLED(CONFIG_INET) */
179+
161180 /**
162181 * @hierarchy: Enables hierarchy identification even when a parent
163182 * domain vanishes. This is needed for the ptrace protection.
@@ -196,13 +215,13 @@ struct landlock_ruleset { · 32 unmodified lines
196215 */
197216 u32 num_layers;
198217 /**
199− * @access_masks: Contains the subset of filesystem
200− * actions that are restricted by a ruleset. A domain
201− * saves all layers of merged rulesets in a stack
202− * (FAM), starting from the first layer to the last
203− * one. These layers are used when merging rulesets,
204− * for user space backward compatibility (i.e.
205− * future-proof), and to properly handle merged
218+ * @access_masks: Contains the subset of filesystem and
219+ * network actions that are restricted by a ruleset.
220+ * A domain saves all layers of merged rulesets in a
221+ * stack (FAM), starting from the first layer to the
222+ * last one. These layers are used when merging
223+ * rulesets, for user space backward compatibility
224+ * (i.e. future-proof), and to properly handle merged
206225 * rulesets without overlapping access rights. These
207226 * layers are set once and never changed for the
208227 * lifetime of the ruleset.
@@ -213,7 +232,8 @@ struct landlock_ruleset { · 4 unmodified lines
213232 };
214233
215234 struct landlock_ruleset *
216−landlock_create_ruleset(const access_mask_t access_mask);
235+landlock_create_ruleset(const access_mask_t access_mask_fs,
236+ const access_mask_t access_mask_net);
217237
218238 void landlock_put_ruleset(struct landlock_ruleset *const ruleset);
219239 void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset);
@@ -249,6 +269,19 @@ landlock_add_fs_access_mask(struct landlock_ruleset *const ruleset, · 29 unmodified lines
249269 (fs_mask << LANDLOCK_SHIFT_ACCESS_FS);
250270 }
251271
272+static inline void
273+landlock_add_net_access_mask(struct landlock_ruleset *const ruleset,
274+ const access_mask_t net_access_mask,
275+ const u16 layer_level)
276+{
277+ access_mask_t net_mask = net_access_mask & LANDLOCK_MASK_ACCESS_NET;
278+
279+ /* Should already be checked in sys_landlock_create_ruleset(). */
280+ WARN_ON_ONCE(net_access_mask != net_mask);
281+ ruleset->access_masks[layer_level] |=
282+ (net_mask << LANDLOCK_SHIFT_ACCESS_NET);
283+}
284+
252285 static inline access_mask_t
253286 landlock_get_raw_fs_access_mask(const struct landlock_ruleset *const ruleset,
254287 const u16 layer_level)
@@ -267,6 +300,15 @@ landlock_get_fs_access_mask(const struct landlock_ruleset *const ruleset, · 12 unmodified lines
267300 LANDLOCK_ACCESS_FS_INITIALLY_DENIED;
268301 }
269302
303+static inline access_mask_t
304+landlock_get_net_access_mask(const struct landlock_ruleset *const ruleset,
305+ const u16 layer_level)
306+{
307+ return (ruleset->access_masks[layer_level] >>
308+ LANDLOCK_SHIFT_ACCESS_NET) &
309+ LANDLOCK_MASK_ACCESS_NET;
310+}
311+
270312 bool landlock_unmask_layers(const struct landlock_rule *const rule,
271313 const access_mask_t access_request,
272314 layer_mask_t (*const layer_masks)[],
security/landlock/setup.c+2−0
@@ -12,6 +12,7 @@ · 11 unmodified lines
1212 #include "common.h"
1313 #include "cred.h"
1414 #include "fs.h"
15+#include "net.h"
1516 #include "ptrace.h"
1617 #include "setup.h"
1718
@@ -29,6 +30,7 @@ static int __init landlock_init(void) · 11 unmodified lines
2930 landlock_add_cred_hooks();
3031 landlock_add_ptrace_hooks();
3132 landlock_add_fs_hooks();
33+ landlock_add_net_hooks();
3234 landlock_initialized = true;
3335 pr_info("Up and running.\n");
3436 return 0;
security/landlock/syscalls.c+63−9
@@ -29,6 +29,7 @@ · 28 unmodified lines
2929 #include "cred.h"
3030 #include "fs.h"
3131 #include "limits.h"
32+#include "net.h"
3233 #include "ruleset.h"
3334 #include "setup.h"
3435
@@ -74,7 +75,8 @@ static void build_check_abi(void) · 39 unmodified lines
7475 {
7576 struct landlock_ruleset_attr ruleset_attr;
7677 struct landlock_path_beneath_attr path_beneath_attr;
77− size_t ruleset_size, path_beneath_size;
78+ struct landlock_net_port_attr net_port_attr;
79+ size_t ruleset_size, path_beneath_size, net_port_size;
7880
7981 /*
8082 * For each user space ABI structures, first checks that there is no
@@ -82,13 +84,19 @@ static void build_check_abi(void) · 1 unmodified line
8284 * struct size.
8385 */
8486 ruleset_size = sizeof(ruleset_attr.handled_access_fs);
87+ ruleset_size += sizeof(ruleset_attr.handled_access_net);
8588 BUILD_BUG_ON(sizeof(ruleset_attr) != ruleset_size);
86− BUILD_BUG_ON(sizeof(ruleset_attr) != 8);
89+ BUILD_BUG_ON(sizeof(ruleset_attr) != 16);
8790
8891 path_beneath_size = sizeof(path_beneath_attr.allowed_access);
8992 path_beneath_size += sizeof(path_beneath_attr.parent_fd);
9093 BUILD_BUG_ON(sizeof(path_beneath_attr) != path_beneath_size);
9194 BUILD_BUG_ON(sizeof(path_beneath_attr) != 12);
95+
96+ net_port_size = sizeof(net_port_attr.allowed_access);
97+ net_port_size += sizeof(net_port_attr.port);
98+ BUILD_BUG_ON(sizeof(net_port_attr) != net_port_size);
99+ BUILD_BUG_ON(sizeof(net_port_attr) != 16);
92100 }
93101
94102 /* Ruleset handling */
@@ -129,7 +137,7 @@ static const struct file_operations ruleset_fops = { · 34 unmodified lines
129137 .write = fop_dummy_write,
130138 };
131139
132−#define LANDLOCK_ABI_VERSION 3
140+#define LANDLOCK_ABI_VERSION 4
133141
134142 /**
135143 * sys_landlock_create_ruleset - Create a new ruleset
@@ -188,8 +196,14 @@ SYSCALL_DEFINE3(landlock_create_ruleset, · 52 unmodified lines
188196 LANDLOCK_MASK_ACCESS_FS)
189197 return -EINVAL;
190198
199+ /* Checks network content (and 32-bits cast). */
200+ if ((ruleset_attr.handled_access_net | LANDLOCK_MASK_ACCESS_NET) !=
201+ LANDLOCK_MASK_ACCESS_NET)
202+ return -EINVAL;
203+
191204 /* Checks arguments and transforms to kernel struct. */
192− ruleset = landlock_create_ruleset(ruleset_attr.handled_access_fs);
205+ ruleset = landlock_create_ruleset(ruleset_attr.handled_access_fs,
206+ ruleset_attr.handled_access_net);
193207 if (IS_ERR(ruleset))
194208 return PTR_ERR(ruleset);
195209
@@ -282,7 +296,7 @@ static int add_rule_path_beneath(struct landlock_ruleset *const ruleset, · 86 unmodified lines
282296 int res, err;
283297 access_mask_t mask;
284298
285− /* Copies raw user space buffer, only one type for now. */
299+ /* Copies raw user space buffer. */
286300 res = copy_from_user(&path_beneath_attr, rule_attr,
287301 sizeof(path_beneath_attr));
288302 if (res)
@@ -312,13 +326,46 @@ static int add_rule_path_beneath(struct landlock_ruleset *const ruleset, · 23 unmodified lines
312326 return err;
313327 }
314328
329+static int add_rule_net_port(struct landlock_ruleset *ruleset,
330+ const void __user *const rule_attr)
331+{
332+ struct landlock_net_port_attr net_port_attr;
333+ int res;
334+ access_mask_t mask;
335+
336+ /* Copies raw user space buffer. */
337+ res = copy_from_user(&net_port_attr, rule_attr, sizeof(net_port_attr));
338+ if (res)
339+ return -EFAULT;
340+
341+ /*
342+ * Informs about useless rule: empty allowed_access (i.e. deny rules)
343+ * are ignored by network actions.
344+ */
345+ if (!net_port_attr.allowed_access)
346+ return -ENOMSG;
347+
348+ /* Checks that allowed_access matches the @ruleset constraints. */
349+ mask = landlock_get_net_access_mask(ruleset, 0);
350+ if ((net_port_attr.allowed_access | mask) != mask)
351+ return -EINVAL;
352+
353+ /* Denies inserting a rule with port greater than 65535. */
354+ if (net_port_attr.port > U16_MAX)
355+ return -EINVAL;
356+
357+ /* Imports the new rule. */
358+ return landlock_append_net_rule(ruleset, net_port_attr.port,
359+ net_port_attr.allowed_access);
360+}
361+
315362 /**
316363 * sys_landlock_add_rule - Add a new rule to a ruleset
317364 *
318365 * @ruleset_fd: File descriptor tied to the ruleset that should be extended
319366 * with the new rule.
320− * @rule_type: Identify the structure type pointed to by @rule_attr (only
321− * %LANDLOCK_RULE_PATH_BENEATH for now).
367+ * @rule_type: Identify the structure type pointed to by @rule_attr:
368+ * %LANDLOCK_RULE_PATH_BENEATH or %LANDLOCK_RULE_NET_PORT.
322369 * @rule_attr: Pointer to a rule (only of type &struct
323370 * landlock_path_beneath_attr for now).
324371 * @flags: Must be 0.
@@ -329,9 +376,13 @@ static int add_rule_path_beneath(struct landlock_ruleset *const ruleset, · 4 unmodified lines
329376 * Possible returned errors are:
330377 *
331378 * - %EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time;
379+ * - %EAFNOSUPPORT: @rule_type is %LANDLOCK_RULE_NET_PORT but TCP/IP is not
380+ * supported by the running kernel;
332381 * - %EINVAL: @flags is not 0, or inconsistent access in the rule (i.e.
333− * &landlock_path_beneath_attr.allowed_access is not a subset of the
334− * ruleset handled accesses);
382+ * &landlock_path_beneath_attr.allowed_access or
383+ * &landlock_net_port_attr.allowed_access is not a subset of the
384+ * ruleset handled accesses), or &landlock_net_port_attr.port is
385+ * greater than 65535;
335386 * - %ENOMSG: Empty accesses (e.g. &landlock_path_beneath_attr.allowed_access);
336387 * - %EBADF: @ruleset_fd is not a file descriptor for the current thread, or a
337388 * member of @rule_attr is not a file descriptor as expected;
@@ -363,6 +414,9 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd, · 25 unmodified lines
363414 case LANDLOCK_RULE_PATH_BENEATH:
364415 err = add_rule_path_beneath(ruleset, rule_attr);
365416 break;
417+ case LANDLOCK_RULE_NET_PORT:
418+ err = add_rule_net_port(ruleset, rule_attr);
419+ break;
366420 default:
367421 err = -EINVAL;
368422 break;
tools/testing/selftests/landlock/base_test.c+1−1
@@ -75,7 +75,7 @@ TEST(abi_version) · 74 unmodified lines
7575 const struct landlock_ruleset_attr ruleset_attr = {
7676 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
7777 };
78− ASSERT_EQ(3, landlock_create_ruleset(NULL, 0,
78+ ASSERT_EQ(4, landlock_create_ruleset(NULL, 0,
7979 LANDLOCK_CREATE_RULESET_VERSION));
8080
8181 ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0,

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t