Linux Security Modules development
 help / color / mirror / Atom feed
From: Justin Suess <utilityemal77@gmail.com>
To: Tingmao Wang <m@maowtm.org>
Cc: "Mickaël Salaün" <mic@digikod.net>,
	"Günther Noack" <gnoack3000@gmail.com>, "Jan Kara" <jack@suse.cz>,
	"Abhinav Saxena" <xandfury@gmail.com>,
	linux-security-module@vger.kernel.org
Subject: Re: [PATCH v9 4/9] samples/landlock: Add quiet flag support to sandboxer
Date: Thu, 28 May 2026 22:34:55 -0400	[thread overview]
Message-ID: <ahj6gwXIbb58VFsZ@zenbox> (raw)
In-Reply-To: <7d5ad9631a51df6c2b857ff9c0122ff8ed491b7d.1779843375.git.m@maowtm.org>

On Wed, May 27, 2026 at 02:01:14AM +0100, Tingmao Wang wrote:
> Adds ability to set which access bits to quiet via LL_*_QUIET_ACCESS (FS,
> NET or SCOPED), and attach quiet flags to individual objects via
> LL_*_QUIET for FS and NET.
> 
> Signed-off-by: Tingmao Wang <m@maowtm.org>
> ---
> 
> Changes in v9:
> - Add udp connect / bind quiet flag support
> 
> Changes in v8:
> - Rebase on top of mic/next
> - populate_ruleset_net() already does not require the env var to be
>   present, so remove redundant comment and check above
>   populate_ruleset_net(ENV_NET_QUIET_NAME, ...).
> 
> Changes in v6:
> - Make populate_ruleset_{fs,net} take a flags argument instead of a bool
>   quiet (suggested by Justin Suess)
> - Fix if braces style
> 
> Changes in v3:
> - Minor change to the above commit message.
> 
> Changes in v2:
> - Added new environment variables to control which quiet access bits to
>   set on the rule, and populate quiet_access_* from it.
> - Added support for quieting net rules and scoped access.  Renamed patch
>   title.
> - Increment ABI version
> 
>  samples/landlock/sandboxer.c | 134 ++++++++++++++++++++++++++++++++---
>  1 file changed, 123 insertions(+), 11 deletions(-)
> 
> diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c
> index 94e399e6b146..74ee53afed6a 100644
> --- a/samples/landlock/sandboxer.c
> +++ b/samples/landlock/sandboxer.c
> @@ -58,9 +58,14 @@ static inline int landlock_restrict_self(const int ruleset_fd,
>  
>  #define ENV_FS_RO_NAME "LL_FS_RO"
>  #define ENV_FS_RW_NAME "LL_FS_RW"
> +#define ENV_FS_QUIET_NAME "LL_FS_QUIET"
> +#define ENV_FS_QUIET_ACCESS_NAME "LL_FS_QUIET_ACCESS"
>  #define ENV_TCP_BIND_NAME "LL_TCP_BIND"
>  #define ENV_TCP_CONNECT_NAME "LL_TCP_CONNECT"
> +#define ENV_NET_QUIET_NAME "LL_NET_QUIET"
> +#define ENV_NET_QUIET_ACCESS_NAME "LL_NET_QUIET_ACCESS"
>  #define ENV_SCOPED_NAME "LL_SCOPED"
> +#define ENV_SCOPED_QUIET_ACCESS_NAME "LL_SCOPED_QUIET_ACCESS"
>  #define ENV_FORCE_LOG_NAME "LL_FORCE_LOG"
>  #define ENV_UDP_BIND_NAME "LL_UDP_BIND"
>  #define ENV_UDP_CONNECT_SEND_NAME "LL_UDP_CONNECT_SEND"
> @@ -119,7 +124,7 @@ static int parse_path(char *env_path, const char ***const path_list)
>  /* clang-format on */
>  
>  static int populate_ruleset_fs(const char *const env_var, const int ruleset_fd,
> -			       const __u64 allowed_access)
> +			       const __u64 allowed_access, __u32 flags)
>  {
>  	int num_paths, i, ret = 1;
>  	char *env_path_name;
> @@ -169,7 +174,7 @@ static int populate_ruleset_fs(const char *const env_var, const int ruleset_fd,
>  		if (!S_ISDIR(statbuf.st_mode))
>  			path_beneath.allowed_access &= ACCESS_FILE;
>  		if (landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
> -				      &path_beneath, 0)) {
> +				      &path_beneath, flags)) {
>  			fprintf(stderr,
>  				"Failed to update the ruleset with \"%s\": %s\n",
>  				path_list[i], strerror(errno));
> @@ -187,7 +192,7 @@ static int populate_ruleset_fs(const char *const env_var, const int ruleset_fd,
>  }
>  
>  static int populate_ruleset_net(const char *const env_var, const int ruleset_fd,
> -				const __u64 allowed_access)
> +				const __u64 allowed_access, __u32 flags)
>  {
>  	int ret = 1;
>  	char *env_port_name, *env_port_name_next, *strport;
> @@ -215,7 +220,7 @@ static int populate_ruleset_net(const char *const env_var, const int ruleset_fd,
>  		}
>  		net_port.port = port;
>  		if (landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
> -				      &net_port, 0)) {
> +				      &net_port, flags)) {
>  			fprintf(stderr,
>  				"Failed to update the ruleset with port \"%llu\": %s\n",
>  				net_port.port, strerror(errno));
> @@ -303,6 +308,58 @@ static bool check_ruleset_scope(const char *const env_var,
>  
>  /* clang-format on */
>  
> +static int add_quiet_access(__u64 *const quiet_access,
> +			    const __u64 handled_access,
> +			    const char *const env_var, const bool default_all)
> +{
> +	char *env_quiet_access, *env_quiet_access_next, *str_access;
> +
> +	if (default_all)
> +		*quiet_access = handled_access;
> +	else
> +		*quiet_access = 0;
> +
> +	env_quiet_access = getenv(env_var);
> +	if (!env_quiet_access)
> +		return 0;
> +
> +	env_quiet_access = strdup(env_quiet_access);
> +	env_quiet_access_next = env_quiet_access;
> +	unsetenv(env_var);
> +	*quiet_access = 0;
> +
> +	while ((str_access = strsep(&env_quiet_access_next, ENV_DELIMITER))) {
> +		if (strcmp(str_access, "") == 0)
> +			continue;
> +		else if (strcmp(str_access, "r") == 0)
> +			*quiet_access |= ACCESS_FS_ROUGHLY_READ;
> +		else if (strcmp(str_access, "w") == 0)
> +			*quiet_access |= ACCESS_FS_ROUGHLY_WRITE;
> +		else if (strcmp(str_access, "b") == 0)
> +			*quiet_access |= LANDLOCK_ACCESS_NET_BIND_TCP;
> +		else if (strcmp(str_access, "c") == 0)
> +			*quiet_access |= LANDLOCK_ACCESS_NET_CONNECT_TCP;
> +		else if (strcmp(str_access, "ub") == 0)
> +			*quiet_access |= LANDLOCK_ACCESS_NET_BIND_UDP;
> +		else if (strcmp(str_access, "uc") == 0)
> +			*quiet_access |= LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP;
> +		else if (strcmp(str_access, "a") == 0)
> +			*quiet_access |= LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET;
> +		else if (strcmp(str_access, "s") == 0)
> +			*quiet_access |= LANDLOCK_SCOPE_SIGNAL;
You don't need to do it in this patch but these strings should probably
be centrally defined somewhere... as we add more they could be easy to
mix up.
> +		else {
> +			fprintf(stderr, "Unknown quiet access \"%s\"\n",
> +				str_access);
> +			free(env_quiet_access);
> +			return -1;
> +		}
> +	}
> +
> +	free(env_quiet_access);
> +	*quiet_access &= handled_access;
> +	return 0;
> +}
> +
>  #define LANDLOCK_ABI_LAST 10
>  
>  #define XSTR(s) #s
> @@ -336,6 +393,22 @@ static const char help[] =
>  	"\n"
>  	"A sandboxer should not log denied access requests to avoid spamming logs, "
>  	"but to test audit we can set " ENV_FORCE_LOG_NAME "=1\n"
> +	ENV_FS_QUIET_NAME " and " ENV_NET_QUIET_NAME ", both optional, can then be used "
> +	"to make access to some denied paths or network ports not trigger audit logging.\n"
> +	ENV_FS_QUIET_ACCESS_NAME " and " ENV_NET_QUIET_ACCESS_NAME " can be used to specify "
> +	"which accesses should be quieted (defaults to all):\n"
> +	"* " ENV_FS_QUIET_ACCESS_NAME ": file system accesses to quiet\n"
> +	"  - \"r\" to quiet all file/dir read accesses\n"
> +	"  - \"w\" to quiet all file/dir write accesses\n"
> +	"* " ENV_NET_QUIET_ACCESS_NAME ": network accesses to quiet\n"
> +	"  - \"b\" to quiet tcp bind denials\n"
> +	"  - \"c\" to quiet tcp connect denials\n"
> +	"  - \"ub\" to quiet udp bind denials\n"
> +	"  - \"uc\" to quiet udp connect / send denials\n"
> +	"In addition, " ENV_SCOPED_QUIET_ACCESS_NAME " can be set to quiet all denials for "
> +	"scoped actions (defaults to none).\n"
> +	"  - \"a\" to quiet abstract unix socket denials\n"
> +	"  - \"s\" to quiet signal denials\n"
>  	"\n"
>  	"Example:\n"
>  	ENV_FS_RO_NAME "=\"${PATH}:/lib:/usr:/proc:/etc:/dev/urandom\" "
> @@ -368,7 +441,12 @@ int main(const int argc, char *const argv[], char *const *const envp)
>  				      LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP,
>  		.scoped = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET |
>  			  LANDLOCK_SCOPE_SIGNAL,
> +		.quiet_access_fs = 0,
> +		.quiet_access_net = 0,
> +		.quiet_scoped = 0,
>  	};
> +
> +	bool quiet_supported = true;
>  	int supported_restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON;
>  	int set_restrict_flags = 0;
>  
> @@ -459,6 +537,9 @@ int main(const int argc, char *const argv[], char *const *const envp)
>  		ruleset_attr.handled_access_net &=
>  			~(LANDLOCK_ACCESS_NET_BIND_UDP |
>  			  LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP);
> +		__attribute__((fallthrough));
The fallthrough should be the last statement in the switch case;
otherwise this causes a build warning.
> +		/* Don't add quiet flags for ABI < 10 later on. */
> +		quiet_supported = false;
>  
>  		/* Must be printed for any ABI < LANDLOCK_ABI_LAST. */
>  		fprintf(stderr,
> @@ -525,6 +606,25 @@ int main(const int argc, char *const argv[], char *const *const envp)
>  		unsetenv(ENV_FORCE_LOG_NAME);
>  	}
>  
> +	/*
> +	 * Add quiet for fs/net handled access bits.  Doing this alone has no
> +	 * effect unless we later add quiet rules per FS_QUIET/NET_QUIET.
> +	 */
> +	if (quiet_supported) {
> +		if (add_quiet_access(&ruleset_attr.quiet_access_fs,
> +				     ruleset_attr.handled_access_fs,
> +				     ENV_FS_QUIET_ACCESS_NAME, true))
> +			return 1;
> +		if (add_quiet_access(&ruleset_attr.quiet_access_net,
> +				     ruleset_attr.handled_access_net,
> +				     ENV_NET_QUIET_ACCESS_NAME, true))
> +			return 1;
> +		if (add_quiet_access(&ruleset_attr.quiet_scoped,
> +				     ruleset_attr.scoped,
> +				     ENV_SCOPED_QUIET_ACCESS_NAME, false))
> +			return 1;
> +	}
> +
>  	ruleset_fd =
>  		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
>  	if (ruleset_fd < 0) {
> @@ -532,30 +632,42 @@ int main(const int argc, char *const argv[], char *const *const envp)
>  		return 1;
>  	}
>  
> -	if (populate_ruleset_fs(ENV_FS_RO_NAME, ruleset_fd, access_fs_ro)) {
> +	if (populate_ruleset_fs(ENV_FS_RO_NAME, ruleset_fd, access_fs_ro, 0))
>  		goto err_close_ruleset;
> -	}
> -	if (populate_ruleset_fs(ENV_FS_RW_NAME, ruleset_fd, access_fs_rw)) {
> +	if (populate_ruleset_fs(ENV_FS_RW_NAME, ruleset_fd, access_fs_rw, 0))
>  		goto err_close_ruleset;
> +
> +	/* Don't require this env to be present. */
> +	if (quiet_supported && getenv(ENV_FS_QUIET_NAME)) {
> +		if (populate_ruleset_fs(ENV_FS_QUIET_NAME, ruleset_fd, 0,
> +					LANDLOCK_ADD_RULE_QUIET))
> +			goto err_close_ruleset;
>  	}
>  
>  	if (populate_ruleset_net(ENV_TCP_BIND_NAME, ruleset_fd,
> -				 LANDLOCK_ACCESS_NET_BIND_TCP)) {
> +				 LANDLOCK_ACCESS_NET_BIND_TCP, 0)) {
>  		goto err_close_ruleset;
>  	}
>  	if (populate_ruleset_net(ENV_TCP_CONNECT_NAME, ruleset_fd,
> -				 LANDLOCK_ACCESS_NET_CONNECT_TCP)) {
> +				 LANDLOCK_ACCESS_NET_CONNECT_TCP, 0)) {
>  		goto err_close_ruleset;
>  	}
>  	if (populate_ruleset_net(ENV_UDP_BIND_NAME, ruleset_fd,
> -				 LANDLOCK_ACCESS_NET_BIND_UDP)) {
> +				 LANDLOCK_ACCESS_NET_BIND_UDP, 0)) {
>  		goto err_close_ruleset;
>  	}
>  	if (populate_ruleset_net(ENV_UDP_CONNECT_SEND_NAME, ruleset_fd,
> -				 LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP)) {
> +				 LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP, 0)) {
>  		goto err_close_ruleset;
>  	}
>  
> +	if (quiet_supported) {
> +		if (populate_ruleset_net(ENV_NET_QUIET_NAME, ruleset_fd, 0,
> +					 LANDLOCK_ADD_RULE_QUIET)) {
> +			goto err_close_ruleset;
> +		}
> +	}
> +
>  	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
>  		perror("Failed to restrict privileges");
>  		goto err_close_ruleset;
> -- 
> 2.54.0

  reply	other threads:[~2026-05-29  2:34 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-27  1:01 [PATCH v9 0/9] Implement LANDLOCK_ADD_RULE_QUIET Tingmao Wang
2026-05-27  1:01 ` [PATCH v9 1/9] landlock: Add a place for flags to layer rules Tingmao Wang
2026-05-28 22:01   ` Justin Suess
2026-05-27  1:01 ` [PATCH v9 2/9] landlock: Add API support and docs for the quiet flags Tingmao Wang
2026-05-27  1:01 ` [PATCH v9 3/9] landlock: Suppress logging when quiet flag is present Tingmao Wang
2026-05-27  1:01 ` [PATCH v9 4/9] samples/landlock: Add quiet flag support to sandboxer Tingmao Wang
2026-05-29  2:34   ` Justin Suess [this message]
2026-05-27  1:01 ` [PATCH v9 5/9] selftests/landlock: Replace hard-coded 16 with a constant Tingmao Wang
2026-05-27  1:01 ` [PATCH v9 6/9] selftests/landlock: add tests for quiet flag with fs rules Tingmao Wang
2026-05-27  1:01 ` [PATCH v9 7/9] selftests/landlock: add tests for quiet flag with net rules Tingmao Wang
2026-05-27  1:01 ` [PATCH v9 8/9] selftests/landlock: Add tests for quiet flag with scope Tingmao Wang
2026-05-27  1:01 ` [PATCH v9 9/9] selftests/landlock: Add tests for invalid use of quiet flag Tingmao Wang

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=ahj6gwXIbb58VFsZ@zenbox \
    --to=utilityemal77@gmail.com \
    --cc=gnoack3000@gmail.com \
    --cc=jack@suse.cz \
    --cc=linux-security-module@vger.kernel.org \
    --cc=m@maowtm.org \
    --cc=mic@digikod.net \
    --cc=xandfury@gmail.com \
    /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