All of lore.kernel.org
 help / color / mirror / Atom feed
From: Song Liu <song@kernel.org>
To: bpf@vger.kernel.org, linux-fsdevel@vger.kernel.org,
	linux-security-module@vger.kernel.org
Cc: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org,
	kernel-team@meta.com, viro@zeniv.linux.org.uk,
	brauner@kernel.org, jack@suse.cz, paul@paul-moore.com,
	jmorris@namei.org, serge@hallyn.com, Song Liu <song@kernel.org>
Subject: [PATCH bpf-next 3/3] selftests/bpf: Add tests for bpf_kern_path kfunc
Date: Wed, 26 Nov 2025 16:50:07 -0800	[thread overview]
Message-ID: <20251127005011.1872209-4-song@kernel.org> (raw)
In-Reply-To: <20251127005011.1872209-1-song@kernel.org>

Add comprehensive selftests for the new bpf_kern_path and bpf_path_put
kfuncs:

1. Functional tests (prog_tests/kern_path.c, progs/test_kern_path.c):
   - test_kern_path_basic: Tests successful path resolution using
     /proc/self/exe and validates the resolved path with bpf_path_d_path
   - test_kern_path_sb_mount: Tests bpf_kern_path with dynamic input
     from LSM hook parameter (dev_name from sb_mount), demonstrating
     real-world usage where BPF programs resolve paths from hook args

2. Verifier success tests (progs/verifier_kern_path.c):
   - kern_path_success: Proper acquire -> use -> release pattern
   - kern_path_multiple_paths: Multiple concurrent path acquisitions

3. Verifier failure tests (progs/verifier_kern_path_fail.c):
   - kern_path_unreleased: Resource leak detection
   - path_put_unacquired: Releasing unacquired path
   - path_use_after_put: Use-after-free detection
   - double_path_put: Double-free detection
   - kern_path_non_lsm: Program type restrictions (LSM only)
   - kern_path_non_const_str: reject none const string

These tests verify both the functionality of the kfuncs and that the
verifier properly enforces acquire/release semantics to prevent
resource leaks.

Signed-off-by: Song Liu <song@kernel.org>
---
 .../testing/selftests/bpf/bpf_experimental.h  |  4 +
 .../selftests/bpf/prog_tests/kern_path.c      | 82 ++++++++++++++++
 .../selftests/bpf/progs/test_kern_path.c      | 56 +++++++++++
 .../selftests/bpf/progs/verifier_kern_path.c  | 52 ++++++++++
 .../bpf/progs/verifier_kern_path_fail.c       | 97 +++++++++++++++++++
 5 files changed, 291 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/kern_path.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_kern_path.c
 create mode 100644 tools/testing/selftests/bpf/progs/verifier_kern_path.c
 create mode 100644 tools/testing/selftests/bpf/progs/verifier_kern_path_fail.c

diff --git a/tools/testing/selftests/bpf/bpf_experimental.h b/tools/testing/selftests/bpf/bpf_experimental.h
index 2cd9165c7348..c512c9a14752 100644
--- a/tools/testing/selftests/bpf/bpf_experimental.h
+++ b/tools/testing/selftests/bpf/bpf_experimental.h
@@ -221,6 +221,10 @@ extern void bpf_put_file(struct file *file) __ksym;
  */
 extern int bpf_path_d_path(const struct path *path, char *buf, size_t buf__sz) __ksym;
 
+extern struct path *bpf_kern_path(const char *pathname, unsigned int flags) __ksym;
+extern void bpf_path_put(struct path *path) __ksym;
+extern int bpf_path_d_path(const struct path *path, char *buf, size_t buf__sz) __ksym;
+
 /* This macro must be used to mark the exception callback corresponding to the
  * main program. For example:
  *
diff --git a/tools/testing/selftests/bpf/prog_tests/kern_path.c b/tools/testing/selftests/bpf/prog_tests/kern_path.c
new file mode 100644
index 000000000000..f4cdfe202a26
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/kern_path.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2025 Meta Platforms, Inc. */
+
+#include <test_progs.h>
+#include <sys/mount.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "test_kern_path.skel.h"
+#include "verifier_kern_path.skel.h"
+#include "verifier_kern_path_fail.skel.h"
+
+static void __test_kern_path(void (*trigger)(void))
+{
+	struct test_kern_path *skel;
+	int err;
+
+	skel = test_kern_path__open_and_load();
+	if (!ASSERT_OK_PTR(skel, "test_kern_path__open_and_load"))
+		return;
+
+	skel->bss->monitored_pid = getpid();
+
+	err = test_kern_path__attach(skel);
+	if (!ASSERT_OK(err, "test_kern_path__attach"))
+		goto cleanup;
+
+	trigger();
+
+	/* Verify the bpf_path_d_path worked */
+	ASSERT_GT(skel->bss->path_len, 0, "path_len > 0");
+
+cleanup:
+	test_kern_path__destroy(skel);
+}
+
+static void trigger_file_open(void)
+{
+	int fd;
+
+	fd = open("/dev/null", O_RDONLY);
+	if (!ASSERT_OK_FD(fd, "open /dev/null"))
+		return;
+	close(fd);
+}
+
+static void trigger_sb_mount(void)
+{
+	char tmpdir[] = "/tmp/bpf_kern_path_test_XXXXXX";
+	int err;
+
+	if (!ASSERT_OK_PTR(mkdtemp(tmpdir), "mkdtemp"))
+		return;
+
+	err = mount("/tmp", tmpdir, NULL, MS_BIND, NULL);
+	if (!ASSERT_OK(err, "bind mount"))
+		goto rmdir;
+
+	umount(tmpdir);
+rmdir:
+	rmdir(tmpdir);
+}
+
+void test_kern_path(void)
+{
+	if (test__start_subtest("file_open"))
+		__test_kern_path(trigger_file_open);
+
+	if (test__start_subtest("sb_mount"))
+		__test_kern_path(trigger_sb_mount);
+}
+
+void test_verifier_kern_path(void)
+{
+	RUN_TESTS(verifier_kern_path);
+}
+
+void test_verifier_kern_path_fail(void)
+{
+	RUN_TESTS(verifier_kern_path_fail);
+}
diff --git a/tools/testing/selftests/bpf/progs/test_kern_path.c b/tools/testing/selftests/bpf/progs/test_kern_path.c
new file mode 100644
index 000000000000..e9186a1aa990
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/test_kern_path.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2025 Meta Platforms, Inc. */
+
+#include "vmlinux.h"
+#include <bpf/bpf_tracing.h>
+#include "bpf_misc.h"
+#include "bpf_experimental.h"
+
+#define MAX_PATH_LEN 256
+
+char buf[MAX_PATH_LEN];
+int path_len = 0;
+u32 monitored_pid = 0;
+
+SEC("lsm.s/file_open")
+int BPF_PROG(test_kern_path_basic, struct file *file)
+{
+	struct path *p;
+	int ret;
+
+	if (bpf_get_current_pid_tgid() >> 32 != monitored_pid)
+		return 0;
+
+	p = bpf_kern_path("/proc/self/exe", 0);
+	if (p) {
+		ret = bpf_path_d_path(p, buf, MAX_PATH_LEN);
+		if (ret > 0)
+			path_len = ret;
+		bpf_path_put(p);
+	}
+
+	return 0;
+}
+
+SEC("lsm.s/sb_mount")
+int BPF_PROG(test_kern_path_from_sb_mount, const char *dev_name, const struct path *path,
+	     const char *type, unsigned long flags, void *data)
+{
+	struct path *p;
+	int ret;
+
+	if (bpf_get_current_pid_tgid() >> 32 != monitored_pid)
+		return 0;
+
+	p = bpf_kern_path(dev_name, 0);
+	if (p) {
+		ret = bpf_path_d_path(p, buf, MAX_PATH_LEN);
+		if (ret > 0)
+			path_len = ret;
+		bpf_path_put(p);
+	}
+
+	return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/verifier_kern_path.c b/tools/testing/selftests/bpf/progs/verifier_kern_path.c
new file mode 100644
index 000000000000..0e6ccf640b64
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/verifier_kern_path.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2025 Meta Platforms, Inc. */
+
+#include <vmlinux.h>
+#include <bpf/bpf_tracing.h>
+#include <linux/limits.h>
+#include "bpf_misc.h"
+#include "bpf_experimental.h"
+
+static char buf[PATH_MAX];
+
+SEC("lsm.s/file_open")
+__success
+int BPF_PROG(kern_path_success)
+{
+	struct path *p;
+
+	p = bpf_kern_path("/proc/self/exe", 0);
+	if (!p)
+		return 0;
+
+	bpf_path_d_path(p, buf, sizeof(buf));
+
+	bpf_path_put(p);
+	return 0;
+}
+
+SEC("lsm.s/file_open")
+__success
+int BPF_PROG(kern_path_multiple_paths)
+{
+	struct path *p1, *p2;
+
+	p1 = bpf_kern_path("/proc/self/exe", 0);
+	if (!p1)
+		return 0;
+
+	p2 = bpf_kern_path("/proc/self/cwd", 0);
+	if (!p2) {
+		bpf_path_put(p1);
+		return 0;
+	}
+
+	bpf_path_d_path(p1, buf, sizeof(buf));
+	bpf_path_d_path(p2, buf, sizeof(buf));
+
+	bpf_path_put(p2);
+	bpf_path_put(p1);
+	return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/verifier_kern_path_fail.c b/tools/testing/selftests/bpf/progs/verifier_kern_path_fail.c
new file mode 100644
index 000000000000..520c227af5ca
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/verifier_kern_path_fail.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2025 Meta Platforms, Inc. */
+
+#include <vmlinux.h>
+#include <bpf/bpf_tracing.h>
+#include <linux/limits.h>
+#include "bpf_misc.h"
+#include "bpf_experimental.h"
+
+static char buf[PATH_MAX];
+
+SEC("lsm.s/file_open")
+__failure __msg("Unreleased reference")
+int BPF_PROG(kern_path_unreleased)
+{
+	struct path *p;
+
+	p = bpf_kern_path("/proc/self/exe", 0);
+	if (!p)
+		return 0;
+
+	/* Acquired but never released - should fail verification */
+	return 0;
+}
+
+SEC("lsm.s/file_open")
+__failure __msg("pointer type STRUCT path must point to scalar, or struct with scalar")
+int BPF_PROG(path_put_unacquired)
+{
+	struct path p = {};
+
+	/* Can't release an unacquired path - should fail verification */
+	bpf_path_put(&p);
+	return 0;
+}
+
+SEC("lsm.s/file_open")
+__failure __msg("pointer type STRUCT path must point to scalar, or struct with scalar")
+int BPF_PROG(path_use_after_put, struct file *file)
+{
+	struct path *p;
+
+	p = bpf_kern_path("/proc/self/exe", 0);
+	if (!p)
+		return 0;
+
+	bpf_path_put(p);
+
+	/* Using path after put - should fail verification */
+	bpf_path_d_path(p, buf, sizeof(buf));
+	return 0;
+}
+
+SEC("lsm.s/file_open")
+__failure __msg("pointer type STRUCT path must point to scalar, or struct with scalar")
+int BPF_PROG(double_path_put)
+{
+	struct path *p;
+
+	p = bpf_kern_path("/proc/self/exe", 0);
+	if (!p)
+		return 0;
+
+	bpf_path_put(p);
+	/* Double put - should fail verification */
+	bpf_path_put(p);
+	return 0;
+}
+
+SEC("fentry/vfs_open")
+__failure __msg("calling kernel function bpf_kern_path is not allowed")
+int BPF_PROG(kern_path_non_lsm)
+{
+	struct path *p;
+
+	/* Calling bpf_kern_path() from a non-LSM BPF program isn't permitted */
+	p = bpf_kern_path("/proc/self/exe", 0);
+	if (p)
+		bpf_path_put(p);
+	return 0;
+}
+
+SEC("lsm.s/sb_eat_lsm_opts")
+__failure __msg("arg#0 doesn't point to a const string")
+int BPF_PROG(kern_path_non_const_str, char *options, void **mnt_opts)
+{
+	struct path *p;
+
+	/* Calling bpf_kern_path() from a with non-const string isn't permitted */
+	p = bpf_kern_path(options, 0);
+	if (p)
+		bpf_path_put(p);
+	return 0;
+}
+
+
+char _license[] SEC("license") = "GPL";
-- 
2.47.3


  parent reply	other threads:[~2025-11-27  0:50 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-11-27  0:50 [PATCH bpf-next 0/3] Introduce bpf_kern_path and bpf_path_put Song Liu
2025-11-27  0:50 ` [PATCH bpf-next 1/3] bpf: Allow const char * from LSM hooks as kfunc const string arguments Song Liu
2025-11-27  0:50 ` [PATCH bpf-next 2/3] bpf: Add bpf_kern_path and bpf_path_put kfuncs Song Liu
2025-11-30  4:23   ` Al Viro
2025-11-30  5:57     ` Song Liu
2025-11-30  6:46       ` Al Viro
2025-12-01  7:32         ` Song Liu
2025-11-27  0:50 ` Song Liu [this message]
2025-11-27  0:50 ` [PATCH bpf-next 0/3] Introduce bpf_kern_path and bpf_path_put Song Liu
2025-11-27  0:50 ` [PATCH bpf-next 1/3] bpf: Allow const char * from LSM hooks as kfunc const string arguments Song Liu
2025-11-27 19:07   ` kernel test robot
2025-11-27  0:50 ` [PATCH bpf-next 2/3] bpf: Add bpf_kern_path and bpf_path_put kfuncs Song Liu
2025-11-27  0:50 ` [PATCH bpf-next 3/3] selftests/bpf: Add tests for bpf_kern_path kfunc Song Liu

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=20251127005011.1872209-4-song@kernel.org \
    --to=song@kernel.org \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=brauner@kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=jack@suse.cz \
    --cc=jmorris@namei.org \
    --cc=kernel-team@meta.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=paul@paul-moore.com \
    --cc=serge@hallyn.com \
    --cc=viro@zeniv.linux.org.uk \
    /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.