요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
Event 예제
landlock.rst:73-135Signal scope와 filesystem 접근 거부 log를 serial별로 해설합니다.
Filtering과 문서
landlock.rst:136-158Log noise를 줄이는 방법과 관련 문서를 안내합니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
.. Copyright © 2025 Microsoft Corporation
================================
Landlock: system-wide management
================================
:Author: Mickaël Salaün
:Date: March 2025
Landlock can leverage the audit framework to log events.
User space documentation can be found here:
Documentation/userspace-api/landlock.rst.
Audit
=====
Denied access requests are logged by default for a sandboxed program if `audit`
is enabled. This default behavior can be changed with the
sys_landlock_restrict_self() flags (cf.
Documentation/userspace-api/landlock.rst). Landlock logs can also be masked
thanks to audit rules. Landlock can generate 2 audit record types.
Record types
------------
AUDIT_LANDLOCK_ACCESS
This record type identifies a denied access request to a kernel resource.
The ``domain`` field indicates the ID of the domain that blocked the
request. The ``blockers`` field indicates the cause(s) of this denial
(separated by a comma), and the following fields identify the kernel object
(similar to SELinux). There may be more than one of this record type per
audit event.
Example with a file link request generating two records in the same event::
domain=195ba459b blockers=fs.refer path="/usr/bin" dev="vda2" ino=351
domain=195ba459b blockers=fs.make_reg,fs.refer path="/usr/local" dev="vda2" ino=365
AUDIT_LANDLOCK_DOMAIN
This record type describes the status of a Landlock domain. The ``status``
field can be either ``allocated`` or ``deallocated``.
The ``allocated`` status is part of the same audit event and follows
the first logged ``AUDIT_LANDLOCK_ACCESS`` record of a domain. It identifies
Landlock domain information at the time of the sys_landlock_restrict_self()
call with the following fields:
- the ``domain`` ID
- the enforcement ``mode``
- the domain creator's ``pid``
- the domain creator's ``uid``
- the domain creator's executable path (``exe``)
- the domain creator's command line (``comm``)
Example::
domain=195ba459b status=allocated mode=enforcing pid=300 uid=0 exe="/root/sandboxer" comm="sandboxer"
The ``deallocated`` status is an event on its own and it identifies a
Landlock domain release. After such event, it is guarantee that the
related domain ID will never be reused during the lifetime of the system.
The ``domain`` field indicates the ID of the domain which is released, and
the ``denials`` field indicates the total number of denied access request,
which might not have been logged according to the audit rules and
sys_landlock_restrict_self()'s flags.
Example::
domain=195ba459b status=deallocated denials=3
Event samples
--------------
Here are two examples of log events (see serial numbers).
In this example a sandboxed program (``kill``) tries to send a signal to the
init process, which is denied because of the signal scoping restriction
(``LL_SCOPED=s``)::
$ LL_FS_RO=/ LL_FS_RW=/ LL_SCOPED=s LL_FORCE_LOG=1 ./sandboxer kill 1
This command generates two events, each identified with a unique serial
number following a timestamp (``msg=audit(1729738800.268:30)``). The first
event (serial ``30``) contains 4 records. The first record
(``type=LANDLOCK_ACCESS``) shows an access denied by the domain `1a6fdc66f`.
The cause of this denial is signal scopping restriction
(``blockers=scope.signal``). The process that would have receive this signal
is the init process (``opid=1 ocomm="systemd"``).
The second record (``type=LANDLOCK_DOMAIN``) describes (``status=allocated``)
domain `1a6fdc66f`. This domain was created by process ``286`` executing the
``/root/sandboxer`` program launched by the root user.
The third record (``type=SYSCALL``) describes the syscall, its provided
arguments, its result (``success=no exit=-1``), and the process that called it.
The fourth record (``type=PROCTITLE``) shows the command's name as an
hexadecimal value. This can be translated with ``python -c
'print(bytes.fromhex("6B696C6C0031"))'``.
Finally, the last record (``type=LANDLOCK_DOMAIN``) is also the only one from
the second event (serial ``31``). It is not tied to a direct user space action
but an asynchronous one to free resources tied to a Landlock domain
(``status=deallocated``). This can be useful to know that the following logs
will not concern the domain ``1a6fdc66f`` anymore. This record also summarize
the number of requests this domain denied (``denials=1``), whether they were
logged or not.
.. code-block::
type=LANDLOCK_ACCESS msg=audit(1729738800.268:30): domain=1a6fdc66f blockers=scope.signal opid=1 ocomm="systemd"
type=LANDLOCK_DOMAIN msg=audit(1729738800.268:30): domain=1a6fdc66f status=allocated mode=enforcing pid=286 uid=0 exe="/root/sandboxer" comm="sandboxer"
type=SYSCALL msg=audit(1729738800.268:30): arch=c000003e syscall=62 success=no exit=-1 [..] ppid=272 pid=286 auid=0 uid=0 gid=0 [...] comm="kill" [...]
type=PROCTITLE msg=audit(1729738800.268:30): proctitle=6B696C6C0031
type=LANDLOCK_DOMAIN msg=audit(1729738800.324:31): domain=1a6fdc66f status=deallocated denials=1
Here is another example showcasing filesystem access control::
$ LL_FS_RO=/ LL_FS_RW=/tmp LL_FORCE_LOG=1 ./sandboxer sh -c "echo > /etc/passwd"
The related audit logs contains 8 records from 3 different events (serials 33,
34 and 35) created by the same domain `1a6fdc679`::
type=LANDLOCK_ACCESS msg=audit(1729738800.221:33): domain=1a6fdc679 blockers=fs.write_file path="/dev/tty" dev="devtmpfs" ino=9
type=LANDLOCK_DOMAIN msg=audit(1729738800.221:33): domain=1a6fdc679 status=allocated mode=enforcing pid=289 uid=0 exe="/root/sandboxer" comm="sandboxer"
type=SYSCALL msg=audit(1729738800.221:33): arch=c000003e syscall=257 success=no exit=-13 [...] ppid=272 pid=289 auid=0 uid=0 gid=0 [...] comm="sh" [...]
type=PROCTITLE msg=audit(1729738800.221:33): proctitle=7368002D63006563686F203E202F6574632F706173737764
type=LANDLOCK_ACCESS msg=audit(1729738800.221:34): domain=1a6fdc679 blockers=fs.write_file path="/etc/passwd" dev="vda2" ino=143821
type=SYSCALL msg=audit(1729738800.221:34): arch=c000003e syscall=257 success=no exit=-13 [...] ppid=272 pid=289 auid=0 uid=0 gid=0 [...] comm="sh" [...]
type=PROCTITLE msg=audit(1729738800.221:34): proctitle=7368002D63006563686F203E202F6574632F706173737764
type=LANDLOCK_DOMAIN msg=audit(1729738800.261:35): domain=1a6fdc679 status=deallocated denials=2
Event filtering
---------------
If you get spammed with audit logs related to Landlock, this is either an
attack attempt or a bug in the security policy. We can put in place some
filters to limit noise with two complementary ways:
- with sys_landlock_restrict_self()'s flags if we can fix the sandboxed
programs,
- or with audit rules (see :manpage:`auditctl(8)`).
Additional documentation
========================
* `Linux Audit Documentation`_
* Documentation/userspace-api/landlock.rst
* Documentation/security/landlock.rst
* https://landlock.io
.. Links
.. _Linux Audit Documentation:
https://github.com/linux-audit/audit-documentation/wiki
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
Landlock system-wide 관리
1-15저자는 Mickaël Salaün이며 문서 날짜는 2025년 3월입니다. Landlock은 audit framework를 활용해 event를 기록할 수 있습니다.
Userspace 문서는 `Documentation/userspace-api/landlock.rst`에서 확인할 수 있습니다.
Audit 개요
16-24`audit`가 활성화되어 있으면 sandboxed program에서 거부된 접근 요청은 기본적으로 기록됩니다. 이 기본 동작은 `sys_landlock_restrict_self()` flag로 바꿀 수 있고, audit rule로 Landlock log를 가릴 수도 있습니다.
Landlock은 두 종류의 audit record를 생성할 수 있습니다.
AUDIT_LANDLOCK_ACCESS
25-40`AUDIT_LANDLOCK_ACCESS`는 kernel resource에 대한 거부된 접근 요청을 식별합니다. `domain` field는 요청을 막은 domain ID를 나타내고 `blockers` field는 comma로 구분된 거부 원인을 나타냅니다. 이어지는 field는 SELinux와 비슷하게 kernel object를 식별합니다.
하나의 audit event에 이 record가 여러 개 있을 수 있습니다. File link 요청이 같은 event에서 두 record를 생성하는 예입니다.
domain=195ba459b blockers=fs.refer path="/usr/bin" dev="vda2" ino=351
domain=195ba459b blockers=fs.make_reg,fs.refer path="/usr/local" dev="vda2" ino=365
AUDIT_LANDLOCK_DOMAIN
41-72`AUDIT_LANDLOCK_DOMAIN`은 Landlock domain의 상태를 설명합니다. `status` field는 `allocated` 또는 `deallocated`입니다.
`allocated` status는 같은 domain에서 처음 기록된 `AUDIT_LANDLOCK_ACCESS` record 뒤에 같은 audit event의 일부로 나타납니다. `sys_landlock_restrict_self()` 호출 당시 domain 정보를 식별합니다.
| Field | 설명 |
|---|---|
| domain | Domain ID |
| mode | Enforcement mode |
| pid | Domain creator의 pid |
| uid | Domain creator의 uid |
| exe | Domain creator의 executable path |
| comm | Domain creator의 command line |
domain=195ba459b status=allocated mode=enforcing pid=300 uid=0 exe="/root/sandboxer" comm="sandboxer"
`deallocated` status는 독립 event이며 Landlock domain 해제를 식별합니다. 이 event 뒤에는 관련 domain ID가 시스템 수명 동안 다시 사용되지 않음이 보장됩니다. `domain`은 해제된 ID이고 `denials`는 audit rule과 `sys_landlock_restrict_self()` flag 때문에 기록되지 않았을 수도 있는 요청을 포함한 전체 거부 횟수입니다.
domain=195ba459b status=deallocated denials=3
Signal scope event 해설
73-110다음은 serial number로 구분되는 두 log event의 예입니다.
Sandbox된 `kill` program이 init process에 signal을 보내려고 하지만 signal scoping restriction인 `LL_SCOPED=s` 때문에 거부됩니다.
$ LL_FS_RO=/ LL_FS_RW=/ LL_SCOPED=s LL_FORCE_LOG=1 ./sandboxer kill 1
Command는 timestamp 뒤의 고유 serial number로 식별되는 두 event를 생성합니다. 첫 event(serial `30`)에는 record 네 개가 있습니다.
첫 `type=LANDLOCK_ACCESS` record는 domain `1a6fdc66f`가 접근을 거부했음을 보여 줍니다. 원인은 `blockers=scope.signal`이고 signal을 받을 process는 `opid=1 ocomm="systemd"`인 init process입니다.
두 번째 `type=LANDLOCK_DOMAIN` record는 `status=allocated`인 domain `1a6fdc66f`를 설명합니다. 이 domain은 root user가 실행한 `/root/sandboxer` program을 실행 중인 process `286`이 만들었습니다.
세 번째 `type=SYSCALL` record는 syscall, 제공된 argument, `success=no exit=-1` 결과와 호출 process를 설명합니다. 네 번째 `type=PROCTITLE`은 command 이름을 hexadecimal value로 보여 주며 `python -c 'print(bytes.fromhex("6B696C6C0031"))'`로 변환할 수 있습니다.
마지막 `type=LANDLOCK_DOMAIN` record는 두 번째 event(serial `31`)의 유일한 record입니다. 직접적인 userspace action이 아니라 `status=deallocated`인 domain resource를 비동기로 해제한 결과입니다. 이후 log는 더 이상 domain `1a6fdc66f`와 관련되지 않으며, 기록 여부와 무관하게 이 domain이 거부한 요청 수 `denials=1`도 요약합니다.
Signal scope audit log
111-119위 signal scope 거부에서 생성된 audit record 전체는 다음과 같습니다.
type=LANDLOCK_ACCESS msg=audit(1729738800.268:30): domain=1a6fdc66f blockers=scope.signal opid=1 ocomm="systemd"
type=LANDLOCK_DOMAIN msg=audit(1729738800.268:30): domain=1a6fdc66f status=allocated mode=enforcing pid=286 uid=0 exe="/root/sandboxer" comm="sandboxer"
type=SYSCALL msg=audit(1729738800.268:30): arch=c000003e syscall=62 success=no exit=-1 [..] ppid=272 pid=286 auid=0 uid=0 gid=0 [...] comm="kill" [...]
type=PROCTITLE msg=audit(1729738800.268:30): proctitle=6B696C6C0031
type=LANDLOCK_DOMAIN msg=audit(1729738800.324:31): domain=1a6fdc66f status=deallocated denials=1
Filesystem 접근 제어 event
120-135다음 예는 filesystem 접근 제어를 보여 줍니다.
$ LL_FS_RO=/ LL_FS_RW=/tmp LL_FORCE_LOG=1 ./sandboxer sh -c "echo > /etc/passwd"
관련 audit log에는 같은 domain `1a6fdc679`가 만든 세 event(serial `33`, `34`, `35`)의 record 여덟 개가 있습니다.
type=LANDLOCK_ACCESS msg=audit(1729738800.221:33): domain=1a6fdc679 blockers=fs.write_file path="/dev/tty" dev="devtmpfs" ino=9
type=LANDLOCK_DOMAIN msg=audit(1729738800.221:33): domain=1a6fdc679 status=allocated mode=enforcing pid=289 uid=0 exe="/root/sandboxer" comm="sandboxer"
type=SYSCALL msg=audit(1729738800.221:33): arch=c000003e syscall=257 success=no exit=-13 [...] ppid=272 pid=289 auid=0 uid=0 gid=0 [...] comm="sh" [...]
type=PROCTITLE msg=audit(1729738800.221:33): proctitle=7368002D63006563686F203E202F6574632F706173737764
type=LANDLOCK_ACCESS msg=audit(1729738800.221:34): domain=1a6fdc679 blockers=fs.write_file path="/etc/passwd" dev="vda2" ino=143821
type=SYSCALL msg=audit(1729738800.221:34): arch=c000003e syscall=257 success=no exit=-13 [...] ppid=272 pid=289 auid=0 uid=0 gid=0 [...] comm="sh" [...]
type=PROCTITLE msg=audit(1729738800.221:34): proctitle=7368002D63006563686F203E202F6574632F706173737764
type=LANDLOCK_DOMAIN msg=audit(1729738800.261:35): domain=1a6fdc679 status=deallocated denials=2
Event filtering
136-147Landlock 관련 audit log가 지나치게 많이 발생한다면 공격 시도이거나 security policy의 bug일 수 있습니다. 두 가지 보완적 방법으로 noise를 줄일 수 있습니다.
| 방법 | 적용 조건 |
|---|---|
| `sys_landlock_restrict_self()` flag | Sandboxed program을 수정할 수 있을 때 |
| Audit rule | `auditctl(8)`을 사용해 기록을 filter할 때 |
Audit record
landlock.rst:1-72Landlock이 생성하는 access 및 domain record의 field와 lifecycle을 설명합니다.