From: "Mickaël Salaün" <mic@digikod.net>
To: Tingmao Wang <m@maowtm.org>
Cc: "Günther Noack" <gnoack3000@gmail.com>,
"Justin Suess" <utilityemal77@gmail.com>,
"Jan Kara" <jack@suse.cz>, "Abhinav Saxena" <xandfury@gmail.com>,
linux-security-module@vger.kernel.org
Subject: Re: [PATCH v10 4/9] samples/landlock: Add quiet flag support to sandboxer
Date: Tue, 9 Jun 2026 00:41:47 +0200 [thread overview]
Message-ID: <20260609.Pi8aiyae5nee@digikod.net> (raw)
In-Reply-To: <9a90a123beb481c5be345e0d169eb14295803678.1780272022.git.m@maowtm.org>
As for LL_FORCE_LOG, using a QUIET flag not supported should exit with
an error.
On Mon, Jun 01, 2026 at 01:00:38AM +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 v10:
> - Remove stray __attribute__((fallthrough)); (Thanks Justin for
> spotting)
>
> 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 | 133 ++++++++++++++++++++++++++++++++---
> 1 file changed, 122 insertions(+), 11 deletions(-)
>
> diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c
> index 94e399e6b146..73a81ecd3696 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;
What happen if we set "b" in LL_FS_QUIET_ACCESS?
> + else if (strcmp(str_access, "c") == 0)
> + *quiet_access |= LANDLOCK_ACCESS_NET_CONNECT_TCP;
> + else if (strcmp(str_access, "ub") == 0)
I don't really like these access-right names, they are not consistent.
All these env variables add a lot of complexity too. What about just
being able to quiet a path or a port? That would mean renaming
LL_FS_QUIET_ACCESS to LL_FS_QUIET.
Anyway, all should be unsetenv() unconditionally.
> + *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;
> + 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,
> };
> +
Why this new line?
> + bool quiet_supported = true;
> int supported_restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON;
> int set_restrict_flags = 0;
>
> @@ -459,6 +537,8 @@ 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);
> + /* Don't add quiet flags for ABI < 10 later on. */
/* Removes quiet flags...
> + quiet_supported = false;
>
> /* Must be printed for any ABI < LANDLOCK_ABI_LAST. */
> fprintf(stderr,
> @@ -525,6 +605,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 +631,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
next prev parent reply other threads:[~2026-06-08 22:50 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-01 0:00 [PATCH v10 0/9] Implement LANDLOCK_ADD_RULE_QUIET Tingmao Wang
2026-06-01 0:00 ` [PATCH v10 1/9] landlock: Add a place for flags to layer rules Tingmao Wang
2026-06-08 22:40 ` Mickaël Salaün
2026-06-01 0:00 ` [PATCH v10 2/9] landlock: Add API support and docs for the quiet flags Tingmao Wang
2026-06-08 22:41 ` Mickaël Salaün
2026-06-01 0:00 ` [PATCH v10 3/9] landlock: Suppress logging when quiet flag is present Tingmao Wang
2026-06-08 22:41 ` Mickaël Salaün
2026-06-01 0:00 ` [PATCH v10 4/9] samples/landlock: Add quiet flag support to sandboxer Tingmao Wang
2026-06-08 22:41 ` Mickaël Salaün [this message]
2026-06-01 0:00 ` [PATCH v10 5/9] selftests/landlock: Replace hard-coded 16 with a constant Tingmao Wang
2026-06-01 0:00 ` [PATCH v10 6/9] selftests/landlock: add tests for quiet flag with fs rules Tingmao Wang
2026-06-05 19:04 ` Justin Suess
2026-06-08 1:31 ` Tingmao Wang
2026-06-01 0:00 ` [PATCH v10 7/9] selftests/landlock: add tests for quiet flag with net rules Tingmao Wang
2026-06-01 0:00 ` [PATCH v10 8/9] selftests/landlock: Add tests for quiet flag with scope Tingmao Wang
2026-06-01 0:00 ` [PATCH v10 9/9] selftests/landlock: Add tests for invalid use of quiet flag Tingmao Wang
2026-06-08 22:41 ` 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=20260609.Pi8aiyae5nee@digikod.net \
--to=mic@digikod.net \
--cc=gnoack3000@gmail.com \
--cc=jack@suse.cz \
--cc=linux-security-module@vger.kernel.org \
--cc=m@maowtm.org \
--cc=utilityemal77@gmail.com \
--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 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.