public inbox for linux-security-module@vger.kernel.org
 help / color / mirror / Atom feed
From: "Günther Noack" <gnoack3000@gmail.com>
To: "Mickaël Salaün" <mic@digikod.net>
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>,
	"Günther Noack" <gnoack3000@gmail.com>
Subject: [PATCH v2 1/3] selftests/landlock: Add filesystem access benchmark
Date: Sun, 25 Jan 2026 20:58:51 +0100	[thread overview]
Message-ID: <20260125195853.109967-2-gnoack3000@gmail.com> (raw)
In-Reply-To: <20260125195853.109967-1-gnoack3000@gmail.com>

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
+ */
+
+#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)
+{
+	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 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);
+		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);
+
+		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");
+	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);
+		if (fd != -1) {
+			if (use_landlock)
+				errx(1, "openat succeeded, expected error");
+
+			close(fd);
+		}
+	}
+
+	if (times(&end_time) == -1)
+		err(1, "times");
+
+	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-25 19:59 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 ` Günther Noack [this message]
2026-01-28 21:31   ` [PATCH v2 1/3] selftests/landlock: Add filesystem access benchmark Mickaël Salaün
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=20260125195853.109967-2-gnoack3000@gmail.com \
    --to=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=mic@digikod.net \
    --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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox