요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
.. Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
.. Copyright © 2019-2020 ANSSI
.. Copyright © 2021-2022 Microsoft Corporation
=====================================
Landlock: unprivileged access control
=====================================
:Author: Mickaël Salaün
:Date: March 2025
The goal of Landlock is to enable restriction of ambient rights (e.g. global
filesystem or network access) for a set of processes. Because Landlock
is a stackable LSM, it makes it possible to create safe security sandboxes as
new security layers in addition to the existing system-wide access-controls.
This kind of sandbox is expected to help mitigate the security impact of bugs or
unexpected/malicious behaviors in user space applications. Landlock empowers
any process, including unprivileged ones, to securely restrict themselves.
We can quickly make sure that Landlock is enabled in the running system by
looking for "landlock: Up and running" in kernel logs (as root):
``dmesg | grep landlock || journalctl -kb -g landlock`` .
Developers can also easily check for Landlock support with a
:ref:`related system call <landlock_abi_versions>`.
If Landlock is not currently supported, we need to
:ref:`configure the kernel appropriately <kernel_support>`.
Landlock rules
==============
A Landlock rule describes an action on an object which the process intends to
perform. A set of rules is aggregated in a ruleset, which can then restrict
the thread enforcing it, and its future children.
The two existing types of rules are:
Filesystem rules
For these rules, the object is a file hierarchy,
and the related filesystem actions are defined with
`filesystem access rights`.
Network rules (since ABI v4)
For these rules, the object is a TCP port,
and the related actions are defined with `network access rights`.
Defining and enforcing a security policy
----------------------------------------
We first need to define the ruleset that will contain our rules.
For this example, the ruleset will contain rules that only allow filesystem
read actions and establish a specific TCP connection. Filesystem write
actions and other TCP actions will be denied.
The ruleset then needs to handle both these kinds of actions. This is
required for backward and forward compatibility (i.e. the kernel and user
space may not know each other's supported restrictions), hence the need
to be explicit about the denied-by-default access rights.
.. code-block:: c
struct landlock_ruleset_attr ruleset_attr = {
.handled_access_fs =
LANDLOCK_ACCESS_FS_EXECUTE |
LANDLOCK_ACCESS_FS_WRITE_FILE |
LANDLOCK_ACCESS_FS_READ_FILE |
LANDLOCK_ACCESS_FS_READ_DIR |
LANDLOCK_ACCESS_FS_REMOVE_DIR |
LANDLOCK_ACCESS_FS_REMOVE_FILE |
LANDLOCK_ACCESS_FS_MAKE_CHAR |
LANDLOCK_ACCESS_FS_MAKE_DIR |
LANDLOCK_ACCESS_FS_MAKE_REG |
LANDLOCK_ACCESS_FS_MAKE_SOCK |
LANDLOCK_ACCESS_FS_MAKE_FIFO |
LANDLOCK_ACCESS_FS_MAKE_BLOCK |
LANDLOCK_ACCESS_FS_MAKE_SYM |
LANDLOCK_ACCESS_FS_REFER |
LANDLOCK_ACCESS_FS_TRUNCATE |
LANDLOCK_ACCESS_FS_IOCTL_DEV,
.handled_access_net =
LANDLOCK_ACCESS_NET_BIND_TCP |
LANDLOCK_ACCESS_NET_CONNECT_TCP,
.scoped =
LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET |
LANDLOCK_SCOPE_SIGNAL,
};
Because we may not know which kernel version an application will be executed
on, it is safer to follow a best-effort security approach. Indeed, we
should try to protect users as much as possible whatever the kernel they are
using.
To be compatible with older Linux versions, we detect the available Landlock ABI
version, and only use the available subset of access rights:
.. code-block:: c
int abi;
abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
if (abi < 0) {
/* Degrades gracefully if Landlock is not handled. */
perror("The running kernel does not enable to use Landlock");
return 0;
}
switch (abi) {
case 1:
/* Removes LANDLOCK_ACCESS_FS_REFER for ABI < 2 */
ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER;
__attribute__((fallthrough));
case 2:
/* Removes LANDLOCK_ACCESS_FS_TRUNCATE for ABI < 3 */
ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE;
__attribute__((fallthrough));
case 3:
/* Removes network support for ABI < 4 */
ruleset_attr.handled_access_net &=
~(LANDLOCK_ACCESS_NET_BIND_TCP |
LANDLOCK_ACCESS_NET_CONNECT_TCP);
__attribute__((fallthrough));
case 4:
/* Removes LANDLOCK_ACCESS_FS_IOCTL_DEV for ABI < 5 */
ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_IOCTL_DEV;
__attribute__((fallthrough));
case 5:
/* Removes LANDLOCK_SCOPE_* for ABI < 6 */
ruleset_attr.scoped &= ~(LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET |
LANDLOCK_SCOPE_SIGNAL);
}
This enables the creation of an inclusive ruleset that will contain our rules.
.. code-block:: c
int ruleset_fd;
ruleset_fd = landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
if (ruleset_fd < 0) {
perror("Failed to create a ruleset");
return 1;
}
We can now add a new rule to this ruleset thanks to the returned file
descriptor referring to this ruleset. The rule will only allow reading the
file hierarchy ``/usr``. Without another rule, write actions would then be
denied by the ruleset. To add ``/usr`` to the ruleset, we open it with the
``O_PATH`` flag and fill the &struct landlock_path_beneath_attr with this file
descriptor.
.. code-block:: c
int err;
struct landlock_path_beneath_attr path_beneath = {
.allowed_access =
LANDLOCK_ACCESS_FS_EXECUTE |
LANDLOCK_ACCESS_FS_READ_FILE |
LANDLOCK_ACCESS_FS_READ_DIR,
};
path_beneath.parent_fd = open("/usr", O_PATH | O_CLOEXEC);
if (path_beneath.parent_fd < 0) {
perror("Failed to open file");
close(ruleset_fd);
return 1;
}
err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
&path_beneath, 0);
close(path_beneath.parent_fd);
if (err) {
perror("Failed to update ruleset");
close(ruleset_fd);
return 1;
}
It may also be required to create rules following the same logic as explained
for the ruleset creation, by filtering access rights according to the Landlock
ABI version. In this example, this is not required because all of the requested
``allowed_access`` rights are already available in ABI 1.
For network access-control, we can add a set of rules that allow to use a port
number for a specific action: HTTPS connections.
.. code-block:: c
struct landlock_net_port_attr net_port = {
.allowed_access = LANDLOCK_ACCESS_NET_CONNECT_TCP,
.port = 443,
};
err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
&net_port, 0);
The next step is to restrict the current thread from gaining more privileges
(e.g. through a SUID binary). We now have a ruleset with the first rule
allowing read access to ``/usr`` while denying all other handled accesses for
the filesystem, and a second rule allowing HTTPS connections.
.. code-block:: c
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
perror("Failed to restrict privileges");
close(ruleset_fd);
return 1;
}
The current thread is now ready to sandbox itself with the ruleset.
.. code-block:: c
if (landlock_restrict_self(ruleset_fd, 0)) {
perror("Failed to enforce ruleset");
close(ruleset_fd);
return 1;
}
close(ruleset_fd);
If the ``landlock_restrict_self`` system call succeeds, the current thread is
now restricted and this policy will be enforced on all its subsequently created
children as well. Once a thread is landlocked, there is no way to remove its
security policy; only adding more restrictions is allowed. These threads are
now in a new Landlock domain, which is a merger of their parent one (if any)
with the new ruleset.
Full working code can be found in `samples/landlock/sandboxer.c`_.
Good practices
--------------
It is recommended to set access rights to file hierarchy leaves as much as
possible. For instance, it is better to be able to have ``~/doc/`` as a
read-only hierarchy and ``~/tmp/`` as a read-write hierarchy, compared to
``~/`` as a read-only hierarchy and ``~/tmp/`` as a read-write hierarchy.
Following this good practice leads to self-sufficient hierarchies that do not
depend on their location (i.e. parent directories). This is particularly
relevant when we want to allow linking or renaming. Indeed, having consistent
access rights per directory enables changing the location of such directories
without relying on the destination directory access rights (except those that
are required for this operation, see ``LANDLOCK_ACCESS_FS_REFER``
documentation).
Having self-sufficient hierarchies also helps to tighten the required access
rights to the minimal set of data. This also helps avoid sinkhole directories,
i.e. directories where data can be linked to but not linked from. However,
this depends on data organization, which might not be controlled by developers.
In this case, granting read-write access to ``~/tmp/``, instead of write-only
access, would potentially allow moving ``~/tmp/`` to a non-readable directory
and still keep the ability to list the content of ``~/tmp/``.
Layers of file path access rights
---------------------------------
Each time a thread enforces a ruleset on itself, it updates its Landlock domain
with a new layer of policy. This complementary policy is stacked with any
other rulesets potentially already restricting this thread. A sandboxed thread
can then safely add more constraints to itself with a new enforced ruleset.
One policy layer grants access to a file path if at least one of its rules
encountered on the path grants the access. A sandboxed thread can only access
a file path if all its enforced policy layers grant the access as well as all
the other system access controls (e.g. filesystem DAC, other LSM policies,
etc.).
Bind mounts and OverlayFS
-------------------------
Landlock enables restricting access to file hierarchies, which means that these
access rights can be propagated with bind mounts (cf.
Documentation/filesystems/sharedsubtree.rst) but not with
Documentation/filesystems/overlayfs.rst.
A bind mount mirrors a source file hierarchy to a destination. The destination
hierarchy is then composed of the exact same files, on which Landlock rules can
be tied, either via the source or the destination path. These rules restrict
access when they are encountered on a path, which means that they can restrict
access to multiple file hierarchies at the same time, whether these hierarchies
are the result of bind mounts or not.
An OverlayFS mount point consists of upper and lower layers. These layers are
combined in a merge directory, and that merged directory becomes available at
the mount point. This merge hierarchy may include files from the upper and
lower layers, but modifications performed on the merge hierarchy only reflect
on the upper layer. From a Landlock policy point of view, all OverlayFS layers
and merge hierarchies are standalone and each contains their own set of files
and directories, which is different from bind mounts. A policy restricting an
OverlayFS layer will not restrict the resulted merged hierarchy, and vice versa.
Landlock users should then only think about file hierarchies they want to allow
access to, regardless of the underlying filesystem.
Inheritance
-----------
Every new thread resulting from a :manpage:`clone(2)` inherits Landlock domain
restrictions from its parent. This is similar to seccomp inheritance (cf.
Documentation/userspace-api/seccomp_filter.rst) or any other LSM dealing with
task's :manpage:`credentials(7)`. For instance, one process's thread may apply
Landlock rules to itself, but they will not be automatically applied to other
sibling threads (unlike POSIX thread credential changes, cf.
:manpage:`nptl(7)`).
When a thread sandboxes itself, we have the guarantee that the related security
policy will stay enforced on all this thread's descendants. This allows
creating standalone and modular security policies per application, which will
automatically be composed between themselves according to their runtime parent
policies.
Ptrace restrictions
-------------------
A sandboxed process has less privileges than a non-sandboxed process and must
then be subject to additional restrictions when manipulating another process.
To be allowed to use :manpage:`ptrace(2)` and related syscalls on a target
process, a sandboxed process should have a superset of the target process's
access rights, which means the tracee must be in a sub-domain of the tracer.
IPC scoping
-----------
Similar to the implicit `Ptrace restrictions`_, we may want to further restrict
interactions between sandboxes. Therefore, at ruleset creation time, each
Landlock domain can restrict the scope for certain operations, so that these
operations can only reach out to processes within the same Landlock domain or in
a nested Landlock domain (the "scope").
The operations which can be scoped are:
``LANDLOCK_SCOPE_SIGNAL``
This limits the sending of signals to target processes which run within the
same or a nested Landlock domain.
``LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET``
This limits the set of abstract :manpage:`unix(7)` sockets to which we can
:manpage:`connect(2)` to socket addresses which were created by a process in
the same or a nested Landlock domain.
A :manpage:`sendto(2)` on a non-connected datagram socket is treated as if
it were doing an implicit :manpage:`connect(2)` and will be blocked if the
remote end does not stem from the same or a nested Landlock domain.
A :manpage:`sendto(2)` on a socket which was previously connected will not
be restricted. This works for both datagram and stream sockets.
IPC scoping does not support exceptions via :manpage:`landlock_add_rule(2)`.
If an operation is scoped within a domain, no rules can be added to allow access
to resources or processes outside of the scope.
Truncating files
----------------
The operations covered by ``LANDLOCK_ACCESS_FS_WRITE_FILE`` and
``LANDLOCK_ACCESS_FS_TRUNCATE`` both change the contents of a file and sometimes
overlap in non-intuitive ways. It is recommended to always specify both of
these together.
A particularly surprising example is :manpage:`creat(2)`. The name suggests
that this system call requires the rights to create and write files. However,
it also requires the truncate right if an existing file under the same name is
already present.
It should also be noted that truncating files does not require the
``LANDLOCK_ACCESS_FS_WRITE_FILE`` right. Apart from the :manpage:`truncate(2)`
system call, this can also be done through :manpage:`open(2)` with the flags
``O_RDONLY | O_TRUNC``.
The truncate right is associated with the opened file (see below).
Rights associated with file descriptors
---------------------------------------
When opening a file, the availability of the ``LANDLOCK_ACCESS_FS_TRUNCATE`` and
``LANDLOCK_ACCESS_FS_IOCTL_DEV`` rights is associated with the newly created
file descriptor and will be used for subsequent truncation and ioctl attempts
using :manpage:`ftruncate(2)` and :manpage:`ioctl(2)`. The behavior is similar
to opening a file for reading or writing, where permissions are checked during
:manpage:`open(2)`, but not during the subsequent :manpage:`read(2)` and
:manpage:`write(2)` calls.
As a consequence, it is possible that a process has multiple open file
descriptors referring to the same file, but Landlock enforces different things
when operating with these file descriptors. This can happen when a Landlock
ruleset gets enforced and the process keeps file descriptors which were opened
both before and after the enforcement. It is also possible to pass such file
descriptors between processes, keeping their Landlock properties, even when some
of the involved processes do not have an enforced Landlock ruleset.
Compatibility
=============
Backward and forward compatibility
----------------------------------
Landlock is designed to be compatible with past and future versions of the
kernel. This is achieved thanks to the system call attributes and the
associated bitflags, particularly the ruleset's ``handled_access_fs``. Making
handled access rights explicit enables the kernel and user space to have a clear
contract with each other. This is required to make sure sandboxing will not
get stricter with a system update, which could break applications.
Developers can subscribe to the `Landlock mailing list
<https://subspace.kernel.org/lists.linux.dev.html>`_ to knowingly update and
test their applications with the latest available features. In the interest of
users, and because they may use different kernel versions, it is strongly
encouraged to follow a best-effort security approach by checking the Landlock
ABI version at runtime and only enforcing the supported features.
.. _landlock_abi_versions:
Landlock ABI versions
---------------------
The Landlock ABI version can be read with the sys_landlock_create_ruleset()
system call:
.. code-block:: c
int abi;
abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
if (abi < 0) {
switch (errno) {
case ENOSYS:
printf("Landlock is not supported by the current kernel.\n");
break;
case EOPNOTSUPP:
printf("Landlock is currently disabled.\n");
break;
}
return 0;
}
if (abi >= 2) {
printf("Landlock supports LANDLOCK_ACCESS_FS_REFER.\n");
}
The following kernel interfaces are implicitly supported by the first ABI
version. Features only supported from a specific version are explicitly marked
as such.
Kernel interface
================
Access rights
-------------
.. kernel-doc:: include/uapi/linux/landlock.h
:identifiers: fs_access net_access scope
Creating a new ruleset
----------------------
.. kernel-doc:: security/landlock/syscalls.c
:identifiers: sys_landlock_create_ruleset
.. kernel-doc:: include/uapi/linux/landlock.h
:identifiers: landlock_ruleset_attr
Extending a ruleset
-------------------
.. kernel-doc:: security/landlock/syscalls.c
:identifiers: sys_landlock_add_rule
.. kernel-doc:: include/uapi/linux/landlock.h
:identifiers: landlock_rule_type landlock_path_beneath_attr
landlock_net_port_attr
Enforcing a ruleset
-------------------
.. kernel-doc:: security/landlock/syscalls.c
:identifiers: sys_landlock_restrict_self
Current limitations
===================
Filesystem topology modification
--------------------------------
Threads sandboxed with filesystem restrictions cannot modify filesystem
topology, whether via :manpage:`mount(2)` or :manpage:`pivot_root(2)`.
However, :manpage:`chroot(2)` calls are not denied.
Special filesystems
-------------------
Access to regular files and directories can be restricted by Landlock,
according to the handled accesses of a ruleset. However, files that do not
come from a user-visible filesystem (e.g. pipe, socket), but can still be
accessed through ``/proc/<pid>/fd/*``, cannot currently be explicitly
restricted. Likewise, some special kernel filesystems such as nsfs, which can
be accessed through ``/proc/<pid>/ns/*``, cannot currently be explicitly
restricted. However, thanks to the `ptrace restrictions`_, access to such
sensitive ``/proc`` files are automatically restricted according to domain
hierarchies. Future Landlock evolutions could still enable to explicitly
restrict such paths with dedicated ruleset flags.
Ruleset layers
--------------
There is a limit of 16 layers of stacked rulesets. This can be an issue for a
task willing to enforce a new ruleset in complement to its 16 inherited
rulesets. Once this limit is reached, sys_landlock_restrict_self() returns
E2BIG. It is then strongly suggested to carefully build rulesets once in the
life of a thread, especially for applications able to launch other applications
that may also want to sandbox themselves (e.g. shells, container managers,
etc.).
Memory usage
------------
Kernel memory allocated to create rulesets is accounted and can be restricted
by the Documentation/admin-guide/cgroup-v1/memory.rst.
IOCTL support
-------------
The ``LANDLOCK_ACCESS_FS_IOCTL_DEV`` right restricts the use of
:manpage:`ioctl(2)`, but it only applies to *newly opened* device files. This
means specifically that pre-existing file descriptors like stdin, stdout and
stderr are unaffected.
Users should be aware that TTY devices have traditionally permitted to control
other processes on the same TTY through the ``TIOCSTI`` and ``TIOCLINUX`` IOCTL
commands. Both of these require ``CAP_SYS_ADMIN`` on modern Linux systems, but
the behavior is configurable for ``TIOCSTI``.
On older systems, it is therefore recommended to close inherited TTY file
descriptors, or to reopen them from ``/proc/self/fd/*`` without the
``LANDLOCK_ACCESS_FS_IOCTL_DEV`` right, if possible.
Landlock's IOCTL support is coarse-grained at the moment, but may become more
fine-grained in the future. Until then, users are advised to establish the
guarantees that they need through the file hierarchy, by only allowing the
``LANDLOCK_ACCESS_FS_IOCTL_DEV`` right on files where it is really required.
Previous limitations
====================
File renaming and linking (ABI < 2)
-----------------------------------
Because Landlock targets unprivileged access controls, it needs to properly
handle composition of rules. Such property also implies rules nesting.
Properly handling multiple layers of rulesets, each one of them able to
restrict access to files, also implies inheritance of the ruleset restrictions
from a parent to its hierarchy. Because files are identified and restricted by
their hierarchy, moving or linking a file from one directory to another implies
propagation of the hierarchy constraints, or restriction of these actions
according to the potentially lost constraints. To protect against privilege
escalations through renaming or linking, and for the sake of simplicity,
Landlock previously limited linking and renaming to the same directory.
Starting with the Landlock ABI version 2, it is now possible to securely
control renaming and linking thanks to the new ``LANDLOCK_ACCESS_FS_REFER``
access right.
File truncation (ABI < 3)
-------------------------
File truncation could not be denied before the third Landlock ABI, so it is
always allowed when using a kernel that only supports the first or second ABI.
Starting with the Landlock ABI version 3, it is now possible to securely control
truncation thanks to the new ``LANDLOCK_ACCESS_FS_TRUNCATE`` access right.
TCP bind and connect (ABI < 4)
------------------------------
Starting with the Landlock ABI version 4, it is now possible to restrict TCP
bind and connect actions to only a set of allowed ports thanks to the new
``LANDLOCK_ACCESS_NET_BIND_TCP`` and ``LANDLOCK_ACCESS_NET_CONNECT_TCP``
access rights.
Device IOCTL (ABI < 5)
----------------------
IOCTL operations could not be denied before the fifth Landlock ABI, so
:manpage:`ioctl(2)` is always allowed when using a kernel that only supports an
earlier ABI.
Starting with the Landlock ABI version 5, it is possible to restrict the use of
:manpage:`ioctl(2)` on character and block devices using the new
``LANDLOCK_ACCESS_FS_IOCTL_DEV`` right.
Abstract UNIX socket (ABI < 6)
------------------------------
Starting with the Landlock ABI version 6, it is possible to restrict
connections to an abstract :manpage:`unix(7)` socket by setting
``LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET`` to the ``scoped`` ruleset attribute.
Signal (ABI < 6)
----------------
Starting with the Landlock ABI version 6, it is possible to restrict
:manpage:`signal(7)` sending by setting ``LANDLOCK_SCOPE_SIGNAL`` to the
``scoped`` ruleset attribute.
Logging (ABI < 7)
-----------------
Starting with the Landlock ABI version 7, it is possible to control logging of
Landlock audit events with the ``LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF``,
``LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON``, and
``LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF`` flags passed to
sys_landlock_restrict_self(). See Documentation/admin-guide/LSM/landlock.rst
for more details on audit.
.. _kernel_support:
Kernel support
==============
Build time configuration
------------------------
Landlock was first introduced in Linux 5.13 but it must be configured at build
time with ``CONFIG_SECURITY_LANDLOCK=y``. Landlock must also be enabled at boot
time like other security modules. The list of security modules enabled by
default is set with ``CONFIG_LSM``. The kernel configuration should then
contain ``CONFIG_LSM=landlock,[...]`` with ``[...]`` as the list of other
potentially useful security modules for the running system (see the
``CONFIG_LSM`` help).
Boot time configuration
-----------------------
If the running kernel does not have ``landlock`` in ``CONFIG_LSM``, then we can
enable Landlock by adding ``lsm=landlock,[...]`` to
Documentation/admin-guide/kernel-parameters.rst in the boot loader
configuration.
For example, if the current built-in configuration is:
.. code-block:: console
$ zgrep -h "^CONFIG_LSM=" "/boot/config-$(uname -r)" /proc/config.gz 2>/dev/null
CONFIG_LSM="lockdown,yama,integrity,apparmor"
...and if the cmdline doesn't contain ``landlock`` either:
.. code-block:: console
$ sed -n 's/.*\(\<lsm=\S\+\).*/\1/p' /proc/cmdline
lsm=lockdown,yama,integrity,apparmor
...we should configure the boot loader to set a cmdline extending the ``lsm``
list with the ``landlock,`` prefix::
lsm=landlock,lockdown,yama,integrity,apparmor
After a reboot, we can check that Landlock is up and running by looking at
kernel logs:
.. code-block:: console
# dmesg | grep landlock || journalctl -kb -g landlock
[ 0.000000] Command line: [...] lsm=landlock,lockdown,yama,integrity,apparmor
[ 0.000000] Kernel command line: [...] lsm=landlock,lockdown,yama,integrity,apparmor
[ 0.000000] LSM: initializing lsm=lockdown,capability,landlock,yama,integrity,apparmor
[ 0.000000] landlock: Up and running.
The kernel may be configured at build time to always load the ``lockdown`` and
``capability`` LSMs. In that case, these LSMs will appear at the beginning of
the ``LSM: initializing`` log line as well, even if they are not configured in
the boot loader.
Network support
---------------
To be able to explicitly allow TCP operations (e.g., adding a network rule with
``LANDLOCK_ACCESS_NET_BIND_TCP``), the kernel must support TCP
(``CONFIG_INET=y``). Otherwise, sys_landlock_add_rule() returns an
``EAFNOSUPPORT`` error, which can safely be ignored because this kind of TCP
operation is already not possible.
Questions and answers
=====================
What about user space sandbox managers?
---------------------------------------
Using user space processes to enforce restrictions on kernel resources can lead
to race conditions or inconsistent evaluations (i.e. `Incorrect mirroring of
the OS code and state
<https://www.ndss-symposium.org/ndss2003/traps-and-pitfalls-practical-problems-system-call-interposition-based-security-tools/>`_).
What about namespaces and containers?
-------------------------------------
Namespaces can help create sandboxes but they are not designed for
access-control and then miss useful features for such use case (e.g. no
fine-grained restrictions). Moreover, their complexity can lead to security
issues, especially when untrusted processes can manipulate them (cf.
`Controlling access to user namespaces <https://lwn.net/Articles/673597/>`_).
How to disable Landlock audit records?
--------------------------------------
You might want to put in place filters as explained here:
Documentation/admin-guide/LSM/landlock.rst
Additional documentation
========================
* Documentation/admin-guide/LSM/landlock.rst
* Documentation/security/landlock.rst
* https://landlock.io
.. Links
.. _samples/landlock/sandboxer.c:
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/samples/landlock/sandboxer.c
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
개요와 지원 확인
1-27이 문서는 GPL-2.0 라이선스로 제공되며 Mickaël Salaün, ANSSI, Microsoft Corporation의 저작권 고지를 포함합니다. 저자는 Mickaël Salaün이고 문서 날짜는 2025년 3월입니다.
Landlock의 목표는 여러 프로세스가 가진 주변 권한, 예를 들어 전역 파일시스템 또는 네트워크 접근을 제한할 수 있게 하는 것입니다. Landlock은 다른 LSM과 함께 쌓을 수 있는 stackable LSM이므로 기존 시스템 전역 접근 제어 위에 새 보안 계층으로 안전한 sandbox를 만들 수 있습니다.
이 sandbox는 사용자 공간 응용 프로그램의 버그나 예상하지 못한 동작, 악의적 동작이 미치는 보안 영향을 줄이기 위한 것입니다. 권한 없는 프로세스를 포함한 어떤 프로세스든 자신의 권한을 안전하게 제한할 수 있습니다.
실행 중인 시스템에서는 root로 `dmesg | grep landlock || journalctl -kb -g landlock`를 실행해 kernel log에 `landlock: Up and running`이 있는지 확인할 수 있습니다. 개발자는 `landlock_create_ruleset()`을 이용한 ABI 조회로도 지원 여부를 확인할 수 있으며, 지원되지 않으면 뒤의 kernel 설정 절차를 따라야 합니다.
기존 접근 제어를 대체하지 않고 프로세스가 스스로 추가 제한을 쌓는 구조입니다.
.. SPDX-License-Identifier: GPL-2.0
.. Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
.. Copyright © 2019-2020 ANSSI
.. Copyright © 2021-2022 Microsoft Corporation
=====================================
Landlock: unprivileged access control
=====================================
:Author: Mickaël Salaün
:Date: March 2025
The goal of Landlock is to enable restriction of ambient rights (e.g. global
filesystem or network access) for a set of processes. Because Landlock
is a stackable LSM, it makes it possible to create safe security sandboxes as
new security layers in addition to the existing system-wide access-controls.
This kind of sandbox is expected to help mitigate the security impact of bugs or
unexpected/malicious behaviors in user space applications. Landlock empowers
any process, including unprivileged ones, to securely restrict themselves.
We can quickly make sure that Landlock is enabled in the running system by
looking for "landlock: Up and running" in kernel logs (as root):
``dmesg | grep landlock || journalctl -kb -g landlock`` .
Developers can also easily check for Landlock support with a
:ref:`related system call <landlock_abi_versions>`.
If Landlock is not currently supported, we need to
:ref:`configure the kernel appropriately <kernel_support>`.
규칙 유형과 정책 모델
28-60Landlock 규칙은 프로세스가 어떤 객체에 수행하려는 동작을 기술합니다. 여러 규칙은 ruleset으로 모이며, 이 ruleset은 이를 강제한 thread와 이후 생성되는 자식들을 제한합니다.
현재 규칙 유형은 두 가지입니다. Filesystem 규칙의 객체는 파일 계층이고 동작은 filesystem access right로 표현합니다. ABI v4부터 제공되는 network 규칙의 객체는 TCP port이며 동작은 network access right로 표현합니다.
예제 정책은 파일시스템 읽기와 특정 TCP 연결만 허용합니다. 파일시스템 쓰기와 그 밖의 TCP 동작은 거부합니다.
ruleset은 제한하려는 파일시스템 동작과 네트워크 동작을 모두 명시적으로 처리해야 합니다. kernel과 사용자 공간이 서로 어느 제한을 지원하는지 모를 수 있으므로, 하위·상위 호환성을 위해 기본 거부할 access right를 명시하는 계약이 필요합니다.
규칙의 객체와 권한 집합을 구분합니다.
처리할 권한을 선언한 뒤 예외 규칙을 추가하고 현재 thread에 강제합니다.
Landlock rules
==============
A Landlock rule describes an action on an object which the process intends to
perform. A set of rules is aggregated in a ruleset, which can then restrict
the thread enforcing it, and its future children.
The two existing types of rules are:
Filesystem rules
For these rules, the object is a file hierarchy,
and the related filesystem actions are defined with
`filesystem access rights`.
Network rules (since ABI v4)
For these rules, the object is a TCP port,
and the related actions are defined with `network access rights`.
Defining and enforcing a security policy
----------------------------------------
We first need to define the ruleset that will contain our rules.
For this example, the ruleset will contain rules that only allow filesystem
read actions and establish a specific TCP connection. Filesystem write
actions and other TCP actions will be denied.
The ruleset then needs to handle both these kinds of actions. This is
required for backward and forward compatibility (i.e. the kernel and user
space may not know each other's supported restrictions), hence the need
to be explicit about the denied-by-default access rights.
처리 권한 선언과 ABI별 필터링
61-131`struct landlock_ruleset_attr`의 `handled_access_fs`에는 실행, 파일 쓰기·읽기, 디렉터리 읽기, 디렉터리·파일 제거, 여러 inode 유형 생성, 참조, truncate, device ioctl 권한을 넣습니다.
`handled_access_net`에는 `LANDLOCK_ACCESS_NET_BIND_TCP`와 `LANDLOCK_ACCESS_NET_CONNECT_TCP`를 넣고, `scoped`에는 `LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET`과 `LANDLOCK_SCOPE_SIGNAL`을 넣습니다. 이는 규칙으로 허용하지 않은 해당 동작을 기본 거부하겠다는 선언입니다.
응용 프로그램이 어느 kernel version에서 실행될지 알 수 없으므로 best-effort 보안을 따르는 편이 안전합니다. 사용 중인 kernel에서 가능한 기능만 사용하되, 가능한 범위에서는 사용자를 최대한 보호해야 합니다.
`landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION)`으로 ABI version을 조회합니다. Landlock을 처리할 수 없으면 예제는 오류를 알리고 제한 없이 정상 종료하는 방식으로 기능을 점진적으로 낮춥니다.
ABI 1에서는 ABI 2부터 생긴 `LANDLOCK_ACCESS_FS_REFER`를 제거하고, ABI 2에서는 ABI 3부터 생긴 `LANDLOCK_ACCESS_FS_TRUNCATE`를 제거합니다. ABI 3에서는 ABI 4부터 생긴 TCP bind·connect 권한을 제거합니다.
ABI 4에서는 ABI 5부터 생긴 `LANDLOCK_ACCESS_FS_IOCTL_DEV`를 제거하고, ABI 5에서는 ABI 6부터 생긴 두 `LANDLOCK_SCOPE_*` bit를 제거합니다. `switch`의 의도적인 fallthrough는 현재 ABI보다 나중에 추가된 기능을 모두 제거합니다.
조회한 ABI가 오래될수록 이후 ABI에서 추가된 bit를 ruleset attribute에서 제거합니다.
새 사용자 공간이 오래된 kernel에서도 지원되는 보호를 포기하지 않도록 구성합니다.
.. code-block:: c
struct landlock_ruleset_attr ruleset_attr = {
.handled_access_fs =
LANDLOCK_ACCESS_FS_EXECUTE |
LANDLOCK_ACCESS_FS_WRITE_FILE |
LANDLOCK_ACCESS_FS_READ_FILE |
LANDLOCK_ACCESS_FS_READ_DIR |
LANDLOCK_ACCESS_FS_REMOVE_DIR |
LANDLOCK_ACCESS_FS_REMOVE_FILE |
LANDLOCK_ACCESS_FS_MAKE_CHAR |
LANDLOCK_ACCESS_FS_MAKE_DIR |
LANDLOCK_ACCESS_FS_MAKE_REG |
LANDLOCK_ACCESS_FS_MAKE_SOCK |
LANDLOCK_ACCESS_FS_MAKE_FIFO |
LANDLOCK_ACCESS_FS_MAKE_BLOCK |
LANDLOCK_ACCESS_FS_MAKE_SYM |
LANDLOCK_ACCESS_FS_REFER |
LANDLOCK_ACCESS_FS_TRUNCATE |
LANDLOCK_ACCESS_FS_IOCTL_DEV,
.handled_access_net =
LANDLOCK_ACCESS_NET_BIND_TCP |
LANDLOCK_ACCESS_NET_CONNECT_TCP,
.scoped =
LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET |
LANDLOCK_SCOPE_SIGNAL,
};
Because we may not know which kernel version an application will be executed
on, it is safer to follow a best-effort security approach. Indeed, we
should try to protect users as much as possible whatever the kernel they are
using.
To be compatible with older Linux versions, we detect the available Landlock ABI
version, and only use the available subset of access rights:
.. code-block:: c
int abi;
abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
if (abi < 0) {
/* Degrades gracefully if Landlock is not handled. */
perror("The running kernel does not enable to use Landlock");
return 0;
}
switch (abi) {
case 1:
/* Removes LANDLOCK_ACCESS_FS_REFER for ABI < 2 */
ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER;
__attribute__((fallthrough));
case 2:
/* Removes LANDLOCK_ACCESS_FS_TRUNCATE for ABI < 3 */
ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE;
__attribute__((fallthrough));
case 3:
/* Removes network support for ABI < 4 */
ruleset_attr.handled_access_net &=
~(LANDLOCK_ACCESS_NET_BIND_TCP |
LANDLOCK_ACCESS_NET_CONNECT_TCP);
__attribute__((fallthrough));
case 4:
/* Removes LANDLOCK_ACCESS_FS_IOCTL_DEV for ABI < 5 */
ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_IOCTL_DEV;
__attribute__((fallthrough));
case 5:
/* Removes LANDLOCK_SCOPE_* for ABI < 6 */
ruleset_attr.scoped &= ~(LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET |
LANDLOCK_SCOPE_SIGNAL);
}
ruleset 생성과 파일 계층 규칙
132-180ABI에 맞게 정리한 attribute를 `landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0)`에 넘겨 포괄적인 ruleset을 만들고 `ruleset_fd`를 받습니다. 실패하면 정책을 강제할 수 없으므로 오류로 종료합니다.
반환된 file descriptor가 ruleset을 가리키므로 이제 규칙을 추가할 수 있습니다. 예제의 첫 규칙은 `/usr` 파일 계층에 대한 읽기만 허용합니다. 다른 규칙이 없다면 handled set에 포함된 쓰기 동작은 거부됩니다.
`struct landlock_path_beneath_attr`의 `allowed_access`에는 `LANDLOCK_ACCESS_FS_EXECUTE`, `LANDLOCK_ACCESS_FS_READ_FILE`, `LANDLOCK_ACCESS_FS_READ_DIR`을 설정합니다.
`/usr`는 `O_PATH | O_CLOEXEC`로 열어 `parent_fd`에 저장합니다. 이 descriptor와 `LANDLOCK_RULE_PATH_BENEATH`를 `landlock_add_rule()`에 전달한 뒤 `parent_fd`를 닫습니다. 규칙 추가 실패 시 ruleset descriptor도 닫고 종료합니다.
규칙의 `allowed_access` 역시 ruleset 생성 때와 같은 방식으로 Landlock ABI에 따라 걸러야 할 수 있습니다. 하지만 이 예제에서 요청한 세 filesystem 권한은 모두 ABI 1부터 있으므로 별도 필터링이 필요하지 않습니다.
`/usr` 읽기 허용 규칙의 핵심 값입니다.
경로 descriptor는 규칙 추가가 끝난 직후 닫아도 됩니다.
This enables the creation of an inclusive ruleset that will contain our rules.
.. code-block:: c
int ruleset_fd;
ruleset_fd = landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
if (ruleset_fd < 0) {
perror("Failed to create a ruleset");
return 1;
}
We can now add a new rule to this ruleset thanks to the returned file
descriptor referring to this ruleset. The rule will only allow reading the
file hierarchy ``/usr``. Without another rule, write actions would then be
denied by the ruleset. To add ``/usr`` to the ruleset, we open it with the
``O_PATH`` flag and fill the &struct landlock_path_beneath_attr with this file
descriptor.
.. code-block:: c
int err;
struct landlock_path_beneath_attr path_beneath = {
.allowed_access =
LANDLOCK_ACCESS_FS_EXECUTE |
LANDLOCK_ACCESS_FS_READ_FILE |
LANDLOCK_ACCESS_FS_READ_DIR,
};
path_beneath.parent_fd = open("/usr", O_PATH | O_CLOEXEC);
if (path_beneath.parent_fd < 0) {
perror("Failed to open file");
close(ruleset_fd);
return 1;
}
err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
&path_beneath, 0);
close(path_beneath.parent_fd);
if (err) {
perror("Failed to update ruleset");
close(ruleset_fd);
return 1;
}
It may also be required to create rules following the same logic as explained
for the ruleset creation, by filtering access rights according to the Landlock
ABI version. In this example, this is not required because all of the requested
``allowed_access`` rights are already available in ABI 1.
네트워크 규칙과 정책 강제
181-226네트워크 접근 제어에서는 특정 동작에 사용할 port 번호를 허용하는 규칙을 추가할 수 있습니다. 예제는 HTTPS 연결을 허용합니다.
`struct landlock_net_port_attr`에 `LANDLOCK_ACCESS_NET_CONNECT_TCP`와 port `443`을 넣고 `LANDLOCK_RULE_NET_PORT` 유형으로 `landlock_add_rule()`을 호출합니다.
이 시점의 ruleset에는 `/usr` 읽기를 허용하면서 그 밖의 handled filesystem 접근을 거부하는 규칙과, HTTPS 연결을 허용하는 규칙이 들어 있습니다.
현재 thread가 SUID binary 등을 통해 더 많은 권한을 얻지 못하도록 먼저 `prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)`을 설정해야 합니다. 실패하면 ruleset descriptor를 닫고 종료합니다.
그 다음 `landlock_restrict_self(ruleset_fd, 0)`을 호출하여 현재 thread를 sandbox에 넣고, 성공 여부와 관계없이 적절한 시점에 `ruleset_fd`를 닫습니다.
호출이 성공하면 정책은 현재 thread와 이후 생성되는 모든 자식에 강제됩니다. Landlock 정책은 제거할 수 없으며 새 제한만 더할 수 있습니다. 새 domain은 기존 parent domain이 있으면 그것과 새 ruleset을 병합한 결과입니다.
전체 동작 예제는 `samples/landlock/sandboxer.c`에서 확인할 수 있습니다.
네트워크 예외를 추가한 뒤 권한 상승을 막고 정책을 적용합니다.
기존 domain과 새 ruleset의 제한이 합쳐진 새 domain으로 이동합니다.
For network access-control, we can add a set of rules that allow to use a port
number for a specific action: HTTPS connections.
.. code-block:: c
struct landlock_net_port_attr net_port = {
.allowed_access = LANDLOCK_ACCESS_NET_CONNECT_TCP,
.port = 443,
};
err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
&net_port, 0);
The next step is to restrict the current thread from gaining more privileges
(e.g. through a SUID binary). We now have a ruleset with the first rule
allowing read access to ``/usr`` while denying all other handled accesses for
the filesystem, and a second rule allowing HTTPS connections.
.. code-block:: c
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
perror("Failed to restrict privileges");
close(ruleset_fd);
return 1;
}
The current thread is now ready to sandbox itself with the ruleset.
.. code-block:: c
if (landlock_restrict_self(ruleset_fd, 0)) {
perror("Failed to enforce ruleset");
close(ruleset_fd);
return 1;
}
close(ruleset_fd);
If the ``landlock_restrict_self`` system call succeeds, the current thread is
now restricted and this policy will be enforced on all its subsequently created
children as well. Once a thread is landlocked, there is no way to remove its
security policy; only adding more restrictions is allowed. These threads are
now in a new Landlock domain, which is a merger of their parent one (if any)
with the new ruleset.
Full working code can be found in `samples/landlock/sandboxer.c`_.
파일 계층 설계 모범 사례
227-249가능한 한 파일 계층의 leaf에 access right를 설정하는 것이 좋습니다. 예를 들어 `~/` 전체를 read-only로 두고 `~/tmp/`만 read-write로 두기보다 `~/doc/`을 read-only, `~/tmp/`를 read-write로 각각 설정하는 편이 낫습니다.
이 방식은 상위 디렉터리 위치에 의존하지 않는 자급적인 계층을 만듭니다. 특히 link나 rename을 허용할 때 디렉터리별 권한이 일관되면, 작업 자체에 필요한 권한을 제외하고 destination directory의 우연한 권한에 기대지 않고 디렉터리를 옮길 수 있습니다. 관련 세부 사항은 `LANDLOCK_ACCESS_FS_REFER` 문서를 참조합니다.
자급적인 계층은 필요한 access right를 최소 데이터 집합으로 좁히는 데도 도움이 됩니다.
또한 데이터는 들어올 수 있지만 나갈 수 없는 sinkhole directory를 피하는 데 도움이 됩니다. 다만 실제 데이터 배치는 개발자가 통제하지 못할 수 있습니다.
그런 경우 `~/tmp/`에 write-only가 아니라 read-write를 부여하면, `~/tmp/`가 읽을 수 없는 디렉터리 아래로 옮겨져도 그 내용을 계속 나열할 수 있습니다.
상위 경로보다 실제 데이터 leaf에 독립적인 권한을 부여합니다.
Good practices
--------------
It is recommended to set access rights to file hierarchy leaves as much as
possible. For instance, it is better to be able to have ``~/doc/`` as a
read-only hierarchy and ``~/tmp/`` as a read-write hierarchy, compared to
``~/`` as a read-only hierarchy and ``~/tmp/`` as a read-write hierarchy.
Following this good practice leads to self-sufficient hierarchies that do not
depend on their location (i.e. parent directories). This is particularly
relevant when we want to allow linking or renaming. Indeed, having consistent
access rights per directory enables changing the location of such directories
without relying on the destination directory access rights (except those that
are required for this operation, see ``LANDLOCK_ACCESS_FS_REFER``
documentation).
Having self-sufficient hierarchies also helps to tighten the required access
rights to the minimal set of data. This also helps avoid sinkhole directories,
i.e. directories where data can be linked to but not linked from. However,
this depends on data organization, which might not be controlled by developers.
In this case, granting read-write access to ``~/tmp/``, instead of write-only
access, would potentially allow moving ``~/tmp/`` to a non-readable directory
and still keep the ability to list the content of ``~/tmp/``.
정책 계층, bind mount와 OverlayFS
250-289thread가 자신에게 ruleset을 강제할 때마다 Landlock domain에 새 정책 계층이 추가됩니다. 이 보완 정책은 이미 thread를 제한하는 다른 ruleset 위에 쌓이므로 sandbox된 thread도 새 ruleset으로 자신을 더 제한할 수 있습니다.
하나의 정책 계층에서는 경로에서 만난 규칙 중 하나 이상이 접근을 허용하면 그 계층이 접근을 허용합니다. 즉 같은 계층의 규칙은 허용 관점에서 합집합처럼 동작합니다.
실제 접근은 강제된 모든 정책 계층이 허용하고, filesystem DAC와 다른 LSM 정책 같은 시스템의 모든 접근 제어도 허용해야 가능합니다. 계층 사이는 교집합처럼 동작합니다.
Landlock은 파일 계층에 접근 권한을 연결합니다. 이 권한은 bind mount에는 전파될 수 있지만 OverlayFS에는 같은 방식으로 전파되지 않습니다.
bind mount는 source 파일 계층을 destination에 그대로 비춥니다. destination은 정확히 같은 파일들로 구성되므로 Landlock 규칙을 source 또는 destination 경로 어느 쪽으로도 연결할 수 있습니다.
규칙은 경로에서 만날 때 접근을 제한하므로 bind mount 결과인지 여부와 무관하게 여러 파일 계층을 동시에 제한할 수 있습니다.
OverlayFS mount point는 upper·lower layer를 merge directory에 결합하고 그 결과를 mount point에 공개합니다. merge 계층의 수정은 upper layer에만 반영됩니다.
Landlock 관점에서 각 OverlayFS layer와 merge hierarchy는 서로 독립적인 파일·디렉터리 집합입니다. layer를 제한해도 merge 결과를 제한하지 않으며 반대도 마찬가지입니다. 사용자는 기반 filesystem 구현보다 실제로 접근을 허용할 파일 계층 각각을 기준으로 정책을 세워야 합니다.
규칙·계층·filesystem 종류에 따라 권한이 결합되는 방식을 구분합니다.
한 계층 안의 허용을 구한 뒤 모든 보안 계층의 결과를 함께 확인합니다.
Layers of file path access rights
---------------------------------
Each time a thread enforces a ruleset on itself, it updates its Landlock domain
with a new layer of policy. This complementary policy is stacked with any
other rulesets potentially already restricting this thread. A sandboxed thread
can then safely add more constraints to itself with a new enforced ruleset.
One policy layer grants access to a file path if at least one of its rules
encountered on the path grants the access. A sandboxed thread can only access
a file path if all its enforced policy layers grant the access as well as all
the other system access controls (e.g. filesystem DAC, other LSM policies,
etc.).
Bind mounts and OverlayFS
-------------------------
Landlock enables restricting access to file hierarchies, which means that these
access rights can be propagated with bind mounts (cf.
Documentation/filesystems/sharedsubtree.rst) but not with
Documentation/filesystems/overlayfs.rst.
A bind mount mirrors a source file hierarchy to a destination. The destination
hierarchy is then composed of the exact same files, on which Landlock rules can
be tied, either via the source or the destination path. These rules restrict
access when they are encountered on a path, which means that they can restrict
access to multiple file hierarchies at the same time, whether these hierarchies
are the result of bind mounts or not.
An OverlayFS mount point consists of upper and lower layers. These layers are
combined in a merge directory, and that merged directory becomes available at
the mount point. This merge hierarchy may include files from the upper and
lower layers, but modifications performed on the merge hierarchy only reflect
on the upper layer. From a Landlock policy point of view, all OverlayFS layers
and merge hierarchies are standalone and each contains their own set of files
and directories, which is different from bind mounts. A policy restricting an
OverlayFS layer will not restrict the resulted merged hierarchy, and vice versa.
Landlock users should then only think about file hierarchies they want to allow
access to, regardless of the underlying filesystem.
상속, ptrace와 IPC 범위
290-346`clone(2)`으로 생긴 새 thread는 parent의 Landlock domain 제한을 상속합니다. 이는 seccomp 또는 task의 `credentials(7)`를 다루는 다른 LSM의 상속과 비슷합니다.
한 process의 특정 thread가 자신에게 Landlock 규칙을 적용해도 sibling thread에는 자동 적용되지 않습니다. 이 점은 POSIX thread credential 변경과 다르며 `nptl(7)`의 설명을 참고해야 합니다.
thread가 자신을 sandbox하면 관련 정책이 그 모든 descendant에 계속 강제됨이 보장됩니다. 따라서 응용 프로그램별 독립적이고 모듈화된 보안 정책을 만들 수 있고, 실행 시점 parent 정책에 따라 자동 조합됩니다.
sandbox process는 sandbox되지 않은 process보다 권한이 적으므로 다른 process를 조작할 때 추가 제한을 받습니다. target에 `ptrace(2)`와 관련 syscall을 사용하려면 tracer가 tracee의 access right를 모두 포함하는 superset이어야 합니다. 다시 말해 tracee가 tracer의 sub-domain에 있어야 합니다.
명시적인 IPC scoping은 sandbox 사이의 상호 작용을 더 줄입니다. ruleset 생성 시 특정 동작의 scope를 제한하면 같은 Landlock domain 또는 nested domain의 process까지만 도달할 수 있습니다.
`LANDLOCK_SCOPE_SIGNAL`은 같은 domain이나 nested domain에서 실행되는 target process에만 signal을 보낼 수 있게 제한합니다.
`LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET`은 같은 domain이나 nested domain의 process가 만든 abstract `unix(7)` socket address에만 `connect(2)`할 수 있게 제한합니다.
연결되지 않은 datagram socket에서 `sendto(2)`를 호출하면 암시적 `connect(2)`처럼 취급하므로 remote endpoint가 같은 domain 또는 nested domain에서 오지 않았다면 차단합니다.
이미 연결된 socket에서 `sendto(2)`를 호출하는 경우에는 제한하지 않습니다. 이 동작은 datagram과 stream socket 모두에 적용됩니다.
IPC scoping에는 `landlock_add_rule(2)`로 예외를 추가할 수 없습니다. domain에서 동작이 scoped되면 scope 밖의 resource나 process를 허용하는 규칙은 만들 수 없습니다.
상속과 대상 domain 관계가 허용 범위를 결정합니다.
동일·하위 domain 방향으로만 scoped 동작을 허용합니다.
Inheritance
-----------
Every new thread resulting from a :manpage:`clone(2)` inherits Landlock domain
restrictions from its parent. This is similar to seccomp inheritance (cf.
Documentation/userspace-api/seccomp_filter.rst) or any other LSM dealing with
task's :manpage:`credentials(7)`. For instance, one process's thread may apply
Landlock rules to itself, but they will not be automatically applied to other
sibling threads (unlike POSIX thread credential changes, cf.
:manpage:`nptl(7)`).
When a thread sandboxes itself, we have the guarantee that the related security
policy will stay enforced on all this thread's descendants. This allows
creating standalone and modular security policies per application, which will
automatically be composed between themselves according to their runtime parent
policies.
Ptrace restrictions
-------------------
A sandboxed process has less privileges than a non-sandboxed process and must
then be subject to additional restrictions when manipulating another process.
To be allowed to use :manpage:`ptrace(2)` and related syscalls on a target
process, a sandboxed process should have a superset of the target process's
access rights, which means the tracee must be in a sub-domain of the tracer.
IPC scoping
-----------
Similar to the implicit `Ptrace restrictions`_, we may want to further restrict
interactions between sandboxes. Therefore, at ruleset creation time, each
Landlock domain can restrict the scope for certain operations, so that these
operations can only reach out to processes within the same Landlock domain or in
a nested Landlock domain (the "scope").
The operations which can be scoped are:
``LANDLOCK_SCOPE_SIGNAL``
This limits the sending of signals to target processes which run within the
same or a nested Landlock domain.
``LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET``
This limits the set of abstract :manpage:`unix(7)` sockets to which we can
:manpage:`connect(2)` to socket addresses which were created by a process in
the same or a nested Landlock domain.
A :manpage:`sendto(2)` on a non-connected datagram socket is treated as if
it were doing an implicit :manpage:`connect(2)` and will be blocked if the
remote end does not stem from the same or a nested Landlock domain.
A :manpage:`sendto(2)` on a socket which was previously connected will not
be restricted. This works for both datagram and stream sockets.
IPC scoping does not support exceptions via :manpage:`landlock_add_rule(2)`.
If an operation is scoped within a domain, no rules can be added to allow access
to resources or processes outside of the scope.
파일 truncate와 file descriptor 권한
347-385`LANDLOCK_ACCESS_FS_WRITE_FILE`과 `LANDLOCK_ACCESS_FS_TRUNCATE`가 다루는 동작은 모두 파일 내용을 바꾸며 직관적이지 않게 겹칠 수 있습니다. 두 권한은 항상 함께 명시하는 것이 권장됩니다.
`creat(2)`는 이름만 보면 파일 생성과 쓰기 권한만 필요할 것 같지만, 같은 이름의 기존 파일이 있으면 truncate 권한도 필요합니다.
반대로 파일 truncate에 `LANDLOCK_ACCESS_FS_WRITE_FILE`이 필요한 것은 아닙니다. `truncate(2)`뿐 아니라 `open(2)`에 `O_RDONLY | O_TRUNC`를 지정해서도 내용을 자를 수 있습니다.
truncate 권한은 열린 파일에 연결됩니다.
파일을 열 때 사용 가능했던 `LANDLOCK_ACCESS_FS_TRUNCATE`와 `LANDLOCK_ACCESS_FS_IOCTL_DEV` 권한은 새 file descriptor에 결합되고, 이후 `ftruncate(2)`와 `ioctl(2)` 시도에 사용됩니다.
이는 파일을 읽기 또는 쓰기로 열 때 `open(2)`에서 권한을 검사하고 이후 `read(2)`·`write(2)`에서는 다시 검사하지 않는 동작과 비슷합니다.
따라서 같은 파일을 가리키는 여러 file descriptor에 Landlock이 서로 다른 동작을 강제할 수 있습니다. ruleset 강제 전과 후에 각각 연 descriptor를 process가 계속 보유하면 이런 상황이 생깁니다.
이 descriptor를 process 사이에 전달해도 Landlock 속성은 유지됩니다. 전달에 참여한 일부 process에 Landlock ruleset이 강제되지 않았더라도 descriptor에 결합된 속성은 그대로 적용됩니다.
path 기준 검사와 descriptor에 결합되는 권한을 함께 구분해야 합니다.
같은 inode라도 open 시점의 domain에 따라 후속 동작이 달라질 수 있습니다.
Truncating files
----------------
The operations covered by ``LANDLOCK_ACCESS_FS_WRITE_FILE`` and
``LANDLOCK_ACCESS_FS_TRUNCATE`` both change the contents of a file and sometimes
overlap in non-intuitive ways. It is recommended to always specify both of
these together.
A particularly surprising example is :manpage:`creat(2)`. The name suggests
that this system call requires the rights to create and write files. However,
it also requires the truncate right if an existing file under the same name is
already present.
It should also be noted that truncating files does not require the
``LANDLOCK_ACCESS_FS_WRITE_FILE`` right. Apart from the :manpage:`truncate(2)`
system call, this can also be done through :manpage:`open(2)` with the flags
``O_RDONLY | O_TRUNC``.
The truncate right is associated with the opened file (see below).
Rights associated with file descriptors
---------------------------------------
When opening a file, the availability of the ``LANDLOCK_ACCESS_FS_TRUNCATE`` and
``LANDLOCK_ACCESS_FS_IOCTL_DEV`` rights is associated with the newly created
file descriptor and will be used for subsequent truncation and ioctl attempts
using :manpage:`ftruncate(2)` and :manpage:`ioctl(2)`. The behavior is similar
to opening a file for reading or writing, where permissions are checked during
:manpage:`open(2)`, but not during the subsequent :manpage:`read(2)` and
:manpage:`write(2)` calls.
As a consequence, it is possible that a process has multiple open file
descriptors referring to the same file, but Landlock enforces different things
when operating with these file descriptors. This can happen when a Landlock
ruleset gets enforced and the process keeps file descriptors which were opened
both before and after the enforcement. It is also possible to pass such file
descriptors between processes, keeping their Landlock properties, even when some
of the involved processes do not have an enforced Landlock ruleset.
하위·상위 호환성과 ABI 조회
386-437Landlock은 과거와 미래 kernel version 모두와 호환되도록 설계되었습니다. syscall attribute와 관련 bitflag, 특히 ruleset의 `handled_access_fs`가 이 계약을 가능하게 합니다.
처리할 access right를 명시하면 kernel과 사용자 공간이 서로 분명한 계약을 맺습니다. 시스템 업데이트만으로 sandbox가 갑자기 더 엄격해져 응용 프로그램이 깨지는 일을 막기 위해 필요한 설계입니다.
개발자는 Landlock mailing list를 구독하여 최신 기능에 맞게 응용 프로그램을 의도적으로 업데이트하고 시험할 수 있습니다.
사용자가 서로 다른 kernel version을 쓸 수 있으므로, runtime에 Landlock ABI version을 확인하고 지원되는 기능만 강제하는 best-effort 보안 방식을 강하게 권장합니다.
`landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION)`으로 ABI를 읽습니다. 실패했을 때 `ENOSYS`는 현재 kernel이 Landlock을 지원하지 않음을, `EOPNOTSUPP`는 현재 비활성화되어 있음을 뜻합니다.
조회가 성공하면 반환값으로 기능을 판별할 수 있습니다. 예를 들어 ABI가 2 이상이면 `LANDLOCK_ACCESS_FS_REFER`를 지원합니다. 첫 ABI가 암시적으로 지원하는 kernel interface와 이후 version부터 지원하는 feature는 이어지는 API 문서에 표시됩니다.
지원되지 않음과 비활성화 상태를 구분합니다.
Compatibility
=============
Backward and forward compatibility
----------------------------------
Landlock is designed to be compatible with past and future versions of the
kernel. This is achieved thanks to the system call attributes and the
associated bitflags, particularly the ruleset's ``handled_access_fs``. Making
handled access rights explicit enables the kernel and user space to have a clear
contract with each other. This is required to make sure sandboxing will not
get stricter with a system update, which could break applications.
Developers can subscribe to the `Landlock mailing list
<https://subspace.kernel.org/lists.linux.dev.html>`_ to knowingly update and
test their applications with the latest available features. In the interest of
users, and because they may use different kernel versions, it is strongly
encouraged to follow a best-effort security approach by checking the Landlock
ABI version at runtime and only enforcing the supported features.
.. _landlock_abi_versions:
Landlock ABI versions
---------------------
The Landlock ABI version can be read with the sys_landlock_create_ruleset()
system call:
.. code-block:: c
int abi;
abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
if (abi < 0) {
switch (errno) {
case ENOSYS:
printf("Landlock is not supported by the current kernel.\n");
break;
case EOPNOTSUPP:
printf("Landlock is currently disabled.\n");
break;
}
return 0;
}
if (abi >= 2) {
printf("Landlock supports LANDLOCK_ACCESS_FS_REFER.\n");
}
The following kernel interfaces are implicitly supported by the first ABI
version. Features only supported from a specific version are explicitly marked
as such.
Kernel interface 문서
438-471이 절은 Landlock kernel interface의 실제 kernel-doc을 소스에서 포함합니다. access right는 `include/uapi/linux/landlock.h`의 `fs_access`, `net_access`, `scope` 식별자에서 생성됩니다.
새 ruleset 생성 syscall 설명은 `security/landlock/syscalls.c`의 `sys_landlock_create_ruleset`에서 가져옵니다.
ruleset attribute 구조체 설명은 `include/uapi/linux/landlock.h`의 `landlock_ruleset_attr`에서 가져옵니다.
ruleset 확장 syscall 설명은 `security/landlock/syscalls.c`의 `sys_landlock_add_rule`에서 가져옵니다.
규칙 유형과 attribute는 `include/uapi/linux/landlock.h`의 `landlock_rule_type`, `landlock_path_beneath_attr`, `landlock_net_port_attr`에서 가져옵니다.
ruleset 강제 syscall 설명은 `security/landlock/syscalls.c`의 `sys_landlock_restrict_self`에서 가져옵니다.
Sphinx가 API 설명을 가져오는 source path와 identifier입니다.
Kernel interface
================
Access rights
-------------
.. kernel-doc:: include/uapi/linux/landlock.h
:identifiers: fs_access net_access scope
Creating a new ruleset
----------------------
.. kernel-doc:: security/landlock/syscalls.c
:identifiers: sys_landlock_create_ruleset
.. kernel-doc:: include/uapi/linux/landlock.h
:identifiers: landlock_ruleset_attr
Extending a ruleset
-------------------
.. kernel-doc:: security/landlock/syscalls.c
:identifiers: sys_landlock_add_rule
.. kernel-doc:: include/uapi/linux/landlock.h
:identifiers: landlock_rule_type landlock_path_beneath_attr
landlock_net_port_attr
Enforcing a ruleset
-------------------
.. kernel-doc:: security/landlock/syscalls.c
:identifiers: sys_landlock_restrict_self
현재 제한: topology, 특수 filesystem과 계층 수
472-506파일시스템 제한으로 sandbox된 thread는 `mount(2)`나 `pivot_root(2)`로 filesystem topology를 바꿀 수 없습니다. 그러나 `chroot(2)` 호출은 거부하지 않습니다.
일반 파일과 디렉터리는 ruleset이 처리하는 access에 따라 제한할 수 있습니다. 하지만 pipe나 socket처럼 사용자에게 보이는 filesystem에서 오지 않으면서 `/proc/<pid>/fd/*`로 접근 가능한 파일은 현재 명시적으로 제한할 수 없습니다.
`/proc/<pid>/ns/*`로 접근하는 nsfs 같은 일부 특수 kernel filesystem도 현재 명시적으로 제한할 수 없습니다.
그럼에도 ptrace 제한 덕분에 민감한 `/proc` 파일 접근은 domain hierarchy에 따라 자동 제한됩니다. 향후에는 전용 ruleset flag로 이런 경로를 명시적으로 제한할 수 있게 될 수 있습니다.
쌓을 수 있는 ruleset 계층은 16개로 제한됩니다. 16개 ruleset을 상속한 task가 보완 ruleset을 하나 더 강제하려 하면 문제가 됩니다.
한도에 도달하면 `sys_landlock_restrict_self()`가 `E2BIG`을 반환합니다.
따라서 thread 생명주기에서 ruleset을 신중하게 한 번 구성하는 것이 강하게 권장됩니다. shell이나 container manager처럼 다른 응용 프로그램을 실행하고 그 응용 프로그램도 자신을 sandbox하려는 환경에서는 특히 중요합니다.
명시적으로 다루지 못하는 객체와 계층 한도를 정리합니다.
Current limitations
===================
Filesystem topology modification
--------------------------------
Threads sandboxed with filesystem restrictions cannot modify filesystem
topology, whether via :manpage:`mount(2)` or :manpage:`pivot_root(2)`.
However, :manpage:`chroot(2)` calls are not denied.
Special filesystems
-------------------
Access to regular files and directories can be restricted by Landlock,
according to the handled accesses of a ruleset. However, files that do not
come from a user-visible filesystem (e.g. pipe, socket), but can still be
accessed through ``/proc/<pid>/fd/*``, cannot currently be explicitly
restricted. Likewise, some special kernel filesystems such as nsfs, which can
be accessed through ``/proc/<pid>/ns/*``, cannot currently be explicitly
restricted. However, thanks to the `ptrace restrictions`_, access to such
sensitive ``/proc`` files are automatically restricted according to domain
hierarchies. Future Landlock evolutions could still enable to explicitly
restrict such paths with dedicated ruleset flags.
Ruleset layers
--------------
There is a limit of 16 layers of stacked rulesets. This can be an issue for a
task willing to enforce a new ruleset in complement to its 16 inherited
rulesets. Once this limit is reached, sys_landlock_restrict_self() returns
E2BIG. It is then strongly suggested to carefully build rulesets once in the
life of a thread, especially for applications able to launch other applications
that may also want to sandbox themselves (e.g. shells, container managers,
etc.).
메모리 계상과 IOCTL 제한
507-534ruleset 생성에 할당된 kernel memory는 계상되며 cgroup v1 memory controller로 제한할 수 있습니다.
`LANDLOCK_ACCESS_FS_IOCTL_DEV`는 `ioctl(2)` 사용을 제한하지만 새로 연 device file에만 적용됩니다. 따라서 stdin, stdout, stderr처럼 이미 존재하던 file descriptor에는 영향을 주지 않습니다.
TTY device는 전통적으로 `TIOCSTI`와 `TIOCLINUX` IOCTL command를 통해 같은 TTY의 다른 process를 제어할 수 있었습니다.
현대 Linux에서는 두 command 모두 `CAP_SYS_ADMIN`을 요구하지만 `TIOCSTI` 동작은 설정에 따라 달라질 수 있습니다.
오래된 시스템에서는 상속된 TTY file descriptor를 닫거나, 가능하다면 `LANDLOCK_ACCESS_FS_IOCTL_DEV` 권한 없이 `/proc/self/fd/*`에서 다시 여는 것이 권장됩니다.
현재 Landlock의 IOCTL 지원은 거친 단위로만 제어하지만 향후 더 세밀해질 수 있습니다.
그때까지 사용자는 정말 필요한 파일에만 `LANDLOCK_ACCESS_FS_IOCTL_DEV`를 허용하여 file hierarchy로 필요한 보증을 세워야 합니다.
이미 열린 descriptor와 새로 연 device file의 차이가 핵심입니다.
Memory usage
------------
Kernel memory allocated to create rulesets is accounted and can be restricted
by the Documentation/admin-guide/cgroup-v1/memory.rst.
IOCTL support
-------------
The ``LANDLOCK_ACCESS_FS_IOCTL_DEV`` right restricts the use of
:manpage:`ioctl(2)`, but it only applies to *newly opened* device files. This
means specifically that pre-existing file descriptors like stdin, stdout and
stderr are unaffected.
Users should be aware that TTY devices have traditionally permitted to control
other processes on the same TTY through the ``TIOCSTI`` and ``TIOCLINUX`` IOCTL
commands. Both of these require ``CAP_SYS_ADMIN`` on modern Linux systems, but
the behavior is configurable for ``TIOCSTI``.
On older systems, it is therefore recommended to close inherited TTY file
descriptors, or to reopen them from ``/proc/self/fd/*`` without the
``LANDLOCK_ACCESS_FS_IOCTL_DEV`` right, if possible.
Landlock's IOCTL support is coarse-grained at the moment, but may become more
fine-grained in the future. Until then, users are advised to establish the
guarantees that they need through the file hierarchy, by only allowing the
``LANDLOCK_ACCESS_FS_IOCTL_DEV`` right on files where it is really required.
이전 ABI의 rename, link와 truncate 제한
535-563Landlock은 권한 없는 접근 제어를 목표로 하므로 여러 규칙의 합성과 nesting을 올바르게 처리해야 합니다. 파일 접근을 제한하는 여러 ruleset 계층은 parent에서 그 hierarchy로 제한이 상속되는 의미도 가집니다.
파일은 hierarchy로 식별하고 제한하므로 한 디렉터리에서 다른 디렉터리로 파일을 이동하거나 link하면 hierarchy 제약을 전파하거나, 사라질 수 있는 제약에 맞추어 동작 자체를 제한해야 합니다.
권한 상승을 막고 구현을 단순하게 유지하기 위해 과거 Landlock은 같은 디렉터리 안에서만 link와 rename을 허용했습니다.
ABI version 2부터 `LANDLOCK_ACCESS_FS_REFER` access right로 rename과 linking을 안전하게 제어할 수 있습니다.
세 번째 ABI 전에는 file truncation을 거부할 수 없어서 ABI 1이나 2만 지원하는 kernel에서는 항상 허용됩니다. ABI version 3부터 `LANDLOCK_ACCESS_FS_TRUNCATE`로 truncate를 안전하게 제어할 수 있습니다.
초기 ABI의 제한과 이를 해소한 access right입니다.
Previous limitations
====================
File renaming and linking (ABI < 2)
-----------------------------------
Because Landlock targets unprivileged access controls, it needs to properly
handle composition of rules. Such property also implies rules nesting.
Properly handling multiple layers of rulesets, each one of them able to
restrict access to files, also implies inheritance of the ruleset restrictions
from a parent to its hierarchy. Because files are identified and restricted by
their hierarchy, moving or linking a file from one directory to another implies
propagation of the hierarchy constraints, or restriction of these actions
according to the potentially lost constraints. To protect against privilege
escalations through renaming or linking, and for the sake of simplicity,
Landlock previously limited linking and renaming to the same directory.
Starting with the Landlock ABI version 2, it is now possible to securely
control renaming and linking thanks to the new ``LANDLOCK_ACCESS_FS_REFER``
access right.
File truncation (ABI < 3)
-------------------------
File truncation could not be denied before the third Landlock ABI, so it is
always allowed when using a kernel that only supports the first or second ABI.
Starting with the Landlock ABI version 3, it is now possible to securely control
truncation thanks to the new ``LANDLOCK_ACCESS_FS_TRUNCATE`` access right.
ABI 4~7에서 추가된 제한
564-606ABI version 4부터 `LANDLOCK_ACCESS_NET_BIND_TCP`와 `LANDLOCK_ACCESS_NET_CONNECT_TCP`로 TCP bind와 connect 동작을 허용된 port 집합으로 제한할 수 있습니다.
다섯 번째 ABI 전에는 IOCTL 동작을 거부할 수 없으므로 더 이른 ABI만 지원하는 kernel에서 `ioctl(2)`은 항상 허용됩니다.
ABI version 5부터 `LANDLOCK_ACCESS_FS_IOCTL_DEV`로 character device와 block device의 `ioctl(2)` 사용을 제한할 수 있습니다.
ABI version 6부터 ruleset attribute의 `scoped`에 `LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET`을 설정하여 abstract `unix(7)` socket 연결을 제한할 수 있습니다.
같은 ABI version 6부터 `LANDLOCK_SCOPE_SIGNAL`을 설정하여 `signal(7)` 전송을 제한할 수 있습니다.
ABI version 7부터 `sys_landlock_restrict_self()`에 flag를 전달하여 Landlock audit event logging을 제어할 수 있습니다.
관련 flag는 `LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF`, `LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON`, `LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF`입니다.
audit의 자세한 내용은 `Documentation/admin-guide/LSM/landlock.rst`를 참조합니다.
각 ABI에서 처음 제어할 수 있게 된 동작입니다.
초기 filesystem 중심 정책이 network, device, IPC, audit 제어로 확장됐습니다.
TCP bind and connect (ABI < 4)
------------------------------
Starting with the Landlock ABI version 4, it is now possible to restrict TCP
bind and connect actions to only a set of allowed ports thanks to the new
``LANDLOCK_ACCESS_NET_BIND_TCP`` and ``LANDLOCK_ACCESS_NET_CONNECT_TCP``
access rights.
Device IOCTL (ABI < 5)
----------------------
IOCTL operations could not be denied before the fifth Landlock ABI, so
:manpage:`ioctl(2)` is always allowed when using a kernel that only supports an
earlier ABI.
Starting with the Landlock ABI version 5, it is possible to restrict the use of
:manpage:`ioctl(2)` on character and block devices using the new
``LANDLOCK_ACCESS_FS_IOCTL_DEV`` right.
Abstract UNIX socket (ABI < 6)
------------------------------
Starting with the Landlock ABI version 6, it is possible to restrict
connections to an abstract :manpage:`unix(7)` socket by setting
``LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET`` to the ``scoped`` ruleset attribute.
Signal (ABI < 6)
----------------
Starting with the Landlock ABI version 6, it is possible to restrict
:manpage:`signal(7)` sending by setting ``LANDLOCK_SCOPE_SIGNAL`` to the
``scoped`` ruleset attribute.
Logging (ABI < 7)
-----------------
Starting with the Landlock ABI version 7, it is possible to control logging of
Landlock audit events with the ``LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF``,
``LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON``, and
``LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF`` flags passed to
sys_landlock_restrict_self(). See Documentation/admin-guide/LSM/landlock.rst
for more details on audit.
Kernel build 설정
607-622Landlock은 Linux 5.13에서 처음 도입됐지만 build 시 `CONFIG_SECURITY_LANDLOCK=y`로 설정해야 합니다.
다른 보안 모듈과 마찬가지로 boot 시에도 활성화되어야 합니다. 기본 활성 보안 모듈 목록은 `CONFIG_LSM`으로 정합니다.
kernel 설정에는 `CONFIG_LSM=landlock,[...]`이 들어 있어야 하며 `[...]`는 실행 시스템에 필요한 다른 보안 모듈 목록입니다.
정확한 구성 의미는 `CONFIG_LSM` help를 참조합니다.
Landlock 코드 포함과 기본 LSM 목록을 모두 설정해야 합니다.
.. _kernel_support:
Kernel support
==============
Build time configuration
------------------------
Landlock was first introduced in Linux 5.13 but it must be configured at build
time with ``CONFIG_SECURITY_LANDLOCK=y``. Landlock must also be enabled at boot
time like other security modules. The list of security modules enabled by
default is set with ``CONFIG_LSM``. The kernel configuration should then
contain ``CONFIG_LSM=landlock,[...]`` with ``[...]`` as the list of other
potentially useful security modules for the running system (see the
``CONFIG_LSM`` help).
Boot 설정과 활성화 확인
623-665실행 중 kernel의 `CONFIG_LSM`에 `landlock`이 없다면 boot loader의 kernel command line에 `lsm=landlock,[...]`을 추가하여 활성화할 수 있습니다.
현재 built-in 설정은 `/boot/config-$(uname -r)` 또는 `/proc/config.gz`에서 `CONFIG_LSM`을 조회해 확인합니다. 원문 예시는 `lockdown,yama,integrity,apparmor`입니다.
`/proc/cmdline`에서 `lsm=` 인자를 추출해 boot command line에도 landlock이 없는지 확인합니다.
두 곳 모두에 없다면 boot loader가 기존 목록 앞에 `landlock,`을 붙여 `lsm=landlock,lockdown,yama,integrity,apparmor`를 전달하도록 설정합니다.
재부팅 뒤 `dmesg | grep landlock || journalctl -kb -g landlock`로 kernel log를 확인합니다.
정상 log에는 command line의 `lsm=landlock,...`, `LSM: initializing ... landlock ...`, 그리고 `landlock: Up and running.`이 나타납니다.
kernel build 설정이 `lockdown`과 `capability` LSM을 항상 load하도록 할 수 있습니다. 이 경우 boot loader에 명시하지 않았더라도 `LSM: initializing` log 앞부분에 이 모듈들이 표시됩니다.
설정 확인부터 재부팅 후 log 검증까지의 순서입니다.
build에 포함된 Landlock을 boot LSM 목록에 넣고 실제 초기화를 검증합니다.
Boot time configuration
-----------------------
If the running kernel does not have ``landlock`` in ``CONFIG_LSM``, then we can
enable Landlock by adding ``lsm=landlock,[...]`` to
Documentation/admin-guide/kernel-parameters.rst in the boot loader
configuration.
For example, if the current built-in configuration is:
.. code-block:: console
$ zgrep -h "^CONFIG_LSM=" "/boot/config-$(uname -r)" /proc/config.gz 2>/dev/null
CONFIG_LSM="lockdown,yama,integrity,apparmor"
...and if the cmdline doesn't contain ``landlock`` either:
.. code-block:: console
$ sed -n 's/.*\(\<lsm=\S\+\).*/\1/p' /proc/cmdline
lsm=lockdown,yama,integrity,apparmor
...we should configure the boot loader to set a cmdline extending the ``lsm``
list with the ``landlock,`` prefix::
lsm=landlock,lockdown,yama,integrity,apparmor
After a reboot, we can check that Landlock is up and running by looking at
kernel logs:
.. code-block:: console
# dmesg | grep landlock || journalctl -kb -g landlock
[ 0.000000] Command line: [...] lsm=landlock,lockdown,yama,integrity,apparmor
[ 0.000000] Kernel command line: [...] lsm=landlock,lockdown,yama,integrity,apparmor
[ 0.000000] LSM: initializing lsm=lockdown,capability,landlock,yama,integrity,apparmor
[ 0.000000] landlock: Up and running.
The kernel may be configured at build time to always load the ``lockdown`` and
``capability`` LSMs. In that case, these LSMs will appear at the beginning of
the ``LSM: initializing`` log line as well, even if they are not configured in
the boot loader.
Kernel network 지원
666-674`LANDLOCK_ACCESS_NET_BIND_TCP` 같은 network 규칙으로 TCP 동작을 명시적으로 허용하려면 kernel이 TCP를 지원해야 하며 `CONFIG_INET=y`가 필요합니다.
TCP를 지원하지 않으면 `sys_landlock_add_rule()`이 `EAFNOSUPPORT`를 반환합니다.
이 오류는 안전하게 무시할 수 있습니다. TCP 자체가 없는 kernel에서는 해당 종류의 TCP 동작이 이미 불가능하기 때문입니다.
TCP 기능이 없을 때의 오류는 보안 저하를 뜻하지 않습니다.
Network support
---------------
To be able to explicitly allow TCP operations (e.g., adding a network rule with
``LANDLOCK_ACCESS_NET_BIND_TCP``), the kernel must support TCP
(``CONFIG_INET=y``). Otherwise, sys_landlock_add_rule() returns an
``EAFNOSUPPORT`` error, which can safely be ignored because this kind of TCP
operation is already not possible.
질문과 답변
675-700사용자 공간 sandbox manager가 kernel resource 제한을 대신 강제하면 race condition이나 일관되지 않은 평가가 생길 수 있습니다. 문서는 syscall interposition 기반 보안 도구가 OS code와 state를 부정확하게 mirror하는 문제를 관련 연구로 연결합니다.
Landlock은 kernel 안에서 실제 객체 접근을 판정하여 이런 사용자 공간 mirror의 구조적 한계를 피합니다.
namespace도 sandbox 구성에 도움이 되지만 access control을 위해 설계된 것은 아니므로 세밀한 제한 같은 유용한 기능이 부족합니다.
또한 namespace의 복잡성은 보안 문제를 낳을 수 있으며 신뢰할 수 없는 process가 이를 조작할 수 있을 때 특히 위험합니다. 사용자 namespace 접근 제어에 관한 LWN 자료가 함께 제시됩니다.
Landlock audit record를 비활성화하거나 줄이려면 `Documentation/admin-guide/LSM/landlock.rst`에서 설명하는 filter를 적용할 수 있습니다.
따라서 Landlock은 namespace나 사용자 공간 manager의 모든 기능을 대체하려는 것이 아니라, kernel 객체에 대한 세밀하고 쌓을 수 있는 자체 제한 계층을 제공합니다.
다른 sandbox 기법의 역할과 주의점을 비교합니다.
Questions and answers
=====================
What about user space sandbox managers?
---------------------------------------
Using user space processes to enforce restrictions on kernel resources can lead
to race conditions or inconsistent evaluations (i.e. `Incorrect mirroring of
the OS code and state
<https://www.ndss-symposium.org/ndss2003/traps-and-pitfalls-practical-problems-system-call-interposition-based-security-tools/>`_).
What about namespaces and containers?
-------------------------------------
Namespaces can help create sandboxes but they are not designed for
access-control and then miss useful features for such use case (e.g. no
fine-grained restrictions). Moreover, their complexity can lead to security
issues, especially when untrusted processes can manipulate them (cf.
`Controlling access to user namespaces <https://lwn.net/Articles/673597/>`_).
How to disable Landlock audit records?
--------------------------------------
You might want to put in place filters as explained here:
Documentation/admin-guide/LSM/landlock.rst
추가 문서와 예제
701-710관리자용 system-wide Landlock와 audit 문서는 `Documentation/admin-guide/LSM/landlock.rst`에 있습니다.
Landlock LSM 내부 설계 문서는 `Documentation/security/landlock.rst`에 있고 프로젝트 사이트는 `https://landlock.io`입니다.
완전한 sandbox 예제 `samples/landlock/sandboxer.c`는 stable Linux 저장소의 해당 source 경로로 연결됩니다.
사용자 API를 넘어 운영·내부 설계·실제 코드를 확인할 수 있습니다.
Additional documentation
========================
* Documentation/admin-guide/LSM/landlock.rst
* Documentation/security/landlock.rst
* https://landlock.io
.. Links
.. _samples/landlock/sandboxer.c:
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/samples/landlock/sandboxer.c
요약·해설
landlock.rst:1-710Landlock은 기존 DAC·LSM 위에 프로세스가 스스로 단조롭게 더 강한 제한을 쌓는 권한 없는 sandbox API입니다. ruleset에서 처리할 권한을 기본 거부로 선언하고 파일 계층·TCP port 허용 규칙을 추가한 뒤 `PR_SET_NO_NEW_PRIVS`와 `landlock_restrict_self()`로 현재 thread와 자식에게 강제합니다.
실무에서는 runtime ABI 조회와 best-effort 기능 선택, leaf 중심 파일 계층 설계, WRITE_FILE·TRUNCATE의 동시 취급, open 시점에 descriptor에 결합되는 TRUNCATE·IOCTL_DEV 권한, bind mount와 OverlayFS의 서로 다른 객체 의미를 함께 고려해야 합니다.
문서는 ABI 1~7의 기능 변화, 최대 16개 ruleset layer, 특수 filesystem·IOCTL의 현재 제한, `CONFIG_SECURITY_LANDLOCK`, `CONFIG_LSM`, boot `lsm=` 설정과 audit 문서까지 포함합니다.