Commit 9fa23750 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull landlock updates from Mickaël Salaün:
 "This simplifies code and improves documentation"

* tag 'landlock-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mic/linux:
  landlock: Various documentation improvements
  landlock: Clarify documentation for struct landlock_ruleset_attr
  landlock: Use bit-fields for storing handled layer access masks
parents 8326f5e1 f4b89d8c
...@@ -8,7 +8,7 @@ Landlock: unprivileged access control ...@@ -8,7 +8,7 @@ Landlock: unprivileged access control
===================================== =====================================
:Author: Mickaël Salaün :Author: Mickaël Salaün
:Date: April 2024 :Date: July 2024
The goal of Landlock is to enable to restrict ambient rights (e.g. global The goal of Landlock is to enable to restrict ambient rights (e.g. global
filesystem or network access) for a set of processes. Because Landlock filesystem or network access) for a set of processes. Because Landlock
......
...@@ -12,29 +12,36 @@ ...@@ -12,29 +12,36 @@
#include <linux/types.h> #include <linux/types.h>
/** /**
* struct landlock_ruleset_attr - Ruleset definition * struct landlock_ruleset_attr - Ruleset definition.
* *
* Argument of sys_landlock_create_ruleset(). This structure can grow in * Argument of sys_landlock_create_ruleset().
* future versions. *
* This structure defines a set of *handled access rights*, a set of actions on
* different object types, which should be denied by default when the ruleset is
* enacted. Vice versa, access rights that are not specifically listed here are
* not going to be denied by this ruleset when it is enacted.
*
* For historical reasons, the %LANDLOCK_ACCESS_FS_REFER right is always denied
* by default, even when its bit is not set in @handled_access_fs. In order to
* add new rules with this access right, the bit must still be set explicitly
* (cf. `Filesystem flags`_).
*
* The explicit listing of *handled access rights* is required for backwards
* compatibility reasons. In most use cases, processes that use Landlock will
* *handle* a wide range or all access rights that they know about at build time
* (and that they have tested with a kernel that supported them all).
*
* This structure can grow in future Landlock versions.
*/ */
struct landlock_ruleset_attr { struct landlock_ruleset_attr {
/** /**
* @handled_access_fs: Bitmask of actions (cf. `Filesystem flags`_) * @handled_access_fs: Bitmask of handled filesystem actions
* that is handled by this ruleset and should then be forbidden if no * (cf. `Filesystem flags`_).
* rule explicitly allow them: it is a deny-by-default list that should
* contain as much Landlock access rights as possible. Indeed, all
* Landlock filesystem access rights that are not part of
* handled_access_fs are allowed. This is needed for backward
* compatibility reasons. One exception is the
* %LANDLOCK_ACCESS_FS_REFER access right, which is always implicitly
* handled, but must still be explicitly handled to add new rules with
* this access right.
*/ */
__u64 handled_access_fs; __u64 handled_access_fs;
/** /**
* @handled_access_net: Bitmask of actions (cf. `Network flags`_) * @handled_access_net: Bitmask of handled network actions (cf. `Network
* that is handled by this ruleset and should then be forbidden if no * flags`_).
* rule explicitly allow them.
*/ */
__u64 handled_access_net; __u64 handled_access_net;
}; };
...@@ -97,20 +104,21 @@ struct landlock_path_beneath_attr { ...@@ -97,20 +104,21 @@ struct landlock_path_beneath_attr {
*/ */
struct landlock_net_port_attr { struct landlock_net_port_attr {
/** /**
* @allowed_access: Bitmask of allowed access network for a port * @allowed_access: Bitmask of allowed network actions for a port
* (cf. `Network flags`_). * (cf. `Network flags`_).
*/ */
__u64 allowed_access; __u64 allowed_access;
/** /**
* @port: Network port in host endianness. * @port: Network port in host endianness.
* *
* It should be noted that port 0 passed to :manpage:`bind(2)` will * It should be noted that port 0 passed to :manpage:`bind(2)` will bind
* bind to an available port from a specific port range. This can be * to an available port from the ephemeral port range. This can be
* configured thanks to the ``/proc/sys/net/ipv4/ip_local_port_range`` * configured with the ``/proc/sys/net/ipv4/ip_local_port_range`` sysctl
* sysctl (also used for IPv6). A Landlock rule with port 0 and the * (also used for IPv6).
* ``LANDLOCK_ACCESS_NET_BIND_TCP`` right means that requesting to bind *
* on port 0 is allowed and it will automatically translate to binding * A Landlock rule with port 0 and the ``LANDLOCK_ACCESS_NET_BIND_TCP``
* on the related port range. * right means that requesting to bind on port 0 is allowed and it will
* automatically translate to binding on the related port range.
*/ */
__u64 port; __u64 port;
}; };
...@@ -131,10 +139,10 @@ struct landlock_net_port_attr { ...@@ -131,10 +139,10 @@ struct landlock_net_port_attr {
* The following access rights apply only to files: * The following access rights apply only to files:
* *
* - %LANDLOCK_ACCESS_FS_EXECUTE: Execute a file. * - %LANDLOCK_ACCESS_FS_EXECUTE: Execute a file.
* - %LANDLOCK_ACCESS_FS_WRITE_FILE: Open a file with write access. Note that * - %LANDLOCK_ACCESS_FS_WRITE_FILE: Open a file with write access. When
* you might additionally need the %LANDLOCK_ACCESS_FS_TRUNCATE right in order * opening files for writing, you will often additionally need the
* to overwrite files with :manpage:`open(2)` using ``O_TRUNC`` or * %LANDLOCK_ACCESS_FS_TRUNCATE right. In many cases, these system calls
* :manpage:`creat(2)`. * truncate existing files when overwriting them (e.g., :manpage:`creat(2)`).
* - %LANDLOCK_ACCESS_FS_READ_FILE: Open a file with read access. * - %LANDLOCK_ACCESS_FS_READ_FILE: Open a file with read access.
* - %LANDLOCK_ACCESS_FS_TRUNCATE: Truncate a file with :manpage:`truncate(2)`, * - %LANDLOCK_ACCESS_FS_TRUNCATE: Truncate a file with :manpage:`truncate(2)`,
* :manpage:`ftruncate(2)`, :manpage:`creat(2)`, or :manpage:`open(2)` with * :manpage:`ftruncate(2)`, :manpage:`creat(2)`, or :manpage:`open(2)` with
...@@ -256,7 +264,7 @@ struct landlock_net_port_attr { ...@@ -256,7 +264,7 @@ struct landlock_net_port_attr {
* These flags enable to restrict a sandboxed process to a set of network * These flags enable to restrict a sandboxed process to a set of network
* actions. This is supported since the Landlock ABI version 4. * actions. This is supported since the Landlock ABI version 4.
* *
* TCP sockets with allowed actions: * The following access rights apply to TCP port numbers:
* *
* - %LANDLOCK_ACCESS_NET_BIND_TCP: Bind a TCP socket to a local port. * - %LANDLOCK_ACCESS_NET_BIND_TCP: Bind a TCP socket to a local port.
* - %LANDLOCK_ACCESS_NET_CONNECT_TCP: Connect an active TCP socket to * - %LANDLOCK_ACCESS_NET_CONNECT_TCP: Connect an active TCP socket to
......
...@@ -21,12 +21,10 @@ ...@@ -21,12 +21,10 @@
#define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_IOCTL_DEV #define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_IOCTL_DEV
#define LANDLOCK_MASK_ACCESS_FS ((LANDLOCK_LAST_ACCESS_FS << 1) - 1) #define LANDLOCK_MASK_ACCESS_FS ((LANDLOCK_LAST_ACCESS_FS << 1) - 1)
#define LANDLOCK_NUM_ACCESS_FS __const_hweight64(LANDLOCK_MASK_ACCESS_FS) #define LANDLOCK_NUM_ACCESS_FS __const_hweight64(LANDLOCK_MASK_ACCESS_FS)
#define LANDLOCK_SHIFT_ACCESS_FS 0
#define LANDLOCK_LAST_ACCESS_NET LANDLOCK_ACCESS_NET_CONNECT_TCP #define LANDLOCK_LAST_ACCESS_NET LANDLOCK_ACCESS_NET_CONNECT_TCP
#define LANDLOCK_MASK_ACCESS_NET ((LANDLOCK_LAST_ACCESS_NET << 1) - 1) #define LANDLOCK_MASK_ACCESS_NET ((LANDLOCK_LAST_ACCESS_NET << 1) - 1)
#define LANDLOCK_NUM_ACCESS_NET __const_hweight64(LANDLOCK_MASK_ACCESS_NET) #define LANDLOCK_NUM_ACCESS_NET __const_hweight64(LANDLOCK_MASK_ACCESS_NET)
#define LANDLOCK_SHIFT_ACCESS_NET LANDLOCK_NUM_ACCESS_FS
/* clang-format on */ /* clang-format on */
......
...@@ -169,13 +169,9 @@ static void build_check_ruleset(void) ...@@ -169,13 +169,9 @@ static void build_check_ruleset(void)
.num_rules = ~0, .num_rules = ~0,
.num_layers = ~0, .num_layers = ~0,
}; };
typeof(ruleset.access_masks[0]) access_masks = ~0;
BUILD_BUG_ON(ruleset.num_rules < LANDLOCK_MAX_NUM_RULES); BUILD_BUG_ON(ruleset.num_rules < LANDLOCK_MAX_NUM_RULES);
BUILD_BUG_ON(ruleset.num_layers < LANDLOCK_MAX_NUM_LAYERS); BUILD_BUG_ON(ruleset.num_layers < LANDLOCK_MAX_NUM_LAYERS);
BUILD_BUG_ON(access_masks <
((LANDLOCK_MASK_ACCESS_FS << LANDLOCK_SHIFT_ACCESS_FS) |
(LANDLOCK_MASK_ACCESS_NET << LANDLOCK_SHIFT_ACCESS_NET)));
} }
/** /**
......
...@@ -39,10 +39,10 @@ static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_NET); ...@@ -39,10 +39,10 @@ static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_NET);
static_assert(sizeof(unsigned long) >= sizeof(access_mask_t)); static_assert(sizeof(unsigned long) >= sizeof(access_mask_t));
/* Ruleset access masks. */ /* Ruleset access masks. */
typedef u32 access_masks_t; struct access_masks {
/* Makes sure all ruleset access rights can be stored. */ access_mask_t fs : LANDLOCK_NUM_ACCESS_FS;
static_assert(BITS_PER_TYPE(access_masks_t) >= access_mask_t net : LANDLOCK_NUM_ACCESS_NET;
LANDLOCK_NUM_ACCESS_FS + LANDLOCK_NUM_ACCESS_NET); };
typedef u16 layer_mask_t; typedef u16 layer_mask_t;
/* Makes sure all layers can be checked. */ /* Makes sure all layers can be checked. */
...@@ -226,7 +226,7 @@ struct landlock_ruleset { ...@@ -226,7 +226,7 @@ struct landlock_ruleset {
* layers are set once and never changed for the * layers are set once and never changed for the
* lifetime of the ruleset. * lifetime of the ruleset.
*/ */
access_masks_t access_masks[]; struct access_masks access_masks[];
}; };
}; };
}; };
...@@ -265,8 +265,7 @@ landlock_add_fs_access_mask(struct landlock_ruleset *const ruleset, ...@@ -265,8 +265,7 @@ landlock_add_fs_access_mask(struct landlock_ruleset *const ruleset,
/* Should already be checked in sys_landlock_create_ruleset(). */ /* Should already be checked in sys_landlock_create_ruleset(). */
WARN_ON_ONCE(fs_access_mask != fs_mask); WARN_ON_ONCE(fs_access_mask != fs_mask);
ruleset->access_masks[layer_level] |= ruleset->access_masks[layer_level].fs |= fs_mask;
(fs_mask << LANDLOCK_SHIFT_ACCESS_FS);
} }
static inline void static inline void
...@@ -278,17 +277,14 @@ landlock_add_net_access_mask(struct landlock_ruleset *const ruleset, ...@@ -278,17 +277,14 @@ landlock_add_net_access_mask(struct landlock_ruleset *const ruleset,
/* Should already be checked in sys_landlock_create_ruleset(). */ /* Should already be checked in sys_landlock_create_ruleset(). */
WARN_ON_ONCE(net_access_mask != net_mask); WARN_ON_ONCE(net_access_mask != net_mask);
ruleset->access_masks[layer_level] |= ruleset->access_masks[layer_level].net |= net_mask;
(net_mask << LANDLOCK_SHIFT_ACCESS_NET);
} }
static inline access_mask_t static inline access_mask_t
landlock_get_raw_fs_access_mask(const struct landlock_ruleset *const ruleset, landlock_get_raw_fs_access_mask(const struct landlock_ruleset *const ruleset,
const u16 layer_level) const u16 layer_level)
{ {
return (ruleset->access_masks[layer_level] >> return ruleset->access_masks[layer_level].fs;
LANDLOCK_SHIFT_ACCESS_FS) &
LANDLOCK_MASK_ACCESS_FS;
} }
static inline access_mask_t static inline access_mask_t
...@@ -304,9 +300,7 @@ static inline access_mask_t ...@@ -304,9 +300,7 @@ static inline access_mask_t
landlock_get_net_access_mask(const struct landlock_ruleset *const ruleset, landlock_get_net_access_mask(const struct landlock_ruleset *const ruleset,
const u16 layer_level) const u16 layer_level)
{ {
return (ruleset->access_masks[layer_level] >> return ruleset->access_masks[layer_level].net;
LANDLOCK_SHIFT_ACCESS_NET) &
LANDLOCK_MASK_ACCESS_NET;
} }
bool landlock_unmask_layers(const struct landlock_rule *const rule, bool landlock_unmask_layers(const struct landlock_rule *const rule,
......
...@@ -378,8 +378,7 @@ static int add_rule_net_port(struct landlock_ruleset *ruleset, ...@@ -378,8 +378,7 @@ static int add_rule_net_port(struct landlock_ruleset *ruleset,
* with the new rule. * with the new rule.
* @rule_type: Identify the structure type pointed to by @rule_attr: * @rule_type: Identify the structure type pointed to by @rule_attr:
* %LANDLOCK_RULE_PATH_BENEATH or %LANDLOCK_RULE_NET_PORT. * %LANDLOCK_RULE_PATH_BENEATH or %LANDLOCK_RULE_NET_PORT.
* @rule_attr: Pointer to a rule (only of type &struct * @rule_attr: Pointer to a rule (matching the @rule_type).
* landlock_path_beneath_attr for now).
* @flags: Must be 0. * @flags: Must be 0.
* *
* This system call enables to define a new rule and add it to an existing * This system call enables to define a new rule and add it to an existing
...@@ -390,18 +389,20 @@ static int add_rule_net_port(struct landlock_ruleset *ruleset, ...@@ -390,18 +389,20 @@ static int add_rule_net_port(struct landlock_ruleset *ruleset,
* - %EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time; * - %EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time;
* - %EAFNOSUPPORT: @rule_type is %LANDLOCK_RULE_NET_PORT but TCP/IP is not * - %EAFNOSUPPORT: @rule_type is %LANDLOCK_RULE_NET_PORT but TCP/IP is not
* supported by the running kernel; * supported by the running kernel;
* - %EINVAL: @flags is not 0, or inconsistent access in the rule (i.e. * - %EINVAL: @flags is not 0;
* - %EINVAL: The rule accesses are inconsistent (i.e.
* &landlock_path_beneath_attr.allowed_access or * &landlock_path_beneath_attr.allowed_access or
* &landlock_net_port_attr.allowed_access is not a subset of the * &landlock_net_port_attr.allowed_access is not a subset of the ruleset
* ruleset handled accesses), or &landlock_net_port_attr.port is * handled accesses)
* greater than 65535; * - %EINVAL: &landlock_net_port_attr.port is greater than 65535;
* - %ENOMSG: Empty accesses (e.g. &landlock_path_beneath_attr.allowed_access); * - %ENOMSG: Empty accesses (e.g. &landlock_path_beneath_attr.allowed_access is
* 0);
* - %EBADF: @ruleset_fd is not a file descriptor for the current thread, or a * - %EBADF: @ruleset_fd is not a file descriptor for the current thread, or a
* member of @rule_attr is not a file descriptor as expected; * member of @rule_attr is not a file descriptor as expected;
* - %EBADFD: @ruleset_fd is not a ruleset file descriptor, or a member of * - %EBADFD: @ruleset_fd is not a ruleset file descriptor, or a member of
* @rule_attr is not the expected file descriptor type; * @rule_attr is not the expected file descriptor type;
* - %EPERM: @ruleset_fd has no write access to the underlying ruleset; * - %EPERM: @ruleset_fd has no write access to the underlying ruleset;
* - %EFAULT: @rule_attr inconsistency. * - %EFAULT: @rule_attr was not a valid address.
*/ */
SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd, SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
const enum landlock_rule_type, rule_type, const enum landlock_rule_type, rule_type,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment