From: "Mickaël Salaün" <mic@digikod.net>
To: Tingmao Wang <m@maowtm.org>
Cc: "Günther Noack" <gnoack@google.com>, "Jan Kara" <jack@suse.cz>,
linux-security-module@vger.kernel.org
Subject: Re: [PATCH v2 3/6] landlock/audit: Check for quiet flag in landlock_log_denial
Date: Wed, 15 Oct 2025 21:09:16 +0200 [thread overview]
Message-ID: <20251015.Iengoh1eeT0c@digikod.net> (raw)
In-Reply-To: <730434d416100f6a72b12fb31eb7253bc8b6fcc0.1759686613.git.m@maowtm.org>
Just use "landlock: " as subject prefix.
On Sun, Oct 05, 2025 at 06:55:26PM +0100, Tingmao Wang wrote:
> Suppresses logging if the flag is effective on the youngest layer.
>
> This does not handle optional access logging yet - to do that correctly we
> will need to expand deny_masks to support representing "don't log
> anything" in a later commit.
>
> Signed-off-by: Tingmao Wang <m@maowtm.org>
> ---
>
> Changes since v1:
> - Supports the new quiet access masks.
> - Support quieting scope requests (but not ptrace and attempted mounting
> for now)
>
> security/landlock/audit.c | 70 +++++++++++++++++++++++++++++++++++--
> security/landlock/audit.h | 3 +-
> security/landlock/fs.c | 18 +++++-----
> security/landlock/net.c | 3 +-
> security/landlock/ruleset.h | 5 +++
> security/landlock/task.c | 12 +++----
> 6 files changed, 92 insertions(+), 19 deletions(-)
>
> diff --git a/security/landlock/audit.c b/security/landlock/audit.c
> index c52d079cdb77..ec00b7dd00c5 100644
> --- a/security/landlock/audit.c
> +++ b/security/landlock/audit.c
> @@ -381,19 +381,39 @@ static bool is_valid_request(const struct landlock_request *const request)
> return true;
> }
>
> +static access_mask_t
> +pick_access_mask_for_req_type(const enum landlock_request_type type,
pick_access_mask_for_request_type
> + const struct access_masks access_masks)
> +{
> + switch (type) {
> + case LANDLOCK_REQUEST_FS_ACCESS:
> + return access_masks.fs;
> + case LANDLOCK_REQUEST_NET_ACCESS:
> + return access_masks.net;
> + default:
> + WARN_ONCE(1, "Invalid request type %d passed to %s", type,
> + __func__);
> + return 0;
> + }
> +}
> +
> /**
> * landlock_log_denial - Create audit records related to a denial
> *
> * @subject: The Landlock subject's credential denying an action.
> * @request: Detail of the user space request.
> + * @rule_flags: The flags for the matched rule, or no_rule_flags (zero) if
> + * this is a scope request (no particular object involved).
> */
> void landlock_log_denial(const struct landlock_cred_security *const subject,
> - const struct landlock_request *const request)
> + const struct landlock_request *const request,
> + const struct collected_rule_flags rule_flags)
> {
> struct audit_buffer *ab;
> struct landlock_hierarchy *youngest_denied;
> size_t youngest_layer;
> - access_mask_t missing;
> + access_mask_t missing, quiet_mask;
> + bool quiet_flag_on_rule = false, quiet_applicable_to_access = false;
>
> if (WARN_ON_ONCE(!subject || !subject->domain ||
> !subject->domain->hierarchy || !request))
> @@ -436,6 +456,52 @@ void landlock_log_denial(const struct landlock_cred_security *const subject,
> if (!audit_enabled)
> return;
>
> + /*
> + * Checks if the object is marked quiet by the layer that denied the
> + * request. If it's a different layer that marked it as quiet, but
> + * that layer is not the one that denied the request, we should still
> + * audit log the denial.
> + */
> + quiet_flag_on_rule = !!(rule_flags.quiet_masks & BIT(youngest_layer));
> +
> + if (quiet_flag_on_rule) {
> + /*
> + * This is not a scope request, since rule_flags is not zero. We
> + * now check if the denied requests are all covered by the layer's
> + * quiet access bits.
> + */
> + quiet_mask = pick_access_mask_for_req_type(
> + request->type, youngest_denied->quiet_masks);
> + quiet_applicable_to_access = (quiet_mask & missing) == missing;
> +
> + if (quiet_applicable_to_access)
> + return;
> + } else {
> + quiet_mask = youngest_denied->quiet_masks.scope;
> + switch (request->type) {
> + case LANDLOCK_REQUEST_SCOPE_SIGNAL:
> + quiet_applicable_to_access =
> + !!(quiet_mask & LANDLOCK_SCOPE_SIGNAL);
> + break;
> + case LANDLOCK_REQUEST_SCOPE_ABSTRACT_UNIX_SOCKET:
> + quiet_applicable_to_access =
> + !!(quiet_mask &
> + LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);
> + break;
> + /*
> + * Leave LANDLOCK_REQUEST_PTRACE and
> + * LANDLOCK_REQUEST_FS_CHANGE_TOPOLOGY unhandled for now - they are
> + * never quiet
> + */
This also covers the case where the object is not quiet.
> + default:
> + break;
> + }
I find this if/else block a bit verbose but I didn't find a better
way...
> +
> + if (quiet_applicable_to_access) {
> + return;
> + }
We can still move this quiet_applicable_to_access check after the block
(and without the curly braces).
> + }
> +
> /* Checks if the current exec was restricting itself. */
> if (subject->domain_exec & BIT(youngest_layer)) {
> /* Ignores denials for the same execution. */
This domain_exec block would be better before the quiet_flag_on_rule
use.
> diff --git a/security/landlock/audit.h b/security/landlock/audit.h
> index 92428b7fc4d8..80cf085465e3 100644
> --- a/security/landlock/audit.h
> +++ b/security/landlock/audit.h
> @@ -56,7 +56,8 @@ struct landlock_request {
> void landlock_log_drop_domain(const struct landlock_hierarchy *const hierarchy);
>
> void landlock_log_denial(const struct landlock_cred_security *const subject,
> - const struct landlock_request *const request);
> + const struct landlock_request *const request,
> + const struct collected_rule_flags rule_flags);
>
> #else /* CONFIG_AUDIT */
>
> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
> index b566ae498df5..1ccef1c2959f 100644
> --- a/security/landlock/fs.c
> +++ b/security/landlock/fs.c
> @@ -984,7 +984,7 @@ static int current_check_access_path(const struct path *const path,
> NULL, 0, NULL, NULL, NULL, NULL))
> return 0;
>
> - landlock_log_denial(subject, &request);
> + landlock_log_denial(subject, &request, rule_flags);
> return -EACCES;
> }
>
> @@ -1194,7 +1194,7 @@ static int current_check_refer_path(struct dentry *const old_dentry,
> &request1, NULL, 0, NULL, NULL, NULL, NULL))
> return 0;
>
> - landlock_log_denial(subject, &request1);
> + landlock_log_denial(subject, &request1, rule_flags_parent1);
> return -EACCES;
> }
>
> @@ -1243,11 +1243,11 @@ static int current_check_refer_path(struct dentry *const old_dentry,
>
> if (request1.access) {
> request1.audit.u.path.dentry = old_parent;
> - landlock_log_denial(subject, &request1);
> + landlock_log_denial(subject, &request1, rule_flags_parent1);
> }
> if (request2.access) {
> request2.audit.u.path.dentry = new_dir->dentry;
> - landlock_log_denial(subject, &request2);
> + landlock_log_denial(subject, &request2, rule_flags_parent2);
> }
>
> /*
> @@ -1403,7 +1403,7 @@ log_fs_change_topology_path(const struct landlock_cred_security *const subject,
> .u.path = *path,
> },
> .layer_plus_one = handle_layer + 1,
> - });
> + }, no_rule_flags);
> }
>
> static void log_fs_change_topology_dentry(
> @@ -1417,7 +1417,7 @@ static void log_fs_change_topology_dentry(
> .u.dentry = dentry,
> },
> .layer_plus_one = handle_layer + 1,
> - });
> + }, no_rule_flags);
> }
>
> /*
> @@ -1705,7 +1705,7 @@ static int hook_file_open(struct file *const file)
>
> /* Sets access to reflect the actual request. */
> request.access = open_access_request;
> - landlock_log_denial(subject, &request);
> + landlock_log_denial(subject, &request, rule_flags);
> return -EACCES;
> }
>
> @@ -1735,7 +1735,7 @@ static int hook_file_truncate(struct file *const file)
> #ifdef CONFIG_AUDIT
> .deny_masks = landlock_file(file)->deny_masks,
> #endif /* CONFIG_AUDIT */
> - });
> + }, no_rule_flags);
> return -EACCES;
> }
>
> @@ -1774,7 +1774,7 @@ static int hook_file_ioctl_common(const struct file *const file,
> #ifdef CONFIG_AUDIT
> .deny_masks = landlock_file(file)->deny_masks,
> #endif /* CONFIG_AUDIT */
> - });
> + }, no_rule_flags);
> return -EACCES;
> }
>
> diff --git a/security/landlock/net.c b/security/landlock/net.c
> index bddbe93d69fd..0587aa3d6d0f 100644
> --- a/security/landlock/net.c
> +++ b/security/landlock/net.c
> @@ -193,7 +193,8 @@ static int current_check_access_socket(struct socket *const sock,
> .access = access_request,
> .layer_masks = &layer_masks,
> .layer_masks_size = ARRAY_SIZE(layer_masks),
> - });
> + },
> + rule_flags);
> return -EACCES;
> }
>
> diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
> index 43d59c7116e5..6f44804c2c9b 100644
> --- a/security/landlock/ruleset.h
> +++ b/security/landlock/ruleset.h
> @@ -58,6 +58,11 @@ struct collected_rule_flags {
> layer_mask_t quiet_masks;
> };
>
> +/**
> + * no_rule_flags - Convenience constant for an empty collected_rule_flags
> + */
> +static const struct collected_rule_flags no_rule_flags = { 0 };
You can remove the "0" for consistency.
> +
> /**
> * union landlock_key - Key of a ruleset's red-black tree
> */
> diff --git a/security/landlock/task.c b/security/landlock/task.c
> index 2385017418ca..d5bd9a1b8467 100644
> --- a/security/landlock/task.c
> +++ b/security/landlock/task.c
> @@ -115,7 +115,7 @@ static int hook_ptrace_access_check(struct task_struct *const child,
> .u.tsk = child,
> },
> .layer_plus_one = parent_subject->domain->num_layers,
> - });
> + }, no_rule_flags);
>
> return err;
> }
> @@ -161,7 +161,7 @@ static int hook_ptrace_traceme(struct task_struct *const parent)
> .u.tsk = current,
> },
> .layer_plus_one = parent_subject->domain->num_layers,
> - });
> + }, no_rule_flags);
> return err;
> }
>
> @@ -290,7 +290,7 @@ static int hook_unix_stream_connect(struct sock *const sock,
> },
> },
> .layer_plus_one = handle_layer + 1,
> - });
> + }, no_rule_flags);
> return -EPERM;
> }
>
> @@ -327,7 +327,7 @@ static int hook_unix_may_send(struct socket *const sock,
> },
> },
> .layer_plus_one = handle_layer + 1,
> - });
> + }, no_rule_flags);
> return -EPERM;
> }
>
> @@ -383,7 +383,7 @@ static int hook_task_kill(struct task_struct *const p,
> .u.tsk = p,
> },
> .layer_plus_one = handle_layer + 1,
> - });
> + }, no_rule_flags);
> return -EPERM;
> }
>
> @@ -426,7 +426,7 @@ static int hook_file_send_sigiotask(struct task_struct *tsk,
> #ifdef CONFIG_AUDIT
> .layer_plus_one = landlock_file(fown->file)->fown_layer + 1,
> #endif /* CONFIG_AUDIT */
> - });
> + }, no_rule_flags);
> return -EPERM;
> }
>
> --
> 2.51.0
>
next prev parent reply other threads:[~2025-10-15 19:09 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-10-05 17:55 [PATCH v2 0/6] Implement LANDLOCK_ADD_RULE_QUIET Tingmao Wang
2025-10-05 17:55 ` [PATCH v2 1/6] landlock: Add a place for flags to layer rules Tingmao Wang
2025-10-15 19:07 ` Mickaël Salaün
2025-10-05 17:55 ` [PATCH v2 2/6] landlock: Add API support and docs for the quiet flags Tingmao Wang
2025-10-15 19:08 ` Mickaël Salaün
2025-10-05 17:55 ` [PATCH v2 3/6] landlock/audit: Check for quiet flag in landlock_log_denial Tingmao Wang
2025-10-15 19:09 ` Mickaël Salaün [this message]
2025-10-19 17:39 ` Tingmao Wang
2025-10-20 20:12 ` Mickaël Salaün
2025-10-26 20:48 ` Tingmao Wang
2025-10-05 17:55 ` [PATCH v2 4/6] landlock/audit: Fix wrong type usage Tingmao Wang
2025-10-05 17:55 ` [PATCH v2 5/6] samples/landlock: Add quiet flag support to sandboxer Tingmao Wang
2025-10-05 17:55 ` [PATCH v2 6/6] Implement quiet for optional accesses Tingmao Wang
2025-10-15 19:09 ` Mickaël Salaün
2025-10-19 17:45 ` Tingmao Wang
2025-10-20 20:11 ` Mickaël Salaün
2025-10-26 20:50 ` Tingmao Wang
2025-10-15 19:06 ` [PATCH v2 0/6] Implement LANDLOCK_ADD_RULE_QUIET Mickaël Salaün
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251015.Iengoh1eeT0c@digikod.net \
--to=mic@digikod.net \
--cc=gnoack@google.com \
--cc=jack@suse.cz \
--cc=linux-security-module@vger.kernel.org \
--cc=m@maowtm.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.