mirror of
https://github.com/torvalds/linux.git
synced 2026-10-08 03:26:02 +02:00
Until now, Landlock observability documentation covered only audit records. The tracepoints added by the previous commits introduce a second channel with different semantics (firing regardless of audit configuration and domain log flags, exposing the full ruleset and domain state to eBPF via BTF), which kernel developers, administrators, and userspace tool authors need to discover and compare against audit. Add a dedicated "Landlock Trace Events" reference covering the event categories, enabling events via tracefs, ruleset versioning, eBPF access through BPF_RAW_TRACEPOINT, and the same_exec and logged denial fields (logged being the kernel's audit-logging decision, so a stateless ftrace filter can select the denials audit would record with logged==1). Cross-reference it from the administrator, kernel-internals, and userspace API documents, contrasting tracepoints with audit: when each channel is preferred, what each guarantees, and how NOAUDIT hooks and audit rate limiting affect them. Also document the relational other-party domain fields the scope and ptrace denial tracepoints expose (tracee_domain, target_domain, peer_domain; 0 when the other party is unsandboxed), so a consumer can resolve them against the lifecycle events and reproduce the two-domain verdict. Cc: Günther Noack <gnoack@google.com> Cc: Tingmao Wang <m@maowtm.org> Link: https://patch.msgid.link/20260811094338.288094-20-mic@digikod.net [mic: Update dates] Signed-off-by: Mickaël Salaün <mic@digikod.net>
226 lines
9.1 KiB
ReStructuredText
226 lines
9.1 KiB
ReStructuredText
.. SPDX-License-Identifier: GPL-2.0
|
|
.. Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
|
|
.. Copyright © 2019-2020 ANSSI
|
|
.. Copyright © 2026 Cloudflare, Inc.
|
|
|
|
==================================
|
|
Landlock LSM: kernel documentation
|
|
==================================
|
|
|
|
:Author: Mickaël Salaün
|
|
:Date: August 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:
|
|
|
|
Denial logging
|
|
==============
|
|
|
|
Access denials are logged through two independent channels: audit
|
|
records and tracepoints. Both are managed by the common denial
|
|
framework in ``log.c``, compiled under ``CONFIG_SECURITY_LANDLOCK_LOG``
|
|
(automatically selected by ``CONFIG_AUDIT`` or ``CONFIG_TRACEPOINTS``).
|
|
|
|
Audit records respect audit configuration, the domain's Landlock log
|
|
flags, and ``LANDLOCK_LOG_DISABLED``. Tracepoints fire unconditionally,
|
|
independent of these settings. The denial counter (``num_denials``) is
|
|
always incremented regardless of logging configuration.
|
|
|
|
Each denial tracepoint carries a ``logged`` field reporting the
|
|
audit-logging verdict: whether the denial would be written to the audit
|
|
log if audit were configured and active. This verdict is the same
|
|
whether or not the kernel is built with audit support, so a
|
|
tracepoints-only build reports the selection audit would make. A quiet
|
|
rule (``LANDLOCK_ADD_RULE_QUIET`` with the access in the ``quiet_*``
|
|
fields of ``struct landlock_ruleset_attr``) suppresses logging by
|
|
setting ``logged=0`` the same way.
|
|
|
|
See Documentation/admin-guide/LSM/landlock.rst for audit record format,
|
|
tracepoint usage, and filtering examples.
|
|
|
|
.. kernel-doc:: security/landlock/log.h
|
|
:identifiers:
|
|
|
|
Trace events
|
|
------------
|
|
|
|
See Documentation/trace/events-landlock.rst for trace event usage and format
|
|
details; the full event reference lives there and is not duplicated here.
|
|
|
|
Additional documentation
|
|
========================
|
|
|
|
* Documentation/userspace-api/landlock.rst
|
|
* Documentation/admin-guide/LSM/landlock.rst
|
|
* Documentation/trace/events-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/
|