Skip to content

Commit c22e26b

Browse files
committed
Merge tag 'landlock-7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mic/linux
Pull landlock updates from Mickaël Salaün: - extend Landlock to enforce restrictions on a whole process, similarly to the seccomp's TSYNC flag - refactor data structures to simplify code and improve performance - add documentation to cover missing parts * tag 'landlock-7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mic/linux: mailmap: Add entry for Mickaël Salaün landlock: Transpose the layer masks data structure landlock: Add access_mask_subset() helper selftests/landlock: Add filesystem access benchmark landlock: Document audit blocker field format landlock: Add errata documentation section landlock: Add backwards compatibility for restrict flags landlock: Refactor TCP socket type check landlock: Minor reword of docs for TCP access rights landlock: Document LANDLOCK_RESTRICT_SELF_TSYNC selftests/landlock: Add LANDLOCK_RESTRICT_SELF_TSYNC tests landlock: Multithreading support for landlock_restrict_self()
2 parents d0e91e4 + e265b33 commit c22e26b

27 files changed

Lines changed: 1490 additions & 403 deletions

File tree

.mailmap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,7 @@ Michel Dänzer <michel@tungstengraphics.com>
563563
Michel Lespinasse <michel@lespinasse.org>
564564
Michel Lespinasse <michel@lespinasse.org> <walken@google.com>
565565
Michel Lespinasse <michel@lespinasse.org> <walken@zoy.org>
566+
Mickaël Salaün <mic@digikod.net> <mic@linux.microsoft.com>
566567
Miguel Ojeda <ojeda@kernel.org> <miguel.ojeda.sandonis@gmail.com>
567568
Mike Rapoport <rppt@kernel.org> <mike@compulab.co.il>
568569
Mike Rapoport <rppt@kernel.org> <mike.rapoport@gmail.com>

Documentation/admin-guide/LSM/landlock.rst

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Landlock: system-wide management
66
================================
77

88
:Author: Mickaël Salaün
9-
:Date: March 2025
9+
:Date: January 2026
1010

1111
Landlock can leverage the audit framework to log events.
1212

@@ -38,6 +38,37 @@ AUDIT_LANDLOCK_ACCESS
3838
domain=195ba459b blockers=fs.refer path="/usr/bin" dev="vda2" ino=351
3939
domain=195ba459b blockers=fs.make_reg,fs.refer path="/usr/local" dev="vda2" ino=365
4040

41+
42+
The ``blockers`` field uses dot-separated prefixes to indicate the type of
43+
restriction that caused the denial:
44+
45+
**fs.*** - Filesystem access rights (ABI 1+):
46+
- fs.execute, fs.write_file, fs.read_file, fs.read_dir
47+
- fs.remove_dir, fs.remove_file
48+
- fs.make_char, fs.make_dir, fs.make_reg, fs.make_sock
49+
- fs.make_fifo, fs.make_block, fs.make_sym
50+
- fs.refer (ABI 2+)
51+
- fs.truncate (ABI 3+)
52+
- fs.ioctl_dev (ABI 5+)
53+
54+
**net.*** - Network access rights (ABI 4+):
55+
- net.bind_tcp - TCP port binding was denied
56+
- net.connect_tcp - TCP connection was denied
57+
58+
**scope.*** - IPC scoping restrictions (ABI 6+):
59+
- scope.abstract_unix_socket - Abstract UNIX socket connection denied
60+
- scope.signal - Signal sending denied
61+
62+
Multiple blockers can appear in a single event (comma-separated) when
63+
multiple access rights are missing. For example, creating a regular file
64+
in a directory that lacks both ``make_reg`` and ``refer`` rights would show
65+
``blockers=fs.make_reg,fs.refer``.
66+
67+
The object identification fields (path, dev, ino for filesystem; opid,
68+
ocomm for signals) depend on the type of access being blocked and provide
69+
context about what resource was involved in the denial.
70+
71+
4172
AUDIT_LANDLOCK_DOMAIN
4273
This record type describes the status of a Landlock domain. The ``status``
4374
field can be either ``allocated`` or ``deallocated``.
@@ -86,7 +117,7 @@ This command generates two events, each identified with a unique serial
86117
number following a timestamp (``msg=audit(1729738800.268:30)``). The first
87118
event (serial ``30``) contains 4 records. The first record
88119
(``type=LANDLOCK_ACCESS``) shows an access denied by the domain `1a6fdc66f`.
89-
The cause of this denial is signal scopping restriction
120+
The cause of this denial is signal scoping restriction
90121
(``blockers=scope.signal``). The process that would have receive this signal
91122
is the init process (``opid=1 ocomm="systemd"``).
92123

Documentation/userspace-api/landlock.rst

Lines changed: 93 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Landlock: unprivileged access control
88
=====================================
99

1010
:Author: Mickaël Salaün
11-
:Date: March 2025
11+
:Date: January 2026
1212

1313
The goal of Landlock is to enable restriction of ambient rights (e.g. global
1414
filesystem or network access) for a set of processes. Because Landlock
@@ -142,11 +142,11 @@ This enables the creation of an inclusive ruleset that will contain our rules.
142142
}
143143
144144
We can now add a new rule to this ruleset thanks to the returned file
145-
descriptor referring to this ruleset. The rule will only allow reading the
146-
file hierarchy ``/usr``. Without another rule, write actions would then be
147-
denied by the ruleset. To add ``/usr`` to the ruleset, we open it with the
148-
``O_PATH`` flag and fill the &struct landlock_path_beneath_attr with this file
149-
descriptor.
145+
descriptor referring to this ruleset. The rule will allow reading and
146+
executing the file hierarchy ``/usr``. Without another rule, write actions
147+
would then be denied by the ruleset. To add ``/usr`` to the ruleset, we open
148+
it with the ``O_PATH`` flag and fill the &struct landlock_path_beneath_attr with
149+
this file descriptor.
150150

151151
.. code-block:: c
152152
@@ -191,10 +191,24 @@ number for a specific action: HTTPS connections.
191191
err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
192192
&net_port, 0);
193193
194+
When passing a non-zero ``flags`` argument to ``landlock_restrict_self()``, a
195+
similar backwards compatibility check is needed for the restrict flags
196+
(see sys_landlock_restrict_self() documentation for available flags):
197+
198+
.. code-block:: c
199+
200+
__u32 restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON;
201+
if (abi < 7) {
202+
/* Clear logging flags unsupported before ABI 7. */
203+
restrict_flags &= ~(LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF |
204+
LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON |
205+
LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF);
206+
}
207+
194208
The next step is to restrict the current thread from gaining more privileges
195209
(e.g. through a SUID binary). We now have a ruleset with the first rule
196-
allowing read access to ``/usr`` while denying all other handled accesses for
197-
the filesystem, and a second rule allowing HTTPS connections.
210+
allowing read and execute access to ``/usr`` while denying all other handled
211+
accesses for the filesystem, and a second rule allowing HTTPS connections.
198212

199213
.. code-block:: c
200214
@@ -208,7 +222,7 @@ The current thread is now ready to sandbox itself with the ruleset.
208222

209223
.. code-block:: c
210224
211-
if (landlock_restrict_self(ruleset_fd, 0)) {
225+
if (landlock_restrict_self(ruleset_fd, restrict_flags)) {
212226
perror("Failed to enforce ruleset");
213227
close(ruleset_fd);
214228
return 1;
@@ -431,9 +445,68 @@ system call:
431445
printf("Landlock supports LANDLOCK_ACCESS_FS_REFER.\n");
432446
}
433447
434-
The following kernel interfaces are implicitly supported by the first ABI
435-
version. Features only supported from a specific version are explicitly marked
436-
as such.
448+
All Landlock kernel interfaces are supported by the first ABI version unless
449+
explicitly noted in their documentation.
450+
451+
Landlock errata
452+
---------------
453+
454+
In addition to ABI versions, Landlock provides an errata mechanism to track
455+
fixes for issues that may affect backwards compatibility or require userspace
456+
awareness. The errata bitmask can be queried using:
457+
458+
.. code-block:: c
459+
460+
int errata;
461+
462+
errata = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_ERRATA);
463+
if (errata < 0) {
464+
/* Landlock not available or disabled */
465+
return 0;
466+
}
467+
468+
The returned value is a bitmask where each bit represents a specific erratum.
469+
If bit N is set (``errata & (1 << (N - 1))``), then erratum N has been fixed
470+
in the running kernel.
471+
472+
.. warning::
473+
474+
**Most applications should NOT check errata.** In 99.9% of cases, checking
475+
errata is unnecessary, increases code complexity, and can potentially
476+
decrease protection if misused. For example, disabling the sandbox when an
477+
erratum is not fixed could leave the system less secure than using
478+
Landlock's best-effort protection. When in doubt, ignore errata.
479+
480+
.. kernel-doc:: security/landlock/errata/abi-4.h
481+
:doc: erratum_1
482+
483+
.. kernel-doc:: security/landlock/errata/abi-6.h
484+
:doc: erratum_2
485+
486+
.. kernel-doc:: security/landlock/errata/abi-1.h
487+
:doc: erratum_3
488+
489+
How to check for errata
490+
~~~~~~~~~~~~~~~~~~~~~~~
491+
492+
If you determine that your application needs to check for specific errata,
493+
use this pattern:
494+
495+
.. code-block:: c
496+
497+
int errata = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_ERRATA);
498+
if (errata >= 0) {
499+
/* Check for specific erratum (1-indexed) */
500+
if (errata & (1 << (erratum_number - 1))) {
501+
/* Erratum N is fixed in this kernel */
502+
} else {
503+
/* Erratum N is NOT fixed - consider implications for your use case */
504+
}
505+
}
506+
507+
**Important:** Only check errata if your application specifically relies on
508+
behavior that changed due to the fix. The fixes generally make Landlock less
509+
restrictive or more correct, not more restrictive.
437510

438511
Kernel interface
439512
================
@@ -604,6 +677,14 @@ Landlock audit events with the ``LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF``,
604677
sys_landlock_restrict_self(). See Documentation/admin-guide/LSM/landlock.rst
605678
for more details on audit.
606679

680+
Thread synchronization (ABI < 8)
681+
--------------------------------
682+
683+
Starting with the Landlock ABI version 8, it is now possible to
684+
enforce Landlock rulesets across all threads of the calling process
685+
using the ``LANDLOCK_RESTRICT_SELF_TSYNC`` flag passed to
686+
sys_landlock_restrict_self().
687+
607688
.. _kernel_support:
608689

609690
Kernel support

include/uapi/linux/landlock.h

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,24 @@ struct landlock_ruleset_attr {
117117
* future nested domains, not the one being created. It can also be used
118118
* with a @ruleset_fd value of -1 to mute subdomain logs without creating a
119119
* domain.
120+
*
121+
* The following flag supports policy enforcement in multithreaded processes:
122+
*
123+
* %LANDLOCK_RESTRICT_SELF_TSYNC
124+
* Applies the new Landlock configuration atomically to all threads of the
125+
* current process, including the Landlock domain and logging
126+
* configuration. This overrides the Landlock configuration of sibling
127+
* threads, irrespective of previously established Landlock domains and
128+
* logging configurations on these threads.
129+
*
130+
* If the calling thread is running with no_new_privs, this operation
131+
* enables no_new_privs on the sibling threads as well.
120132
*/
121133
/* clang-format off */
122134
#define LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF (1U << 0)
123135
#define LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON (1U << 1)
124136
#define LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF (1U << 2)
137+
#define LANDLOCK_RESTRICT_SELF_TSYNC (1U << 3)
125138
/* clang-format on */
126139

127140
/**
@@ -182,11 +195,13 @@ struct landlock_net_port_attr {
182195
* It should be noted that port 0 passed to :manpage:`bind(2)` will bind
183196
* to an available port from the ephemeral port range. This can be
184197
* configured with the ``/proc/sys/net/ipv4/ip_local_port_range`` sysctl
185-
* (also used for IPv6).
198+
* (also used for IPv6), and within that range, on a per-socket basis
199+
* with ``setsockopt(IP_LOCAL_PORT_RANGE)``.
186200
*
187-
* A Landlock rule with port 0 and the ``LANDLOCK_ACCESS_NET_BIND_TCP``
201+
* A Landlock rule with port 0 and the %LANDLOCK_ACCESS_NET_BIND_TCP
188202
* right means that requesting to bind on port 0 is allowed and it will
189-
* automatically translate to binding on the related port range.
203+
* automatically translate to binding on a kernel-assigned ephemeral
204+
* port.
190205
*/
191206
__u64 port;
192207
};
@@ -329,13 +344,12 @@ struct landlock_net_port_attr {
329344
* These flags enable to restrict a sandboxed process to a set of network
330345
* actions.
331346
*
332-
* This is supported since Landlock ABI version 4.
333-
*
334347
* The following access rights apply to TCP port numbers:
335348
*
336-
* - %LANDLOCK_ACCESS_NET_BIND_TCP: Bind a TCP socket to a local port.
337-
* - %LANDLOCK_ACCESS_NET_CONNECT_TCP: Connect an active TCP socket to
338-
* a remote port.
349+
* - %LANDLOCK_ACCESS_NET_BIND_TCP: Bind TCP sockets to the given local
350+
* port. Support added in Landlock ABI version 4.
351+
* - %LANDLOCK_ACCESS_NET_CONNECT_TCP: Connect TCP sockets to the given
352+
* remote port. Support added in Landlock ABI version 4.
339353
*/
340354
/* clang-format off */
341355
#define LANDLOCK_ACCESS_NET_BIND_TCP (1ULL << 0)

security/landlock/Makefile

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
obj-$(CONFIG_SECURITY_LANDLOCK) := landlock.o
22

3-
landlock-y := setup.o syscalls.o object.o ruleset.o \
4-
cred.o task.o fs.o
3+
landlock-y := \
4+
setup.o \
5+
syscalls.o \
6+
object.o \
7+
ruleset.o \
8+
cred.o \
9+
task.o \
10+
fs.o \
11+
tsync.o
512

613
landlock-$(CONFIG_INET) += net.o
714

security/landlock/access.h

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,30 @@ union access_masks_all {
6161
static_assert(sizeof(typeof_member(union access_masks_all, masks)) ==
6262
sizeof(typeof_member(union access_masks_all, all)));
6363

64-
typedef u16 layer_mask_t;
65-
66-
/* Makes sure all layers can be checked. */
67-
static_assert(BITS_PER_TYPE(layer_mask_t) >= LANDLOCK_MAX_NUM_LAYERS);
64+
/**
65+
* struct layer_access_masks - A boolean matrix of layers and access rights
66+
*
67+
* This has a bit for each combination of layer numbers and access rights.
68+
* During access checks, it is used to represent the access rights for each
69+
* layer which still need to be fulfilled. When all bits are 0, the access
70+
* request is considered to be fulfilled.
71+
*/
72+
struct layer_access_masks {
73+
/**
74+
* @access: The unfulfilled access rights for each layer.
75+
*/
76+
access_mask_t access[LANDLOCK_MAX_NUM_LAYERS];
77+
};
6878

6979
/*
70-
* Tracks domains responsible of a denied access. This is required to avoid
71-
* storing in each object the full layer_masks[] required by update_request().
80+
* Tracks domains responsible of a denied access. This avoids storing in each
81+
* object the full matrix of per-layer unfulfilled access rights, which is
82+
* required by update_request().
83+
*
84+
* Each nibble represents the layer index of the newest layer which denied a
85+
* certain access right. For file system access rights, the upper four bits are
86+
* the index of the layer which denies LANDLOCK_ACCESS_FS_IOCTL_DEV and the
87+
* lower nibble represents LANDLOCK_ACCESS_FS_TRUNCATE.
7288
*/
7389
typedef u8 deny_masks_t;
7490

@@ -97,4 +113,11 @@ landlock_upgrade_handled_access_masks(struct access_masks access_masks)
97113
return access_masks;
98114
}
99115

116+
/* Checks the subset relation between access masks. */
117+
static inline bool access_mask_subset(access_mask_t subset,
118+
access_mask_t superset)
119+
{
120+
return (subset | superset) == superset;
121+
}
122+
100123
#endif /* _SECURITY_LANDLOCK_ACCESS_H */

0 commit comments

Comments
 (0)