linux-security-module.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
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
> 

  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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).