All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Mickaël Salaün" <mic@digikod.net>
To: "Günther Noack" <gnoack3000@gmail.com>
Cc: linux-security-module@vger.kernel.org,
	Tingmao Wang <m@maowtm.org>,
	 Justin Suess <utilityemal77@gmail.com>,
	Samasth Norway Ananda <samasth.norway.ananda@oracle.com>,
	 Matthieu Buffet <matthieu@buffet.re>,
	Mikhail Ivanov <ivanov.mikhail1@huawei-partners.com>,
	 konstantin.meskhidze@huawei.com,
	Randy Dunlap <rdunlap@infradead.org>
Subject: Re: [PATCH v2 1/3] selftests/landlock: Add filesystem access benchmark
Date: Wed, 28 Jan 2026 22:31:23 +0100	[thread overview]
Message-ID: <20260128.eiJou3fiezai@digikod.net> (raw)
In-Reply-To: <20260125195853.109967-2-gnoack3000@gmail.com>

On Sun, Jan 25, 2026 at 08:58:51PM +0100, Günther Noack wrote:
> fs_bench benchmarks the performance of Landlock's path walk
> by exercising it in a scenario that amplifies Landlock's overhead:
> 
> * Create a large number of nested directories
> * Enforce a Landlock policy in which a rule is associated with each of
>   these subdirectories
> * Benchmark openat() applied to the deepest directory,
>   forcing Landlock to walk the entire path.
> 
> Signed-off-by: Günther Noack <gnoack3000@gmail.com>
> ---
>  tools/testing/selftests/landlock/.gitignore |   1 +
>  tools/testing/selftests/landlock/Makefile   |   1 +
>  tools/testing/selftests/landlock/fs_bench.c | 161 ++++++++++++++++++++
>  3 files changed, 163 insertions(+)
>  create mode 100644 tools/testing/selftests/landlock/fs_bench.c
> 
> diff --git a/tools/testing/selftests/landlock/.gitignore b/tools/testing/selftests/landlock/.gitignore
> index a820329cae0d..1974e17a2611 100644
> --- a/tools/testing/selftests/landlock/.gitignore
> +++ b/tools/testing/selftests/landlock/.gitignore
> @@ -1,4 +1,5 @@
>  /*_test
> +/fs_bench
>  /sandbox-and-launch
>  /true
>  /wait-pipe
> diff --git a/tools/testing/selftests/landlock/Makefile b/tools/testing/selftests/landlock/Makefile
> index 044b83bde16e..fc43225d319a 100644
> --- a/tools/testing/selftests/landlock/Makefile
> +++ b/tools/testing/selftests/landlock/Makefile
> @@ -9,6 +9,7 @@ LOCAL_HDRS += $(wildcard *.h)
>  src_test := $(wildcard *_test.c)
>  
>  TEST_GEN_PROGS := $(src_test:.c=)
> +TEST_GEN_PROGS += fs_bench
>  
>  TEST_GEN_PROGS_EXTENDED := \
>  	true \
> diff --git a/tools/testing/selftests/landlock/fs_bench.c b/tools/testing/selftests/landlock/fs_bench.c
> new file mode 100644
> index 000000000000..a3b686418bc5
> --- /dev/null
> +++ b/tools/testing/selftests/landlock/fs_bench.c
> @@ -0,0 +1,161 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Landlock filesystem benchmark

You might want to add some copyright.

> + */
> +
> +#define _GNU_SOURCE
> +#include <err.h>
> +#include <fcntl.h>
> +#include <linux/landlock.h>
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/prctl.h>
> +#include <sys/stat.h>
> +#include <sys/syscall.h>
> +#include <sys/times.h>
> +#include <time.h>
> +#include <unistd.h>
> +
> +void usage(const char *argv0)

const

> +{
> +	printf("Usage:\n");
> +	printf("  %s [OPTIONS]\n", argv0);
> +	printf("\n");
> +	printf("  Benchmark expensive Landlock checks for D nested dirs\n");
> +	printf("\n");
> +	printf("Options:\n");
> +	printf("  -h	help\n");
> +	printf("  -L	disable Landlock (as a baseline)\n");
> +	printf("  -d D	set directory depth to D\n");
> +	printf("  -n N	set number of benchmark iterations to N\n");
> +}
> +
> +/*
> + * Build a deep directory, enforce Landlock and return the FD to the
> + * deepest dir.  On any failure, exit the process with an error.
> + */
> +int build_directory(size_t depth, bool use_landlock)

const

> +{
> +	const char *path = "d"; /* directory name */
> +	int abi, ruleset_fd, current, previous;
> +
> +	if (use_landlock) {
> +		abi = syscall(SYS_landlock_create_ruleset, NULL, 0,
> +			      LANDLOCK_CREATE_RULESET_VERSION);

Please include wrappers.h and use the related syscall helpers.  One of
the benefit is to use __NR_* constants defined by the installed kernel
headers.

> +		if (abi < 7)
> +			err(1, "Landlock ABI too low: got %d, wanted 7+", abi);
> +	}
> +
> +	ruleset_fd = -1;
> +	if (use_landlock) {
> +		struct landlock_ruleset_attr attr = {
> +			.handled_access_fs =
> +				0xffff, /* All FS access rights as of 2026-01 */
> +		};
> +		ruleset_fd = syscall(SYS_landlock_create_ruleset, &attr,
> +				     sizeof(attr), 0U);
> +		if (ruleset_fd < 0)
> +			err(1, "landlock_create_ruleset");
> +	}
> +
> +	current = open(".", O_PATH);
> +	if (current < 0)
> +		err(1, "open(.)");
> +
> +	while (depth--) {
> +		if (use_landlock) {
> +			struct landlock_path_beneath_attr attr = {
> +				.allowed_access = LANDLOCK_ACCESS_FS_IOCTL_DEV,
> +				.parent_fd = current,
> +			};
> +			if (syscall(SYS_landlock_add_rule, ruleset_fd,
> +				    LANDLOCK_RULE_PATH_BENEATH, &attr, 0) < 0)
> +				err(1, "landlock_add_rule");
> +		}
> +
> +		if (mkdirat(current, path, 0700) < 0)
> +			err(1, "mkdirat(%s)", path);

We should have a loop to build the directories, then start the timer and
have another loop to add Landlock rules.

> +
> +		previous = current;
> +		current = openat(current, path, O_PATH);
> +		if (current < 0)
> +			err(1, "open(%s)", path);
> +
> +		close(previous);
> +	}
> +
> +	if (use_landlock) {
> +		if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0)
> +			err(1, "prctl");
> +
> +		if (syscall(SYS_landlock_restrict_self, ruleset_fd, 0) < 0)
> +			err(1, "landlock_restrict_self");
> +	}
> +
> +	close(ruleset_fd);
> +	return current;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	bool use_landlock = true;
> +	size_t num_iterations = 100000;
> +	size_t num_subdirs = 10000;
> +	int c, current, fd;
> +	struct tms start_time, end_time;
> +
> +	setbuf(stdout, NULL);
> +	while ((c = getopt(argc, argv, "hLd:n:")) != -1) {
> +		switch (c) {
> +		case 'h':
> +			usage(argv[0]);
> +			return EXIT_SUCCESS;
> +		case 'L':
> +			use_landlock = false;
> +			break;
> +		case 'd':
> +			num_subdirs = atoi(optarg);
> +			break;
> +		case 'n':
> +			num_iterations = atoi(optarg);
> +			break;
> +		default:
> +			usage(argv[0]);
> +			return EXIT_FAILURE;
> +		}
> +	}
> +
> +	printf("*** Benchmark ***\n");

We should probably use ksft_*() helpers in main (see
seccomp_benchmark.c).

> +	printf("%zu dirs, %zu iterations, %s landlock\n", num_subdirs,
> +	       num_iterations, use_landlock ? "with" : "without");
> +
> +	if (times(&start_time) == -1)
> +		err(1, "times");
> +
> +	current = build_directory(num_subdirs, use_landlock);
> +
> +	for (int i = 0; i < num_iterations; i++) {
> +		fd = openat(current, ".", O_DIRECTORY);

We can use AT_EMPTY_PATH (with an empty path) instead of "."
I guess the benchmark should not change, but better to check again.

> +		if (fd != -1) {
> +			if (use_landlock)
> +				errx(1, "openat succeeded, expected error");
> +
> +			close(fd);
> +		}
> +	}
> +
> +	if (times(&end_time) == -1)
> +		err(1, "times");

The created directories should be removed here (setup and teardown).

> +
> +	printf("*** Benchmark concluded ***\n");
> +	printf("System: %ld clocks\n",
> +	       end_time.tms_stime - start_time.tms_stime);
> +	printf("User  : %ld clocks\n",
> +	       end_time.tms_utime - start_time.tms_utime);
> +	printf("Clocks per second: %ld\n", CLOCKS_PER_SEC);
> +
> +	close(current);
> +}
> -- 
> 2.52.0
> 
> 

  reply	other threads:[~2026-01-28 22:26 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-25 19:58 [PATCH v2 0/3] landlock: Refactor layer masks Günther Noack
2026-01-25 19:58 ` [PATCH v2 1/3] selftests/landlock: Add filesystem access benchmark Günther Noack
2026-01-28 21:31   ` Mickaël Salaün [this message]
2026-02-06 12:24     ` Günther Noack
2026-02-06 12:59       ` Mickaël Salaün
2026-02-06 15:05         ` Günther Noack
2026-01-25 19:58 ` [PATCH v2 2/3] landlock: access_mask_subset() helper Günther Noack
2026-01-25 21:48   ` Randy Dunlap
2026-01-26 16:48     ` Günther Noack
2026-01-28 21:31   ` Mickaël Salaün
2026-01-28 21:38     ` Günther Noack
2026-01-25 19:58 ` [PATCH v2 3/3] landlock: transpose the layer masks data structure Günther Noack
2026-01-25 22:02   ` Randy Dunlap
2026-01-26 16:52     ` Günther Noack
2026-01-26 17:55       ` Randy Dunlap
2026-01-28 21:34   ` Mickaël Salaün
2026-01-29  7:56     ` Günther Noack
2026-01-29 16:54       ` Mickaël Salaün
2026-02-06  8:02         ` Günther Noack
2026-01-29 20:28   ` Mickaël Salaün
2026-02-01 12:24     ` Günther Noack
2026-01-28 21:31 ` [PATCH v2 0/3] landlock: Refactor layer masks Mickaël Salaün
2026-02-06  7:32   ` Günther Noack
2026-02-06  7:49     ` Günther Noack
2026-02-06 11:24       ` 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=20260128.eiJou3fiezai@digikod.net \
    --to=mic@digikod.net \
    --cc=gnoack3000@gmail.com \
    --cc=ivanov.mikhail1@huawei-partners.com \
    --cc=konstantin.meskhidze@huawei.com \
    --cc=linux-security-module@vger.kernel.org \
    --cc=m@maowtm.org \
    --cc=matthieu@buffet.re \
    --cc=rdunlap@infradead.org \
    --cc=samasth.norway.ananda@oracle.com \
    --cc=utilityemal77@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.