summaryrefslogtreecommitdiff
path: root/security/landlock/audit.c
AgeCommit message (Collapse)Author
2025-05-12landlock: Improve bit operations in audit codeMickaël Salaün
Use the BIT() and BIT_ULL() macros in the new audit code instead of explicit shifts to improve readability. Use bitmask instead of modulo operation to simplify code. Add test_range1_rand15() and test_range2_rand15() KUnit tests to improve get_id_range() coverage. Signed-off-by: Günther Noack <gnoack3000@gmail.com> Link: https://lore.kernel.org/r/20250512093732.1408485-1-mic@digikod.net Signed-off-by: Mickaël Salaün <mic@digikod.net>
2025-05-03landlock: Remove KUnit test that triggers a warningMickaël Salaün
A KUnit test checking boundaries triggers a canary warning, which may be disturbing. Let's remove this test for now. Hopefully, KUnit will soon get support for suppressing warning backtraces [1]. Cc: Alessandro Carminati <acarmina@redhat.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Günther Noack <gnoack@google.com> Reported-by: Tingmao Wang <m@maowtm.org> Closes: https://lore.kernel.org/r/20250327213807.12964-1-m@maowtm.org Link: https://lore.kernel.org/r/20250425193249.78b45d2589575c15f483c3d8@linux-foundation.org [1] Link: https://lore.kernel.org/r/20250503065359.3625407-1-mic@digikod.net Signed-off-by: Mickaël Salaün <mic@digikod.net>
2025-03-26landlock: Add LANDLOCK_RESTRICT_SELF_LOG_*_EXEC_* flagsMickaël Salaün
Most of the time we want to log denied access because they should not happen and such information helps diagnose issues. However, when sandboxing processes that we know will try to access denied resources (e.g. unknown, bogus, or malicious binary), we might want to not log related access requests that might fill up logs. By default, denied requests are logged until the task call execve(2). If the LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF flag is set, denied requests will not be logged for the same executed file. If the LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON flag is set, denied requests from after an execve(2) call will be logged. The rationale is that a program should know its own behavior, but not necessarily the behavior of other programs. Because LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF is set for a specific Landlock domain, it makes it possible to selectively mask some access requests that would be logged by a parent domain, which might be handy for unprivileged processes to limit logs. However, system administrators should still use the audit filtering mechanism. There is intentionally no audit nor sysctl configuration to re-enable these logs. This is delegated to the user space program. Increment the Landlock ABI version to reflect this interface change. Cc: Günther Noack <gnoack@google.com> Cc: Paul Moore <paul@paul-moore.com> Link: https://lore.kernel.org/r/20250320190717.2287696-18-mic@digikod.net [mic: Rename variables and fix __maybe_unused] Signed-off-by: Mickaël Salaün <mic@digikod.net>
2025-03-26landlock: Log scoped denialsMickaël Salaün
Add audit support for unix_stream_connect, unix_may_send, task_kill, and file_send_sigiotask hooks. The related blockers are: - scope.abstract_unix_socket - scope.signal Audit event sample for abstract unix socket: type=LANDLOCK_DENY msg=audit(1729738800.268:30): domain=195ba459b blockers=scope.abstract_unix_socket path=00666F6F Audit event sample for signal: type=LANDLOCK_DENY msg=audit(1729738800.291:31): domain=195ba459b blockers=scope.signal opid=1 ocomm="systemd" Refactor and simplify error handling in LSM hooks. Extend struct landlock_file_security with fown_layer and use it to log the blocking domain. The struct aligned size is still 16 bytes. Cc: Günther Noack <gnoack@google.com> Cc: Tahera Fahimi <fahimitahera@gmail.com> Link: https://lore.kernel.org/r/20250320190717.2287696-17-mic@digikod.net Signed-off-by: Mickaël Salaün <mic@digikod.net>
2025-03-26landlock: Log TCP bind and connect denialsMickaël Salaün
Add audit support to socket_bind and socket_connect hooks. The related blockers are: - net.bind_tcp - net.connect_tcp Audit event sample: type=LANDLOCK_DENY msg=audit(1729738800.349:44): domain=195ba459b blockers=net.connect_tcp daddr=127.0.0.1 dest=80 Cc: Günther Noack <gnoack@google.com> Cc: Konstantin Meskhidze <konstantin.meskhidze@huawei.com> Cc: Mikhail Ivanov <ivanov.mikhail1@huawei-partners.com> Link: https://lore.kernel.org/r/20250320190717.2287696-16-mic@digikod.net Signed-off-by: Mickaël Salaün <mic@digikod.net>
2025-03-26landlock: Log truncate and IOCTL denialsMickaël Salaün
Add audit support to the file_truncate and file_ioctl hooks. Add a deny_masks_t type and related helpers to store the domain's layer level per optional access rights (i.e. LANDLOCK_ACCESS_FS_TRUNCATE and LANDLOCK_ACCESS_FS_IOCTL_DEV) when opening a file, which cannot be inferred later. In practice, the landlock_file_security aligned blob size is still 16 bytes because this new one-byte deny_masks field follows the existing two-bytes allowed_access field and precede the packed fown_subject. Implementing deny_masks_t with a bitfield instead of a struct enables a generic implementation to store and extract layer levels. Add KUnit tests to check the identification of a layer level from a deny_masks_t, and the computation of a deny_masks_t from an access right with its layer level or a layer_mask_t array. Audit event sample: type=LANDLOCK_DENY msg=audit(1729738800.349:44): domain=195ba459b blockers=fs.ioctl_dev path="/dev/tty" dev="devtmpfs" ino=9 ioctlcmd=0x5401 Cc: Günther Noack <gnoack@google.com> Link: https://lore.kernel.org/r/20250320190717.2287696-15-mic@digikod.net Signed-off-by: Mickaël Salaün <mic@digikod.net>
2025-03-26landlock: Log file-related denialsMickaël Salaün
Add audit support for path_mkdir, path_mknod, path_symlink, path_unlink, path_rmdir, path_truncate, path_link, path_rename, and file_open hooks. The dedicated blockers are: - fs.execute - fs.write_file - fs.read_file - fs.read_dir - fs.remove_dir - fs.remove_file - fs.make_char - fs.make_dir - fs.make_reg - fs.make_sock - fs.make_fifo - fs.make_block - fs.make_sym - fs.refer - fs.truncate - fs.ioctl_dev Audit event sample for a denied link action: type=LANDLOCK_DENY msg=audit(1729738800.349:44): domain=195ba459b blockers=fs.refer path="/usr/bin" dev="vda2" ino=351 type=LANDLOCK_DENY msg=audit(1729738800.349:44): domain=195ba459b blockers=fs.make_reg,fs.refer path="/usr/local" dev="vda2" ino=365 We could pack blocker names (e.g. "fs:make_reg,refer") but that would increase complexity for the kernel and log parsers. Moreover, this could not handle blockers of different classes (e.g. fs and net). Make it simple and flexible instead. Add KUnit tests to check the identification from a layer_mask_t array of the first layer level denying such request. Cc: Günther Noack <gnoack@google.com> Depends-on: 058518c20920 ("landlock: Align partial refer access checks with final ones") Depends-on: d617f0d72d80 ("landlock: Optimize file path walks and prepare for audit support") Link: https://lore.kernel.org/r/20250320190717.2287696-13-mic@digikod.net Signed-off-by: Mickaël Salaün <mic@digikod.net>
2025-03-26landlock: Log mount-related denialsMickaël Salaün
Add audit support for sb_mount, move_mount, sb_umount, sb_remount, and sb_pivot_root hooks. The new related blocker is "fs.change_topology". Audit event sample: type=LANDLOCK_DENY msg=audit(1729738800.349:44): domain=195ba459b blockers=fs.change_topology name="/" dev="tmpfs" ino=1 Remove landlock_get_applicable_domain() and get_current_fs_domain() which are now fully replaced with landlock_get_applicable_subject(). Cc: Günther Noack <gnoack@google.com> Link: https://lore.kernel.org/r/20250320190717.2287696-12-mic@digikod.net Signed-off-by: Mickaël Salaün <mic@digikod.net>
2025-03-26landlock: Add AUDIT_LANDLOCK_DOMAIN and log domain statusMickaël Salaün
Asynchronously log domain information when it first denies an access. This minimize the amount of generated logs, which makes it possible to always log denials for the current execution since they should not happen. These records are identified with the new AUDIT_LANDLOCK_DOMAIN type. The AUDIT_LANDLOCK_DOMAIN message contains: - the "domain" ID which is described; - the "status" which can either be "allocated" or "deallocated"; - the "mode" which is for now only "enforcing"; - for the "allocated" status, a minimal set of properties to easily identify the task that loaded the domain's policy with landlock_restrict_self(2): "pid", "uid", executable path ("exe"), and command line ("comm"); - for the "deallocated" state, the number of "denials" accounted to this domain, which is at least 1. This requires each domain to save these task properties at creation time in the new struct landlock_details. A reference to the PID is kept for the lifetime of the domain to avoid race conditions when investigating the related task. The executable path is resolved and stored to not keep a reference to the filesystem and block related actions. All these metadata are stored for the lifetime of the related domain and should then be minimal. The required memory is not accounted to the task calling landlock_restrict_self(2) contrary to most other Landlock allocations (see related comment). The AUDIT_LANDLOCK_DOMAIN record follows the first AUDIT_LANDLOCK_ACCESS record for the same domain, which is always followed by AUDIT_SYSCALL and AUDIT_PROCTITLE. This is in line with the audit logic to first record the cause of an event, and then add context with other types of record. Audit event sample for a first denial: type=LANDLOCK_ACCESS msg=audit(1732186800.349:44): domain=195ba459b blockers=ptrace opid=1 ocomm="systemd" type=LANDLOCK_DOMAIN msg=audit(1732186800.349:44): domain=195ba459b status=allocated mode=enforcing pid=300 uid=0 exe="/root/sandboxer" comm="sandboxer" type=SYSCALL msg=audit(1732186800.349:44): arch=c000003e syscall=101 success=no [...] pid=300 auid=0 Audit event sample for a following denial: type=LANDLOCK_ACCESS msg=audit(1732186800.372:45): domain=195ba459b blockers=ptrace opid=1 ocomm="systemd" type=SYSCALL msg=audit(1732186800.372:45): arch=c000003e syscall=101 success=no [...] pid=300 auid=0 Log domain deletion with the "deallocated" state when a domain was previously logged. This makes it possible for log parsers to free potential resources when a domain ID will never show again. The number of denied access requests is useful to easily check how many access requests a domain blocked and potentially if some of them are missing in logs because of audit rate limiting, audit rules, or Landlock log configuration flags (see following commit). Audit event sample for a deletion of a domain that denied something: type=LANDLOCK_DOMAIN msg=audit(1732186800.393:46): domain=195ba459b status=deallocated denials=2 Cc: Günther Noack <gnoack@google.com> Acked-by: Paul Moore <paul@paul-moore.com> Link: https://lore.kernel.org/r/20250320190717.2287696-11-mic@digikod.net [mic: Update comment and GFP flag for landlock_log_drop_domain()] Signed-off-by: Mickaël Salaün <mic@digikod.net>
2025-03-26landlock: Add AUDIT_LANDLOCK_ACCESS and log ptrace denialsMickaël Salaün
Add a new AUDIT_LANDLOCK_ACCESS record type dedicated to an access request denied by a Landlock domain. AUDIT_LANDLOCK_ACCESS indicates that something unexpected happened. For now, only denied access are logged, which means that any AUDIT_LANDLOCK_ACCESS record is always followed by a SYSCALL record with "success=no". However, log parsers should check this syscall property because this is the only sign that a request was denied. Indeed, we could have "success=yes" if Landlock would support a "permissive" mode. We could also add a new field to AUDIT_LANDLOCK_DOMAIN for this mode (see following commit). By default, the only logged access requests are those coming from the same executed program that enforced the Landlock restriction on itself. In other words, no audit record are created for a task after it called execve(2). This is required to avoid log spam because programs may only be aware of their own restrictions, but not the inherited ones. Following commits will allow to conditionally generate AUDIT_LANDLOCK_ACCESS records according to dedicated landlock_restrict_self(2)'s flags. The AUDIT_LANDLOCK_ACCESS message contains: - the "domain" ID restricting the action on an object, - the "blockers" that are missing to allow the requested access, - a set of fields identifying the related object (e.g. task identified with "opid" and "ocomm"). The blockers are implicit restrictions (e.g. ptrace), or explicit access rights (e.g. filesystem), or explicit scopes (e.g. signal). This field contains a list of at least one element, each separated with a comma. The initial blocker is "ptrace", which describe all implicit Landlock restrictions related to ptrace (e.g. deny tracing of tasks outside a sandbox). Add audit support to ptrace_access_check and ptrace_traceme hooks. For the ptrace_access_check case, we log the current/parent domain and the child task. For the ptrace_traceme case, we log the parent domain and the current/child task. Indeed, the requester and the target are the current task, but the action would be performed by the parent task. Audit event sample: type=LANDLOCK_ACCESS msg=audit(1729738800.349:44): domain=195ba459b blockers=ptrace opid=1 ocomm="systemd" type=SYSCALL msg=audit(1729738800.349:44): arch=c000003e syscall=101 success=no [...] pid=300 auid=0 A following commit adds user documentation. Add KUnit tests to check reading of domain ID relative to layer level. The quick return for non-landlocked tasks is moved from task_ptrace() to each LSM hooks. It is not useful to inline the audit_enabled check because other computation are performed by landlock_log_denial(). Use scoped guards for RCU read-side critical sections. Cc: Günther Noack <gnoack@google.com> Acked-by: Paul Moore <paul@paul-moore.com> Link: https://lore.kernel.org/r/20250320190717.2287696-10-mic@digikod.net Signed-off-by: Mickaël Salaün <mic@digikod.net>