Files
linux/Documentation/security/landlock.rst
Günther Noack ae97330d1b landlock: Control pathname UNIX domain socket resolution by path
* Add a new access right LANDLOCK_ACCESS_FS_RESOLVE_UNIX, which
  controls the lookup operations for named UNIX domain sockets.  The
  resolution happens during connect() and sendmsg() (depending on
  socket type).
* Change access_mask_t from u16 to u32 (see below)
* Hook into the path lookup in unix_find_bsd() in af_unix.c, using a
  LSM hook.  Make policy decisions based on the new access rights
* Increment the Landlock ABI version.
* Minor test adaptations to keep the tests working.
* Document the design rationale for scoped access rights,
  and cross-reference it from the header documentation.

With this access right, access is granted if either of the following
conditions is met:

* The target socket's filesystem path was allow-listed using a
  LANDLOCK_RULE_PATH_BENEATH rule, *or*:
* The target socket was created in the same Landlock domain in which
  LANDLOCK_ACCESS_FS_RESOLVE_UNIX was restricted.

In case of a denial, connect() and sendmsg() return EACCES, which is
the same error as it is returned if the user does not have the write
bit in the traditional UNIX file system permissions of that file.

The access_mask_t type grows from u16 to u32 to make space for the new
access right.  This also doubles the size of struct layer_access_masks
from 32 byte to 64 byte.  To avoid memory layout inconsistencies between
architectures (especially m68k), pack and align struct access_masks [2].

Document the (possible future) interaction between scoped flags and
other access rights in struct landlock_ruleset_attr, and summarize the
rationale, as discussed in code review leading up to [3].

This feature was created with substantial discussion and input from
Justin Suess, Tingmao Wang and Mickaël Salaün.

Cc: Tingmao Wang <m@maowtm.org>
Cc: Justin Suess <utilityemal77@gmail.com>
Cc: Kuniyuki Iwashima <kuniyu@google.com>
Suggested-by: Jann Horn <jannh@google.com>
Link[1]: https://github.com/landlock-lsm/linux/issues/36
Link[2]: https://lore.kernel.org/all/20260401.Re1Eesu1Yaij@digikod.net/
Link[3]: https://lore.kernel.org/all/20260205.8531e4005118@gnoack.org/
Signed-off-by: Günther Noack <gnoack3000@gmail.com>
Acked-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Link: https://lore.kernel.org/r/20260327164838.38231-5-gnoack3000@gmail.com
[mic: Fix kernel-doc formatting, pack and align access_masks]
Signed-off-by: Mickaël Salaün <mic@digikod.net>
2026-04-07 18:51:06 +02:00

190 lines
7.6 KiB
ReStructuredText

.. SPDX-License-Identifier: GPL-2.0
.. Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
.. Copyright © 2019-2020 ANSSI
==================================
Landlock LSM: kernel documentation
==================================
:Author: Mickaël Salaün
:Date: March 2026
Landlock's goal is to create scoped access-control (i.e. sandboxing). To
harden a whole system, this feature should be available to any process,
including unprivileged ones. Because such a process may be compromised or
backdoored (i.e. untrusted), Landlock's features must be safe to use from the
kernel and other processes point of view. Landlock's interface must therefore
expose a minimal attack surface.
Landlock is designed to be usable by unprivileged processes while following the
system security policy enforced by other access control mechanisms (e.g. DAC,
LSM). A Landlock rule shall not interfere with other access-controls enforced
on the system, only add more restrictions.
Any user can enforce Landlock rulesets on their processes. They are merged and
evaluated against inherited rulesets in a way that ensures that only more
constraints can be added.
User space documentation can be found here:
Documentation/userspace-api/landlock.rst.
Guiding principles for safe access controls
===========================================
* A Landlock rule shall be focused on access control on kernel objects instead
of syscall filtering (i.e. syscall arguments), which is the purpose of
seccomp-bpf.
* To avoid multiple kinds of side-channel attacks (e.g. leak of security
policies, CPU-based attacks), Landlock rules shall not be able to
programmatically communicate with user space.
* Kernel access check shall not slow down access request from unsandboxed
processes.
* Computation related to Landlock operations (e.g. enforcing a ruleset) shall
only impact the processes requesting them.
* Resources (e.g. file descriptors) directly obtained from the kernel by a
sandboxed process shall retain their scoped accesses (at the time of resource
acquisition) whatever process uses them.
Cf. `File descriptor access rights`_.
* Access denials shall be logged according to system and Landlock domain
configurations. Log entries must contain information about the cause of the
denial and the owner of the related security policy. Such log generation
should have a negligible performance and memory impact on allowed requests.
Design choices
==============
Inode access rights
-------------------
All access rights are tied to an inode and what can be accessed through it.
Reading the content of a directory does not imply to be allowed to read the
content of a listed inode. Indeed, a file name is local to its parent
directory, and an inode can be referenced by multiple file names thanks to
(hard) links. Being able to unlink a file only has a direct impact on the
directory, not the unlinked inode. This is the reason why
``LANDLOCK_ACCESS_FS_REMOVE_FILE`` or ``LANDLOCK_ACCESS_FS_REFER`` are not
allowed to be tied to files but only to directories.
File descriptor access rights
-----------------------------
Access rights are checked and tied to file descriptors at open time. The
underlying principle is that equivalent sequences of operations should lead to
the same results, when they are executed under the same Landlock domain.
Taking the ``LANDLOCK_ACCESS_FS_TRUNCATE`` right as an example, it may be
allowed to open a file for writing without being allowed to
:manpage:`ftruncate` the resulting file descriptor if the related file
hierarchy doesn't grant that access right. The following sequences of
operations have the same semantic and should then have the same result:
* ``truncate(path);``
* ``int fd = open(path, O_WRONLY); ftruncate(fd); close(fd);``
Similarly to file access modes (e.g. ``O_RDWR``), Landlock access rights
attached to file descriptors are retained even if they are passed between
processes (e.g. through a Unix domain socket). Such access rights will then be
enforced even if the receiving process is not sandboxed by Landlock. Indeed,
this is required to keep access controls consistent over the whole system, and
this avoids unattended bypasses through file descriptor passing (i.e. confused
deputy attack).
.. _scoped-flags-interaction:
Interaction between scoped flags and other access rights
--------------------------------------------------------
The ``scoped`` flags in &struct landlock_ruleset_attr restrict the
use of *outgoing* IPC from the created Landlock domain, while they
permit reaching out to IPC endpoints *within* the created Landlock
domain.
In the future, scoped flags *may* interact with other access rights,
e.g. so that abstract UNIX sockets can be allow-listed by name, or so
that signals can be allow-listed by signal number or target process.
When introducing ``LANDLOCK_ACCESS_FS_RESOLVE_UNIX``, we defined it to
implicitly have the same scoping semantics as a
``LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET`` flag would have: connecting to
UNIX sockets within the same domain (where
``LANDLOCK_ACCESS_FS_RESOLVE_UNIX`` is used) is unconditionally
allowed.
The reasoning is:
* Like other IPC mechanisms, connecting to named UNIX sockets in the
same domain should be expected and harmless. (If needed, users can
further refine their Landlock policies with nested domains or by
restricting ``LANDLOCK_ACCESS_FS_MAKE_SOCK``.)
* We reserve the option to still introduce
``LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET`` in the future. (This would
be useful if we wanted to have a Landlock rule to permit IPC access
to other Landlock domains.)
* But we can postpone the point in time when users have to deal with
two interacting flags visible in the userspace API. (In particular,
it is possible that it won't be needed in practice, in which case we
can avoid the second flag altogether.)
* If we *do* introduce ``LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET`` in the
future, setting this scoped flag in a ruleset does *not reduce* the
restrictions, because access within the same scope is already
allowed based on ``LANDLOCK_ACCESS_FS_RESOLVE_UNIX``.
Tests
=====
Userspace tests for backward compatibility, ptrace restrictions and filesystem
support can be found here: `tools/testing/selftests/landlock/`_.
Kernel structures
=================
Object
------
.. kernel-doc:: security/landlock/object.h
:identifiers:
Filesystem
----------
.. kernel-doc:: security/landlock/fs.h
:identifiers:
Process credential
------------------
.. kernel-doc:: security/landlock/cred.h
:identifiers:
Ruleset and domain
------------------
A domain is a read-only ruleset tied to a set of subjects (i.e. tasks'
credentials). Each time a ruleset is enforced on a task, the current domain is
duplicated and the ruleset is imported as a new layer of rules in the new
domain. Indeed, once in a domain, each rule is tied to a layer level. To
grant access to an object, at least one rule of each layer must allow the
requested action on the object. A task can then only transit to a new domain
that is the intersection of the constraints from the current domain and those
of a ruleset provided by the task.
The definition of a subject is implicit for a task sandboxing itself, which
makes the reasoning much easier and helps avoid pitfalls.
.. kernel-doc:: security/landlock/ruleset.h
:identifiers:
.. kernel-doc:: security/landlock/domain.h
:identifiers:
Additional documentation
========================
* Documentation/userspace-api/landlock.rst
* Documentation/admin-guide/LSM/landlock.rst
* https://landlock.io
.. Links
.. _tools/testing/selftests/landlock/:
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/tools/testing/selftests/landlock/