Commit 9fa23750 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -8,7 +8,7 @@ Landlock: unprivileged access control
=====================================

: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
filesystem or network access) for a set of processes.  Because Landlock
+37 −29
Original line number Diff line number Diff line
@@ -12,29 +12,36 @@
#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
 * future versions.
 * Argument of sys_landlock_create_ruleset().
 *
 * 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 {
	/**
	 * @handled_access_fs: Bitmask of actions (cf. `Filesystem flags`_)
	 * that is handled by this ruleset and should then be forbidden if no
	 * 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.
	 * @handled_access_fs: Bitmask of handled filesystem actions
	 * (cf. `Filesystem flags`_).
	 */
	__u64 handled_access_fs;
	/**
	 * @handled_access_net: Bitmask of actions (cf. `Network flags`_)
	 * that is handled by this ruleset and should then be forbidden if no
	 * rule explicitly allow them.
	 * @handled_access_net: Bitmask of handled network actions (cf. `Network
	 * flags`_).
	 */
	__u64 handled_access_net;
};
@@ -97,20 +104,21 @@ struct landlock_path_beneath_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`_).
	 */
	__u64 allowed_access;
	/**
	 * @port: Network port in host endianness.
	 *
	 * It should be noted that port 0 passed to :manpage:`bind(2)` will
	 * bind to an available port from a specific port range. This can be
	 * configured thanks to the ``/proc/sys/net/ipv4/ip_local_port_range``
	 * sysctl (also used for IPv6). A Landlock rule with port 0 and the
	 * ``LANDLOCK_ACCESS_NET_BIND_TCP`` right means that requesting to bind
	 * on port 0 is allowed and it will automatically translate to binding
	 * on the related port range.
	 * It should be noted that port 0 passed to :manpage:`bind(2)` will bind
	 * to an available port from the ephemeral port range.  This can be
	 * configured with the ``/proc/sys/net/ipv4/ip_local_port_range`` sysctl
	 * (also used for IPv6).
	 *
	 * A Landlock rule with port 0 and the ``LANDLOCK_ACCESS_NET_BIND_TCP``
	 * 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;
};
@@ -131,10 +139,10 @@ struct landlock_net_port_attr {
 * The following access rights apply only to files:
 *
 * - %LANDLOCK_ACCESS_FS_EXECUTE: Execute a file.
 * - %LANDLOCK_ACCESS_FS_WRITE_FILE: Open a file with write access. Note that
 *   you might additionally need the %LANDLOCK_ACCESS_FS_TRUNCATE right in order
 *   to overwrite files with :manpage:`open(2)` using ``O_TRUNC`` or
 *   :manpage:`creat(2)`.
 * - %LANDLOCK_ACCESS_FS_WRITE_FILE: Open a file with write access.  When
 *   opening files for writing, you will often additionally need the
 *   %LANDLOCK_ACCESS_FS_TRUNCATE right.  In many cases, these system calls
 *   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_TRUNCATE: Truncate a file with :manpage:`truncate(2)`,
 *   :manpage:`ftruncate(2)`, :manpage:`creat(2)`, or :manpage:`open(2)` with
@@ -256,7 +264,7 @@ struct landlock_net_port_attr {
 * These flags enable to restrict a sandboxed process to a set of network
 * 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_CONNECT_TCP: Connect an active TCP socket to
+0 −2
Original line number Diff line number Diff line
@@ -21,12 +21,10 @@
#define LANDLOCK_LAST_ACCESS_FS		LANDLOCK_ACCESS_FS_IOCTL_DEV
#define LANDLOCK_MASK_ACCESS_FS		((LANDLOCK_LAST_ACCESS_FS << 1) - 1)
#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_MASK_ACCESS_NET	((LANDLOCK_LAST_ACCESS_NET << 1) - 1)
#define LANDLOCK_NUM_ACCESS_NET		__const_hweight64(LANDLOCK_MASK_ACCESS_NET)
#define LANDLOCK_SHIFT_ACCESS_NET	LANDLOCK_NUM_ACCESS_FS

/* clang-format on */

+0 −4
Original line number Diff line number Diff line
@@ -169,13 +169,9 @@ static void build_check_ruleset(void)
		.num_rules = ~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_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)));
}

/**
+9 −15
Original line number Diff line number Diff line
@@ -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));

/* Ruleset access masks. */
typedef u32 access_masks_t;
/* Makes sure all ruleset access rights can be stored. */
static_assert(BITS_PER_TYPE(access_masks_t) >=
	      LANDLOCK_NUM_ACCESS_FS + LANDLOCK_NUM_ACCESS_NET);
struct access_masks {
	access_mask_t fs : LANDLOCK_NUM_ACCESS_FS;
	access_mask_t net : LANDLOCK_NUM_ACCESS_NET;
};

typedef u16 layer_mask_t;
/* Makes sure all layers can be checked. */
@@ -226,7 +226,7 @@ struct landlock_ruleset {
			 * layers are set once and never changed for the
			 * 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,

	/* Should already be checked in sys_landlock_create_ruleset(). */
	WARN_ON_ONCE(fs_access_mask != fs_mask);
	ruleset->access_masks[layer_level] |=
		(fs_mask << LANDLOCK_SHIFT_ACCESS_FS);
	ruleset->access_masks[layer_level].fs |= fs_mask;
}

static inline void
@@ -278,17 +277,14 @@ landlock_add_net_access_mask(struct landlock_ruleset *const ruleset,

	/* Should already be checked in sys_landlock_create_ruleset(). */
	WARN_ON_ONCE(net_access_mask != net_mask);
	ruleset->access_masks[layer_level] |=
		(net_mask << LANDLOCK_SHIFT_ACCESS_NET);
	ruleset->access_masks[layer_level].net |= net_mask;
}

static inline access_mask_t
landlock_get_raw_fs_access_mask(const struct landlock_ruleset *const ruleset,
				const u16 layer_level)
{
	return (ruleset->access_masks[layer_level] >>
		LANDLOCK_SHIFT_ACCESS_FS) &
	       LANDLOCK_MASK_ACCESS_FS;
	return ruleset->access_masks[layer_level].fs;
}

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,
			     const u16 layer_level)
{
	return (ruleset->access_masks[layer_level] >>
		LANDLOCK_SHIFT_ACCESS_NET) &
	       LANDLOCK_MASK_ACCESS_NET;
	return ruleset->access_masks[layer_level].net;
}

bool landlock_unmask_layers(const struct landlock_rule *const rule,
Loading