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
31 * this access right.31 * this access right.
32 */32 */
33 __u64 handled_access_fs;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/*
@@ -54,6 +60,11 @@ enum landlock_rule_type { · 17 unmodified lines
54 * landlock_path_beneath_attr .60 * landlock_path_beneath_attr .
55 */61 */
56 LANDLOCK_RULE_PATH_BENEATH = 1,62 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,
57};68};
58 69
59/**70/**
@@ -79,6 +90,31 @@ struct landlock_path_beneath_attr { · 19 unmodified lines
79 */90 */
80} __attribute__((packed));91} __attribute__((packed));
81 92
93/**
94 * struct landlock_net_port_attr - Network port definition
95 *
96 * Argument of sys_landlock_add_rule().
97 */
98struct 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
82/**118/**
83 * DOC: fs_access119 * DOC: fs_access
84 *120 *
@@ -189,4 +225,23 @@ struct landlock_path_beneath_attr { · 104 unmodified lines
189#define LANDLOCK_ACCESS_FS_TRUNCATE (1ULL << 14)225#define LANDLOCK_ACCESS_FS_TRUNCATE (1ULL << 14)
190/* clang-format on */226/* clang-format on */
191 227
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 */
192#endif /* _UAPI_LINUX_LANDLOCK_H */247#endif /* _UAPI_LINUX_LANDLOCK_H */
security/landlock/Kconfig+1−0
@@ -3,6 +3,7 @@ · 2 unmodified lines
3config SECURITY_LANDLOCK3config SECURITY_LANDLOCK
4 bool "Landlock support"4 bool "Landlock support"
5 depends on SECURITY5 depends on SECURITY
6 select SECURITY_NETWORK
6 select SECURITY_PATH7 select SECURITY_PATH
7 help8 help
8 Landlock is a sandboxing mechanism that enables processes to restrict9 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
2 2
3landlock-y := setup.o syscalls.o object.o ruleset.o \3landlock-y := setup.o syscalls.o object.o ruleset.o \
4 cred.o ptrace.o fs.o4 cred.o ptrace.o fs.o
5
6landlock-$(CONFIG_INET) += net.o
security/landlock/limits.h+5−0
@@ -23,6 +23,11 @@ · 22 unmodified lines
23#define LANDLOCK_NUM_ACCESS_FS __const_hweight64(LANDLOCK_MASK_ACCESS_FS)23#define LANDLOCK_NUM_ACCESS_FS __const_hweight64(LANDLOCK_MASK_ACCESS_FS)
24#define LANDLOCK_SHIFT_ACCESS_FS 024#define LANDLOCK_SHIFT_ACCESS_FS 0
25 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
30
26/* clang-format on */31/* clang-format on */
27 32
28#endif /* _SECURITY_LANDLOCK_LIMITS_H */33#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
20int 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
42static access_mask_t
43get_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
53static 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
64static 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
176static 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
183static 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
191static 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
18int landlock_append_net_rule(struct landlock_ruleset *const ruleset,
19 const u16 port, access_mask_t access_rights);
20#else /* IS_ENABLED(CONFIG_INET) */
21static inline void landlock_add_net_hooks(void)
22{
23}
24
25static inline int
26landlock_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
36 refcount_set(&new_ruleset->usage, 1);36 refcount_set(&new_ruleset->usage, 1);
37 mutex_init(&new_ruleset->lock);37 mutex_init(&new_ruleset->lock);
38 new_ruleset->root_inode = 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 new_ruleset->num_layers = num_layers;44 new_ruleset->num_layers = num_layers;
40 /*45 /*
41 * hierarchy = NULL46 * hierarchy = NULL
@@ -46,16 +51,21 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers) · 4 unmodified lines
46}51}
47 52
48struct landlock_ruleset *53struct landlock_ruleset *
49landlock_create_ruleset(const access_mask_t fs_access_mask)54landlock_create_ruleset(const access_mask_t fs_access_mask,
55 const access_mask_t net_access_mask)
50{56{
51 struct landlock_ruleset *new_ruleset;57 struct landlock_ruleset *new_ruleset;
52 58
53 /* Informs about useless ruleset. */59 /* Informs about useless ruleset. */
54 if (!fs_access_mask)60 if (!fs_access_mask && !net_access_mask)
55 return ERR_PTR(-ENOMSG);61 return ERR_PTR(-ENOMSG);
56 new_ruleset = create_ruleset(1);62 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)
58 landlock_add_fs_access_mask(new_ruleset, fs_access_mask, 0);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 return new_ruleset;69 return new_ruleset;
60}70}
61 71
@@ -74,6 +84,11 @@ static bool is_object_pointer(const enum landlock_key_type key_type) · 12 unmodified lines
74 case LANDLOCK_KEY_INODE:84 case LANDLOCK_KEY_INODE:
75 return true;85 return true;
76 86
87#if IS_ENABLED(CONFIG_INET)
88 case LANDLOCK_KEY_NET_PORT:
89 return false;
90#endif /* IS_ENABLED(CONFIG_INET) */
91
77 default:92 default:
78 WARN_ON_ONCE(1);93 WARN_ON_ONCE(1);
79 return false;94 return false;
@@ -126,6 +141,11 @@ static struct rb_root *get_root(struct landlock_ruleset *const ruleset, · 46 unmodified lines
126 case LANDLOCK_KEY_INODE:141 case LANDLOCK_KEY_INODE:
127 return &ruleset->root_inode;142 return &ruleset->root_inode;
128 143
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
129 default:149 default:
130 WARN_ON_ONCE(1);150 WARN_ON_ONCE(1);
131 return ERR_PTR(-EINVAL);151 return ERR_PTR(-EINVAL);
@@ -154,7 +174,8 @@ static void build_check_ruleset(void) · 22 unmodified lines
154 BUILD_BUG_ON(ruleset.num_rules < LANDLOCK_MAX_NUM_RULES);174 BUILD_BUG_ON(ruleset.num_rules < LANDLOCK_MAX_NUM_RULES);
155 BUILD_BUG_ON(ruleset.num_layers < LANDLOCK_MAX_NUM_LAYERS);175 BUILD_BUG_ON(ruleset.num_layers < LANDLOCK_MAX_NUM_LAYERS);
156 BUILD_BUG_ON(access_masks <176 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)));
158}179}
159 180
160/**181/**
@@ -371,6 +392,13 @@ static int merge_ruleset(struct landlock_ruleset *const dst, · 210 unmodified lines
371 if (err)392 if (err)
372 goto out_unlock;393 goto out_unlock;
373 394
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
374out_unlock:402out_unlock:
375 mutex_unlock(&src->lock);403 mutex_unlock(&src->lock);
376 mutex_unlock(&dst->lock);404 mutex_unlock(&dst->lock);
@@ -427,6 +455,13 @@ static int inherit_ruleset(struct landlock_ruleset *const parent, · 50 unmodified lines
427 if (err)455 if (err)
428 goto out_unlock;456 goto out_unlock;
429 457
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
430 if (WARN_ON_ONCE(child->num_layers <= parent->num_layers)) {465 if (WARN_ON_ONCE(child->num_layers <= parent->num_layers)) {
431 err = -EINVAL;466 err = -EINVAL;
432 goto out_unlock;467 goto out_unlock;
@@ -456,6 +491,13 @@ static void free_ruleset(struct landlock_ruleset *const ruleset) · 23 unmodified lines
456 rbtree_postorder_for_each_entry_safe(freeme, next, &ruleset->root_inode,491 rbtree_postorder_for_each_entry_safe(freeme, next, &ruleset->root_inode,
457 node)492 node)
458 free_rule(freeme, LANDLOCK_KEY_INODE);493 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
459 put_hierarchy(ruleset->hierarchy);501 put_hierarchy(ruleset->hierarchy);
460 kfree(ruleset);502 kfree(ruleset);
461}503}
@@ -636,7 +678,8 @@ get_access_mask_t(const struct landlock_ruleset *const ruleset, · 174 unmodified lines
636 *678 *
637 * @domain: The domain that defines the current restrictions.679 * @domain: The domain that defines the current restrictions.
638 * @access_request: The requested access rights to check.680 * @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.
640 * @key_type: The key type to switch between access masks of different types.683 * @key_type: The key type to switch between access masks of different types.
641 *684 *
642 * Returns: An access mask where each access right bit is set which is handled685 * 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
657 get_access_mask = landlock_get_fs_access_mask;700 get_access_mask = landlock_get_fs_access_mask;
658 num_access = LANDLOCK_NUM_ACCESS_FS;701 num_access = LANDLOCK_NUM_ACCESS_FS;
659 break;702 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
660 default:711 default:
661 WARN_ON_ONCE(1);712 WARN_ON_ONCE(1);
662 return 0;713 return 0;
security/landlock/ruleset.h+52−10
@@ -33,13 +33,16 @@ · 32 unmodified lines
33typedef u16 access_mask_t;33typedef u16 access_mask_t;
34/* Makes sure all filesystem access rights can be stored. */34/* Makes sure all filesystem access rights can be stored. */
35static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_FS);35static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_FS);
36/* Makes sure all network access rights can be stored. */
37static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_NET);
36/* Makes sure for_each_set_bit() and for_each_clear_bit() calls are OK. */38/* Makes sure for_each_set_bit() and for_each_clear_bit() calls are OK. */
37static_assert(sizeof(unsigned long) >= sizeof(access_mask_t));39static_assert(sizeof(unsigned long) >= sizeof(access_mask_t));
38 40
39/* Ruleset access masks. */41/* Ruleset access masks. */
40typedef u16 access_masks_t;42typedef u32 access_masks_t;
41/* Makes sure all ruleset access rights can be stored. */43/* Makes sure all ruleset access rights can be stored. */
42static_assert(BITS_PER_TYPE(access_masks_t) >= LANDLOCK_NUM_ACCESS_FS);44static_assert(BITS_PER_TYPE(access_masks_t) >=
45 LANDLOCK_NUM_ACCESS_FS + LANDLOCK_NUM_ACCESS_NET);
43 46
44typedef u16 layer_mask_t;47typedef u16 layer_mask_t;
45/* Makes sure all layers can be checked. */48/* Makes sure all layers can be checked. */
@@ -84,6 +87,11 @@ enum landlock_key_type { · 38 unmodified lines
84 * keys.87 * keys.
85 */88 */
86 LANDLOCK_KEY_INODE = 1,89 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,
87};95};
88 96
89/**97/**
@@ -158,6 +166,17 @@ struct landlock_ruleset { · 68 unmodified lines
158 * reaches zero.166 * reaches zero.
159 */167 */
160 struct rb_root root_inode;168 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
161 /**180 /**
162 * @hierarchy: Enables hierarchy identification even when a parent181 * @hierarchy: Enables hierarchy identification even when a parent
163 * domain vanishes. This is needed for the ptrace protection.182 * domain vanishes. This is needed for the ptrace protection.
@@ -196,13 +215,13 @@ struct landlock_ruleset { · 32 unmodified lines
196 */215 */
197 u32 num_layers;216 u32 num_layers;
198 /**217 /**
199 * @access_masks: Contains the subset of filesystem218 * @access_masks: Contains the subset of filesystem and
200 * actions that are restricted by a ruleset. A domain219 * network actions that are restricted by a ruleset.
201 * saves all layers of merged rulesets in a stack220 * A domain saves all layers of merged rulesets in a
202 * (FAM), starting from the first layer to the last221 * stack (FAM), starting from the first layer to the
203 * one. These layers are used when merging rulesets,222 * last one. These layers are used when merging
204 * for user space backward compatibility (i.e.223 * rulesets, for user space backward compatibility
205 * future-proof), and to properly handle merged224 * (i.e. future-proof), and to properly handle merged
206 * rulesets without overlapping access rights. These225 * rulesets without overlapping access rights. These
207 * layers are set once and never changed for the226 * layers are set once and never changed for the
208 * lifetime of the ruleset.227 * lifetime of the ruleset.
@@ -213,7 +232,8 @@ struct landlock_ruleset { · 4 unmodified lines
213};232};
214 233
215struct landlock_ruleset *234struct landlock_ruleset *
216landlock_create_ruleset(const access_mask_t access_mask);235landlock_create_ruleset(const access_mask_t access_mask_fs,
236 const access_mask_t access_mask_net);
217 237
218void landlock_put_ruleset(struct landlock_ruleset *const ruleset);238void landlock_put_ruleset(struct landlock_ruleset *const ruleset);
219void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset);239void 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
249 (fs_mask << LANDLOCK_SHIFT_ACCESS_FS);269 (fs_mask << LANDLOCK_SHIFT_ACCESS_FS);
250}270}
251 271
272static inline void
273landlock_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
252static inline access_mask_t285static inline access_mask_t
253landlock_get_raw_fs_access_mask(const struct landlock_ruleset *const ruleset,286landlock_get_raw_fs_access_mask(const struct landlock_ruleset *const ruleset,
254 const u16 layer_level)287 const u16 layer_level)
@@ -267,6 +300,15 @@ landlock_get_fs_access_mask(const struct landlock_ruleset *const ruleset, · 12 unmodified lines
267 LANDLOCK_ACCESS_FS_INITIALLY_DENIED;300 LANDLOCK_ACCESS_FS_INITIALLY_DENIED;
268}301}
269 302
303static inline access_mask_t
304landlock_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
270bool landlock_unmask_layers(const struct landlock_rule *const rule,312bool landlock_unmask_layers(const struct landlock_rule *const rule,
271 const access_mask_t access_request,313 const access_mask_t access_request,
272 layer_mask_t (*const layer_masks)[],314 layer_mask_t (*const layer_masks)[],
security/landlock/setup.c+2−0
@@ -12,6 +12,7 @@ · 11 unmodified lines
12#include "common.h"12#include "common.h"
13#include "cred.h"13#include "cred.h"
14#include "fs.h"14#include "fs.h"
15#include "net.h"
15#include "ptrace.h"16#include "ptrace.h"
16#include "setup.h"17#include "setup.h"
17 18
@@ -29,6 +30,7 @@ static int __init landlock_init(void) · 11 unmodified lines
29 landlock_add_cred_hooks();30 landlock_add_cred_hooks();
30 landlock_add_ptrace_hooks();31 landlock_add_ptrace_hooks();
31 landlock_add_fs_hooks();32 landlock_add_fs_hooks();
33 landlock_add_net_hooks();
32 landlock_initialized = true;34 landlock_initialized = true;
33 pr_info("Up and running.\n");35 pr_info("Up and running.\n");
34 return 0;36 return 0;
security/landlock/syscalls.c+63−9
@@ -29,6 +29,7 @@ · 28 unmodified lines
29#include "cred.h"29#include "cred.h"
30#include "fs.h"30#include "fs.h"
31#include "limits.h"31#include "limits.h"
32#include "net.h"
32#include "ruleset.h"33#include "ruleset.h"
33#include "setup.h"34#include "setup.h"
34 35
@@ -74,7 +75,8 @@ static void build_check_abi(void) · 39 unmodified lines
74{75{
75 struct landlock_ruleset_attr ruleset_attr;76 struct landlock_ruleset_attr ruleset_attr;
76 struct landlock_path_beneath_attr path_beneath_attr;77 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;
78 80
79 /*81 /*
80 * For each user space ABI structures, first checks that there is no82 * 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
82 * struct size.84 * struct size.
83 */85 */
84 ruleset_size = sizeof(ruleset_attr.handled_access_fs);86 ruleset_size = sizeof(ruleset_attr.handled_access_fs);
87 ruleset_size += sizeof(ruleset_attr.handled_access_net);
85 BUILD_BUG_ON(sizeof(ruleset_attr) != ruleset_size);88 BUILD_BUG_ON(sizeof(ruleset_attr) != ruleset_size);
86 BUILD_BUG_ON(sizeof(ruleset_attr) != 8);89 BUILD_BUG_ON(sizeof(ruleset_attr) != 16);
87 90
88 path_beneath_size = sizeof(path_beneath_attr.allowed_access);91 path_beneath_size = sizeof(path_beneath_attr.allowed_access);
89 path_beneath_size += sizeof(path_beneath_attr.parent_fd);92 path_beneath_size += sizeof(path_beneath_attr.parent_fd);
90 BUILD_BUG_ON(sizeof(path_beneath_attr) != path_beneath_size);93 BUILD_BUG_ON(sizeof(path_beneath_attr) != path_beneath_size);
91 BUILD_BUG_ON(sizeof(path_beneath_attr) != 12);94 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);
92}100}
93 101
94/* Ruleset handling */102/* Ruleset handling */
@@ -129,7 +137,7 @@ static const struct file_operations ruleset_fops = { · 34 unmodified lines
129 .write = fop_dummy_write,137 .write = fop_dummy_write,
130};138};
131 139
132#define LANDLOCK_ABI_VERSION 3140#define LANDLOCK_ABI_VERSION 4
133 141
134/**142/**
135 * sys_landlock_create_ruleset - Create a new ruleset143 * sys_landlock_create_ruleset - Create a new ruleset
@@ -188,8 +196,14 @@ SYSCALL_DEFINE3(landlock_create_ruleset, · 52 unmodified lines
188 LANDLOCK_MASK_ACCESS_FS)196 LANDLOCK_MASK_ACCESS_FS)
189 return -EINVAL;197 return -EINVAL;
190 198
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
191 /* Checks arguments and transforms to kernel struct. */204 /* 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);
193 if (IS_ERR(ruleset))207 if (IS_ERR(ruleset))
194 return PTR_ERR(ruleset);208 return PTR_ERR(ruleset);
195 209
@@ -282,7 +296,7 @@ static int add_rule_path_beneath(struct landlock_ruleset *const ruleset, · 86 unmodified lines
282 int res, err;296 int res, err;
283 access_mask_t mask;297 access_mask_t mask;
284 298
285 /* Copies raw user space buffer, only one type for now. */299 /* Copies raw user space buffer. */
286 res = copy_from_user(&path_beneath_attr, rule_attr,300 res = copy_from_user(&path_beneath_attr, rule_attr,
287 sizeof(path_beneath_attr));301 sizeof(path_beneath_attr));
288 if (res)302 if (res)
@@ -312,13 +326,46 @@ static int add_rule_path_beneath(struct landlock_ruleset *const ruleset, · 23 unmodified lines
312 return err;326 return err;
313}327}
314 328
329static 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
315/**362/**
316 * sys_landlock_add_rule - Add a new rule to a ruleset363 * sys_landlock_add_rule - Add a new rule to a ruleset
317 *364 *
318 * @ruleset_fd: File descriptor tied to the ruleset that should be extended365 * @ruleset_fd: File descriptor tied to the ruleset that should be extended
319 * with the new rule.366 * with the new rule.
320 * @rule_type: Identify the structure type pointed to by @rule_attr (only367 * @rule_type: Identify the structure type pointed to by @rule_attr:
321 * %LANDLOCK_RULE_PATH_BENEATH for now).368 * %LANDLOCK_RULE_PATH_BENEATH or %LANDLOCK_RULE_NET_PORT.
322 * @rule_attr: Pointer to a rule (only of type &struct369 * @rule_attr: Pointer to a rule (only of type &struct
323 * landlock_path_beneath_attr for now).370 * landlock_path_beneath_attr for now).
324 * @flags: Must be 0.371 * @flags: Must be 0.
@@ -329,9 +376,13 @@ static int add_rule_path_beneath(struct landlock_ruleset *const ruleset, · 4 unmodified lines
329 * Possible returned errors are:376 * Possible returned errors are:
330 *377 *
331 * - %EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time;378 * - %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;
332 * - %EINVAL: @flags is not 0, or inconsistent access in the rule (i.e.381 * - %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 the382 * &landlock_path_beneath_attr.allowed_access or
334 * ruleset handled accesses);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;
335 * - %ENOMSG: Empty accesses (e.g. &landlock_path_beneath_attr.allowed_access);386 * - %ENOMSG: Empty accesses (e.g. &landlock_path_beneath_attr.allowed_access);
336 * - %EBADF: @ruleset_fd is not a file descriptor for the current thread, or a387 * - %EBADF: @ruleset_fd is not a file descriptor for the current thread, or a
337 * member of @rule_attr is not a file descriptor as expected;388 * 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
363 case LANDLOCK_RULE_PATH_BENEATH:414 case LANDLOCK_RULE_PATH_BENEATH:
364 err = add_rule_path_beneath(ruleset, rule_attr);415 err = add_rule_path_beneath(ruleset, rule_attr);
365 break;416 break;
417 case LANDLOCK_RULE_NET_PORT:
418 err = add_rule_net_port(ruleset, rule_attr);
419 break;
366 default:420 default:
367 err = -EINVAL;421 err = -EINVAL;
368 break;422 break;
tools/testing/selftests/landlock/base_test.c+1−1
@@ -75,7 +75,7 @@ TEST(abi_version) · 74 unmodified lines
75 const struct landlock_ruleset_attr ruleset_attr = {75 const struct landlock_ruleset_attr ruleset_attr = {
76 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,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 LANDLOCK_CREATE_RULESET_VERSION));79 LANDLOCK_CREATE_RULESET_VERSION));
80 80
81 ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0,81 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