linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH bpf-next 0/3] Introduce bpf_kern_path and bpf_path_put
@ 2025-11-27  0:50 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
                   ` (6 more replies)
  0 siblings, 7 replies; 13+ messages in thread
From: Song Liu @ 2025-11-27  0:50 UTC (permalink / raw)
  To: bpf, linux-fsdevel, linux-security-module
  Cc: ast, daniel, andrii, kernel-team, viro, brauner, jack, paul,
	jmorris, serge, Song Liu

Security solutions use LSM hook security_sb_mount to monitor mount
operations. security_sb_mount takes dev_name as a string. To get a struct
path from dev_name, in-tree LSMs use kern_path. Introduce kfuncs
bpf_kern_path so that bpf LSM can do similar operations. bpf_kern_path
takes a reference on the return value path. Also add kfunc bpf_path_put to
release path returned by bpf_kern_path. Note that, bpf_kern_path only holds
reference on the path during the duration of this bpf program. The verifier
enforces the bpf program release this reference.

Patch 1/3 prepares bpf verifier to handle const char * passed in as hook
argument. Before this change, bpf helpers and kfuncs only consider value
from read only map as const string.

Patch 2/3 adds the two kfuncs.

Patch 3/3 add tests for the new kfuncs.

Song Liu (3):
  bpf: Allow const char * from LSM hooks as kfunc const string arguments
  bpf: Add bpf_kern_path and bpf_path_put kfuncs
  selftests/bpf: Add tests for bpf_kern_path kfunc

 fs/bpf_fs_kfuncs.c                            | 58 +++++++++++
 include/linux/btf.h                           |  1 +
 kernel/bpf/btf.c                              | 33 +++++++
 kernel/bpf/verifier.c                         | 51 +++++++---
 .../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 +++++++++++++++++++
 9 files changed, 422 insertions(+), 12 deletions(-)
 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

--
2.47.3

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH bpf-next 1/3] bpf: Allow const char * from LSM hooks as kfunc const string arguments
  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 ` Song Liu
  2025-11-27  0:50 ` [PATCH bpf-next 2/3] bpf: Add bpf_kern_path and bpf_path_put kfuncs Song Liu
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Song Liu @ 2025-11-27  0:50 UTC (permalink / raw)
  To: bpf, linux-fsdevel, linux-security-module
  Cc: ast, daniel, andrii, kernel-team, viro, brauner, jack, paul,
	jmorris, serge, Song Liu

Let the BPF verifier to recognize const char * arguments from LSM hooks
(and other BPF program types) as valid const string pointers that can be
passed to kfuncs expecting KF_ARG_PTR_TO_CONST_STR.

Previously, kfuncs with KF_ARG_PTR_TO_CONST_STR only accepted
PTR_TO_MAP_VALUE from readonly maps. This was limiting for LSM programs
that receive const char * arguments from hooks like sb_mount's dev_name.

Signed-off-by: Song Liu <song@kernel.org>
---
 include/linux/btf.h   |  1 +
 kernel/bpf/btf.c      | 33 ++++++++++++++++++++++++++++
 kernel/bpf/verifier.c | 51 +++++++++++++++++++++++++++++++++----------
 3 files changed, 73 insertions(+), 12 deletions(-)

diff --git a/include/linux/btf.h b/include/linux/btf.h
index f06976ffb63f..bd5a32d33254 100644
--- a/include/linux/btf.h
+++ b/include/linux/btf.h
@@ -224,6 +224,7 @@ struct btf *btf_base_btf(const struct btf *btf);
 bool btf_type_is_i32(const struct btf_type *t);
 bool btf_type_is_i64(const struct btf_type *t);
 bool btf_type_is_primitive(const struct btf_type *t);
+bool btf_type_is_const_char_ptr(const struct btf *btf, const struct btf_type *t);
 bool btf_member_is_reg_int(const struct btf *btf, const struct btf_type *s,
 			   const struct btf_member *m,
 			   u32 expected_offset, u32 expected_size);
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 0de8fc8a0e0b..94a272585b97 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -897,6 +897,25 @@ bool btf_type_is_primitive(const struct btf_type *t)
 	       btf_is_any_enum(t);
 }
 
+bool btf_type_is_const_char_ptr(const struct btf *btf, const struct btf_type *t)
+{
+	const char *tname;
+
+	/* The type chain has to be PTR->CONST->CHAR */
+	if (BTF_INFO_KIND(t->info) != BTF_KIND_PTR)
+		return false;
+
+	t = btf_type_by_id(btf, t->type);
+	if (BTF_INFO_KIND(t->info) != BTF_KIND_CONST)
+		return false;
+
+	t = btf_type_by_id(btf, t->type);
+	tname = btf_name_by_offset(btf, t->name_off);
+	if (tname && strcmp(tname, "char") == 0)
+		return true;
+	return false;
+}
+
 /*
  * Check that given struct member is a regular int with expected
  * offset and size.
@@ -6746,6 +6765,20 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
 			/* Default prog with MAX_BPF_FUNC_REG_ARGS args */
 			return true;
 		t = btf_type_by_id(btf, args[arg].type);
+
+		/*
+		 * For const string, we need to match "const char *"
+		 * exactly. Therefore, do the check before the skipping
+		 * modifiers.
+		 */
+		if (btf_type_is_const_char_ptr(btf, t)) {
+			info->reg_type = PTR_TO_BTF_ID;
+			if (prog_args_trusted(prog))
+				info->reg_type |= PTR_TRUSTED;
+			info->btf = btf;
+			info->btf_id = args[arg].type;
+			return true;
+		}
 	}
 
 	/* skip modifiers */
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 766695491bc5..a9757c056d4b 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -9598,8 +9598,12 @@ static enum bpf_dynptr_type dynptr_get_type(struct bpf_verifier_env *env,
 	return state->stack[spi].spilled_ptr.dynptr.type;
 }
 
-static int check_reg_const_str(struct bpf_verifier_env *env,
-			       struct bpf_reg_state *reg, u32 regno)
+/*
+ * Check for const string saved in a bpf map. The caller is responsible
+ * to check reg->type == PTR_TO_MAP_VALUE.
+ */
+static int check_reg_const_str_in_map(struct bpf_verifier_env *env,
+				      struct bpf_reg_state *reg, u32 regno)
 {
 	struct bpf_map *map = reg->map_ptr;
 	int err;
@@ -9607,9 +9611,6 @@ static int check_reg_const_str(struct bpf_verifier_env *env,
 	u64 map_addr;
 	char *str_ptr;
 
-	if (reg->type != PTR_TO_MAP_VALUE)
-		return -EINVAL;
-
 	if (!bpf_map_is_rdonly(map)) {
 		verbose(env, "R%d does not point to a readonly map'\n", regno);
 		return -EACCES;
@@ -9646,6 +9647,26 @@ static int check_reg_const_str(struct bpf_verifier_env *env,
 	return 0;
 }
 
+/* Check for const string passed in as input to the bpf program. */
+static int check_reg_const_str_arg(struct bpf_reg_state *reg)
+{
+	const struct btf *btf;
+	const struct btf_type *t;
+	const char *tname;
+
+	if (base_type(reg->type) != PTR_TO_BTF_ID)
+		return -EINVAL;
+
+	btf = reg->btf;
+	t = btf_type_by_id(btf, reg->btf_id);
+	if (!t)
+		return -EINVAL;
+
+	if (btf_type_is_const_char_ptr(btf, t))
+		return 0;
+	return -EINVAL;
+}
+
 /* Returns constant key value in `value` if possible, else negative error */
 static int get_constant_map_key(struct bpf_verifier_env *env,
 				struct bpf_reg_state *key,
@@ -9964,7 +9985,9 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
 		break;
 	case ARG_PTR_TO_CONST_STR:
 	{
-		err = check_reg_const_str(env, reg, regno);
+		if (reg->type != PTR_TO_MAP_VALUE)
+			return -EINVAL;
+		err = check_reg_const_str_in_map(env, reg, regno);
 		if (err)
 			return err;
 		break;
@@ -13626,13 +13649,17 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
 			meta->arg_btf_id = reg->btf_id;
 			break;
 		case KF_ARG_PTR_TO_CONST_STR:
-			if (reg->type != PTR_TO_MAP_VALUE) {
-				verbose(env, "arg#%d doesn't point to a const string\n", i);
-				return -EINVAL;
+			if (reg->type == PTR_TO_MAP_VALUE) {
+				ret = check_reg_const_str_in_map(env, reg, regno);
+				if (ret)
+					return ret;
+			} else {
+				ret = check_reg_const_str_arg(reg);
+				if (ret) {
+					verbose(env, "arg#%d doesn't point to a const string\n", i);
+					return ret;
+				}
 			}
-			ret = check_reg_const_str(env, reg, regno);
-			if (ret)
-				return ret;
 			break;
 		case KF_ARG_PTR_TO_WORKQUEUE:
 			if (reg->type != PTR_TO_MAP_VALUE) {
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH bpf-next 2/3] bpf: Add bpf_kern_path and bpf_path_put kfuncs
  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 ` Song Liu
  2025-11-30  4:23   ` Al Viro
  2025-11-27  0:50 ` [PATCH bpf-next 3/3] selftests/bpf: Add tests for bpf_kern_path kfunc Song Liu
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Song Liu @ 2025-11-27  0:50 UTC (permalink / raw)
  To: bpf, linux-fsdevel, linux-security-module
  Cc: ast, daniel, andrii, kernel-team, viro, brauner, jack, paul,
	jmorris, serge, Song Liu

Add two new kfuncs to fs/bpf_fs_kfuncs.c that wrap kern_path() for use
by BPF LSM programs:

bpf_kern_path():
- Resolves a pathname string to a struct path
- Allocates memory for the path structure
- Returns NULL on error or if the path doesn't exist
- Marked with KF_ACQUIRE | KF_SLEEPABLE | KF_RET_NULL

bpf_path_put():
- Releases the path reference and frees the allocated memory
- Marked with KF_RELEASE to enforce acquire/release semantics

These kfuncs enable BPF LSM programs to resolve pathnames provided by
hook arguments (e.g., dev_name from sb_mount) and validate or inspect
the resolved paths. The verifier enforces proper resource management
through acquire/release tracking.

Example usage:
  struct path *p = bpf_kern_path("/etc/passwd", LOOKUP_FOLLOW);
  if (p) {
      // Use the path...
      bpf_path_put(p);  // Must release
  }

Signed-off-by: Song Liu <song@kernel.org>
---
 fs/bpf_fs_kfuncs.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/fs/bpf_fs_kfuncs.c b/fs/bpf_fs_kfuncs.c
index 5ace2511fec5..977f8dcbc208 100644
--- a/fs/bpf_fs_kfuncs.c
+++ b/fs/bpf_fs_kfuncs.c
@@ -11,6 +11,7 @@
 #include <linux/file.h>
 #include <linux/kernfs.h>
 #include <linux/mm.h>
+#include <linux/namei.h>
 #include <linux/xattr.h>
 
 __bpf_kfunc_start_defs();
@@ -96,6 +97,61 @@ __bpf_kfunc int bpf_path_d_path(const struct path *path, char *buf, size_t buf__
 	return len;
 }
 
+/**
+ * bpf_kern_path - resolve a pathname to a struct path
+ * @pathname__str: pathname to resolve
+ * @flags: lookup flags (e.g., LOOKUP_FOLLOW)
+ *
+ * Resolve the pathname for the supplied *pathname__str* and return a pointer
+ * to a struct path. This is a wrapper around kern_path() that allocates and
+ * returns a struct path pointer on success.
+ *
+ * The returned struct path pointer must be released using bpf_path_put().
+ * Failing to call bpf_path_put() on the returned struct path pointer will
+ * result in the BPF program being rejected by the BPF verifier.
+ *
+ * This BPF kfunc may only be called from BPF LSM programs.
+ *
+ * Return: A pointer to an allocated struct path on success, NULL on error.
+ */
+__bpf_kfunc struct path *bpf_kern_path(const char *pathname__str, unsigned int flags)
+{
+	struct path *path;
+	int ret;
+
+	path = kmalloc(sizeof(*path), GFP_KERNEL);
+	if (!path)
+		return NULL;
+
+	ret = kern_path(pathname__str, flags, path);
+	if (ret) {
+		kfree(path);
+		return NULL;
+	}
+
+	return path;
+}
+
+/**
+ * bpf_path_put - release a struct path reference
+ * @path: struct path pointer to release
+ *
+ * Release the struct path pointer that was acquired by bpf_kern_path().
+ * This BPF kfunc calls path_put() on the supplied *path* and then frees
+ * the allocated memory.
+ *
+ * Only struct path pointers acquired by bpf_kern_path() may be passed to
+ * this BPF kfunc. Attempting to pass any other pointer will result in the
+ * BPF program being rejected by the BPF verifier.
+ *
+ * This BPF kfunc may only be called from BPF LSM programs.
+ */
+__bpf_kfunc void bpf_path_put(struct path *path)
+{
+	path_put(path);
+	kfree(path);
+}
+
 static bool match_security_bpf_prefix(const char *name__str)
 {
 	return !strncmp(name__str, XATTR_NAME_BPF_LSM, XATTR_NAME_BPF_LSM_LEN);
@@ -363,6 +419,8 @@ BTF_ID_FLAGS(func, bpf_get_task_exe_file,
 	     KF_ACQUIRE | KF_TRUSTED_ARGS | KF_RET_NULL)
 BTF_ID_FLAGS(func, bpf_put_file, KF_RELEASE)
 BTF_ID_FLAGS(func, bpf_path_d_path, KF_TRUSTED_ARGS)
+BTF_ID_FLAGS(func, bpf_kern_path, KF_TRUSTED_ARGS | KF_ACQUIRE | KF_SLEEPABLE | KF_RET_NULL)
+BTF_ID_FLAGS(func, bpf_path_put, KF_RELEASE)
 BTF_ID_FLAGS(func, bpf_get_dentry_xattr, KF_SLEEPABLE | KF_TRUSTED_ARGS)
 BTF_ID_FLAGS(func, bpf_get_file_xattr, KF_SLEEPABLE | KF_TRUSTED_ARGS)
 BTF_ID_FLAGS(func, bpf_set_dentry_xattr, KF_SLEEPABLE | KF_TRUSTED_ARGS)
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH bpf-next 3/3] selftests/bpf: Add tests for bpf_kern_path kfunc
  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-27  0:50 ` Song Liu
  2025-11-27  0:50 ` [PATCH bpf-next 0/3] Introduce bpf_kern_path and bpf_path_put Song Liu
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Song Liu @ 2025-11-27  0:50 UTC (permalink / raw)
  To: bpf, linux-fsdevel, linux-security-module
  Cc: ast, daniel, andrii, kernel-team, viro, brauner, jack, paul,
	jmorris, serge, Song Liu

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


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH bpf-next 0/3] Introduce bpf_kern_path and bpf_path_put
  2025-11-27  0:50 [PATCH bpf-next 0/3] Introduce bpf_kern_path and bpf_path_put Song Liu
                   ` (2 preceding siblings ...)
  2025-11-27  0:50 ` [PATCH bpf-next 3/3] selftests/bpf: Add tests for bpf_kern_path kfunc Song Liu
@ 2025-11-27  0:50 ` 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
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Song Liu @ 2025-11-27  0:50 UTC (permalink / raw)
  To: bpf, linux-fsdevel, linux-security-module
  Cc: ast, daniel, andrii, kernel-team, viro, brauner, jack, paul,
	jmorris, serge, Song Liu

Security solutions use LSM hook security_sb_mount to monitor mount
operations. security_sb_mount takes dev_name as a string. To get a struct
path from dev_name, in-tree LSMs use kern_path. Introduce kfuncs
bpf_kern_path so that bpf LSM can do similar operations. bpf_kern_path
takes a reference on the return value path. Also add kfunc bpf_path_put to
release path returned by bpf_kern_path. Note that, bpf_kern_path only holds
reference on the path during the duration of this bpf program. The verifier
enforces the bpf program release this reference.

Patch 1/3 prepares bpf verifier to handle const char * passed in as hook
argument. Before this change, bpf helpers and kfuncs only consider value
from read only map as const string.

Patch 2/3 adds the two kfuncs.

Patch 3/3 add tests for the new kfuncs.

Song Liu (3):
  bpf: Allow const char * from LSM hooks as kfunc const string arguments
  bpf: Add bpf_kern_path and bpf_path_put kfuncs
  selftests/bpf: Add tests for bpf_kern_path kfunc

 fs/bpf_fs_kfuncs.c                            | 58 +++++++++++
 include/linux/btf.h                           |  1 +
 kernel/bpf/btf.c                              | 33 +++++++
 kernel/bpf/verifier.c                         | 51 +++++++---
 .../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 +++++++++++++++++++
 9 files changed, 422 insertions(+), 12 deletions(-)
 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

--
2.47.3

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH bpf-next 1/3] bpf: Allow const char * from LSM hooks as kfunc const string arguments
  2025-11-27  0:50 [PATCH bpf-next 0/3] Introduce bpf_kern_path and bpf_path_put Song Liu
                   ` (3 preceding siblings ...)
  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 ` 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
  6 siblings, 1 reply; 13+ messages in thread
From: Song Liu @ 2025-11-27  0:50 UTC (permalink / raw)
  To: bpf, linux-fsdevel, linux-security-module
  Cc: ast, daniel, andrii, kernel-team, viro, brauner, jack, paul,
	jmorris, serge, Song Liu

Let the BPF verifier to recognize const char * arguments from LSM hooks
(and other BPF program types) as valid const string pointers that can be
passed to kfuncs expecting KF_ARG_PTR_TO_CONST_STR.

Previously, kfuncs with KF_ARG_PTR_TO_CONST_STR only accepted
PTR_TO_MAP_VALUE from readonly maps. This was limiting for LSM programs
that receive const char * arguments from hooks like sb_mount's dev_name.

Signed-off-by: Song Liu <song@kernel.org>
---
 include/linux/btf.h   |  1 +
 kernel/bpf/btf.c      | 33 ++++++++++++++++++++++++++++
 kernel/bpf/verifier.c | 51 +++++++++++++++++++++++++++++++++----------
 3 files changed, 73 insertions(+), 12 deletions(-)

diff --git a/include/linux/btf.h b/include/linux/btf.h
index f06976ffb63f..bd5a32d33254 100644
--- a/include/linux/btf.h
+++ b/include/linux/btf.h
@@ -224,6 +224,7 @@ struct btf *btf_base_btf(const struct btf *btf);
 bool btf_type_is_i32(const struct btf_type *t);
 bool btf_type_is_i64(const struct btf_type *t);
 bool btf_type_is_primitive(const struct btf_type *t);
+bool btf_type_is_const_char_ptr(const struct btf *btf, const struct btf_type *t);
 bool btf_member_is_reg_int(const struct btf *btf, const struct btf_type *s,
 			   const struct btf_member *m,
 			   u32 expected_offset, u32 expected_size);
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 0de8fc8a0e0b..94a272585b97 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -897,6 +897,25 @@ bool btf_type_is_primitive(const struct btf_type *t)
 	       btf_is_any_enum(t);
 }
 
+bool btf_type_is_const_char_ptr(const struct btf *btf, const struct btf_type *t)
+{
+	const char *tname;
+
+	/* The type chain has to be PTR->CONST->CHAR */
+	if (BTF_INFO_KIND(t->info) != BTF_KIND_PTR)
+		return false;
+
+	t = btf_type_by_id(btf, t->type);
+	if (BTF_INFO_KIND(t->info) != BTF_KIND_CONST)
+		return false;
+
+	t = btf_type_by_id(btf, t->type);
+	tname = btf_name_by_offset(btf, t->name_off);
+	if (tname && strcmp(tname, "char") == 0)
+		return true;
+	return false;
+}
+
 /*
  * Check that given struct member is a regular int with expected
  * offset and size.
@@ -6746,6 +6765,20 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
 			/* Default prog with MAX_BPF_FUNC_REG_ARGS args */
 			return true;
 		t = btf_type_by_id(btf, args[arg].type);
+
+		/*
+		 * For const string, we need to match "const char *"
+		 * exactly. Therefore, do the check before the skipping
+		 * modifiers.
+		 */
+		if (btf_type_is_const_char_ptr(btf, t)) {
+			info->reg_type = PTR_TO_BTF_ID;
+			if (prog_args_trusted(prog))
+				info->reg_type |= PTR_TRUSTED;
+			info->btf = btf;
+			info->btf_id = args[arg].type;
+			return true;
+		}
 	}
 
 	/* skip modifiers */
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 766695491bc5..a9757c056d4b 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -9598,8 +9598,12 @@ static enum bpf_dynptr_type dynptr_get_type(struct bpf_verifier_env *env,
 	return state->stack[spi].spilled_ptr.dynptr.type;
 }
 
-static int check_reg_const_str(struct bpf_verifier_env *env,
-			       struct bpf_reg_state *reg, u32 regno)
+/*
+ * Check for const string saved in a bpf map. The caller is responsible
+ * to check reg->type == PTR_TO_MAP_VALUE.
+ */
+static int check_reg_const_str_in_map(struct bpf_verifier_env *env,
+				      struct bpf_reg_state *reg, u32 regno)
 {
 	struct bpf_map *map = reg->map_ptr;
 	int err;
@@ -9607,9 +9611,6 @@ static int check_reg_const_str(struct bpf_verifier_env *env,
 	u64 map_addr;
 	char *str_ptr;
 
-	if (reg->type != PTR_TO_MAP_VALUE)
-		return -EINVAL;
-
 	if (!bpf_map_is_rdonly(map)) {
 		verbose(env, "R%d does not point to a readonly map'\n", regno);
 		return -EACCES;
@@ -9646,6 +9647,26 @@ static int check_reg_const_str(struct bpf_verifier_env *env,
 	return 0;
 }
 
+/* Check for const string passed in as input to the bpf program. */
+static int check_reg_const_str_arg(struct bpf_reg_state *reg)
+{
+	const struct btf *btf;
+	const struct btf_type *t;
+	const char *tname;
+
+	if (base_type(reg->type) != PTR_TO_BTF_ID)
+		return -EINVAL;
+
+	btf = reg->btf;
+	t = btf_type_by_id(btf, reg->btf_id);
+	if (!t)
+		return -EINVAL;
+
+	if (btf_type_is_const_char_ptr(btf, t))
+		return 0;
+	return -EINVAL;
+}
+
 /* Returns constant key value in `value` if possible, else negative error */
 static int get_constant_map_key(struct bpf_verifier_env *env,
 				struct bpf_reg_state *key,
@@ -9964,7 +9985,9 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
 		break;
 	case ARG_PTR_TO_CONST_STR:
 	{
-		err = check_reg_const_str(env, reg, regno);
+		if (reg->type != PTR_TO_MAP_VALUE)
+			return -EINVAL;
+		err = check_reg_const_str_in_map(env, reg, regno);
 		if (err)
 			return err;
 		break;
@@ -13626,13 +13649,17 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
 			meta->arg_btf_id = reg->btf_id;
 			break;
 		case KF_ARG_PTR_TO_CONST_STR:
-			if (reg->type != PTR_TO_MAP_VALUE) {
-				verbose(env, "arg#%d doesn't point to a const string\n", i);
-				return -EINVAL;
+			if (reg->type == PTR_TO_MAP_VALUE) {
+				ret = check_reg_const_str_in_map(env, reg, regno);
+				if (ret)
+					return ret;
+			} else {
+				ret = check_reg_const_str_arg(reg);
+				if (ret) {
+					verbose(env, "arg#%d doesn't point to a const string\n", i);
+					return ret;
+				}
 			}
-			ret = check_reg_const_str(env, reg, regno);
-			if (ret)
-				return ret;
 			break;
 		case KF_ARG_PTR_TO_WORKQUEUE:
 			if (reg->type != PTR_TO_MAP_VALUE) {
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH bpf-next 2/3] bpf: Add bpf_kern_path and bpf_path_put kfuncs
  2025-11-27  0:50 [PATCH bpf-next 0/3] Introduce bpf_kern_path and bpf_path_put Song Liu
                   ` (4 preceding siblings ...)
  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 ` Song Liu
  2025-11-27  0:50 ` [PATCH bpf-next 3/3] selftests/bpf: Add tests for bpf_kern_path kfunc Song Liu
  6 siblings, 0 replies; 13+ messages in thread
From: Song Liu @ 2025-11-27  0:50 UTC (permalink / raw)
  To: bpf, linux-fsdevel, linux-security-module
  Cc: ast, daniel, andrii, kernel-team, viro, brauner, jack, paul,
	jmorris, serge, Song Liu

Add two new kfuncs to fs/bpf_fs_kfuncs.c that wrap kern_path() for use
by BPF LSM programs:

bpf_kern_path():
- Resolves a pathname string to a struct path
- Allocates memory for the path structure
- Returns NULL on error or if the path doesn't exist
- Marked with KF_ACQUIRE | KF_SLEEPABLE | KF_RET_NULL

bpf_path_put():
- Releases the path reference and frees the allocated memory
- Marked with KF_RELEASE to enforce acquire/release semantics

These kfuncs enable BPF LSM programs to resolve pathnames provided by
hook arguments (e.g., dev_name from sb_mount) and validate or inspect
the resolved paths. The verifier enforces proper resource management
through acquire/release tracking.

Example usage:
  struct path *p = bpf_kern_path("/etc/passwd", LOOKUP_FOLLOW);
  if (p) {
      // Use the path...
      bpf_path_put(p);  // Must release
  }

Signed-off-by: Song Liu <song@kernel.org>
---
 fs/bpf_fs_kfuncs.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/fs/bpf_fs_kfuncs.c b/fs/bpf_fs_kfuncs.c
index 5ace2511fec5..977f8dcbc208 100644
--- a/fs/bpf_fs_kfuncs.c
+++ b/fs/bpf_fs_kfuncs.c
@@ -11,6 +11,7 @@
 #include <linux/file.h>
 #include <linux/kernfs.h>
 #include <linux/mm.h>
+#include <linux/namei.h>
 #include <linux/xattr.h>
 
 __bpf_kfunc_start_defs();
@@ -96,6 +97,61 @@ __bpf_kfunc int bpf_path_d_path(const struct path *path, char *buf, size_t buf__
 	return len;
 }
 
+/**
+ * bpf_kern_path - resolve a pathname to a struct path
+ * @pathname__str: pathname to resolve
+ * @flags: lookup flags (e.g., LOOKUP_FOLLOW)
+ *
+ * Resolve the pathname for the supplied *pathname__str* and return a pointer
+ * to a struct path. This is a wrapper around kern_path() that allocates and
+ * returns a struct path pointer on success.
+ *
+ * The returned struct path pointer must be released using bpf_path_put().
+ * Failing to call bpf_path_put() on the returned struct path pointer will
+ * result in the BPF program being rejected by the BPF verifier.
+ *
+ * This BPF kfunc may only be called from BPF LSM programs.
+ *
+ * Return: A pointer to an allocated struct path on success, NULL on error.
+ */
+__bpf_kfunc struct path *bpf_kern_path(const char *pathname__str, unsigned int flags)
+{
+	struct path *path;
+	int ret;
+
+	path = kmalloc(sizeof(*path), GFP_KERNEL);
+	if (!path)
+		return NULL;
+
+	ret = kern_path(pathname__str, flags, path);
+	if (ret) {
+		kfree(path);
+		return NULL;
+	}
+
+	return path;
+}
+
+/**
+ * bpf_path_put - release a struct path reference
+ * @path: struct path pointer to release
+ *
+ * Release the struct path pointer that was acquired by bpf_kern_path().
+ * This BPF kfunc calls path_put() on the supplied *path* and then frees
+ * the allocated memory.
+ *
+ * Only struct path pointers acquired by bpf_kern_path() may be passed to
+ * this BPF kfunc. Attempting to pass any other pointer will result in the
+ * BPF program being rejected by the BPF verifier.
+ *
+ * This BPF kfunc may only be called from BPF LSM programs.
+ */
+__bpf_kfunc void bpf_path_put(struct path *path)
+{
+	path_put(path);
+	kfree(path);
+}
+
 static bool match_security_bpf_prefix(const char *name__str)
 {
 	return !strncmp(name__str, XATTR_NAME_BPF_LSM, XATTR_NAME_BPF_LSM_LEN);
@@ -363,6 +419,8 @@ BTF_ID_FLAGS(func, bpf_get_task_exe_file,
 	     KF_ACQUIRE | KF_TRUSTED_ARGS | KF_RET_NULL)
 BTF_ID_FLAGS(func, bpf_put_file, KF_RELEASE)
 BTF_ID_FLAGS(func, bpf_path_d_path, KF_TRUSTED_ARGS)
+BTF_ID_FLAGS(func, bpf_kern_path, KF_TRUSTED_ARGS | KF_ACQUIRE | KF_SLEEPABLE | KF_RET_NULL)
+BTF_ID_FLAGS(func, bpf_path_put, KF_RELEASE)
 BTF_ID_FLAGS(func, bpf_get_dentry_xattr, KF_SLEEPABLE | KF_TRUSTED_ARGS)
 BTF_ID_FLAGS(func, bpf_get_file_xattr, KF_SLEEPABLE | KF_TRUSTED_ARGS)
 BTF_ID_FLAGS(func, bpf_set_dentry_xattr, KF_SLEEPABLE | KF_TRUSTED_ARGS)
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH bpf-next 3/3] selftests/bpf: Add tests for bpf_kern_path kfunc
  2025-11-27  0:50 [PATCH bpf-next 0/3] Introduce bpf_kern_path and bpf_path_put Song Liu
                   ` (5 preceding siblings ...)
  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 ` Song Liu
  6 siblings, 0 replies; 13+ messages in thread
From: Song Liu @ 2025-11-27  0:50 UTC (permalink / raw)
  To: bpf, linux-fsdevel, linux-security-module
  Cc: ast, daniel, andrii, kernel-team, viro, brauner, jack, paul,
	jmorris, serge, Song Liu

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


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH bpf-next 1/3] bpf: Allow const char * from LSM hooks as kfunc const string arguments
  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
  0 siblings, 0 replies; 13+ messages in thread
From: kernel test robot @ 2025-11-27 19:07 UTC (permalink / raw)
  To: Song Liu, bpf, linux-fsdevel, linux-security-module
  Cc: llvm, oe-kbuild-all, ast, daniel, andrii, kernel-team, viro,
	brauner, jack, paul, jmorris, serge, Song Liu

Hi Song,

kernel test robot noticed the following build warnings:

[auto build test WARNING on bpf-next/master]

url:    https://github.com/intel-lab-lkp/linux/commits/Song-Liu/bpf-Allow-const-char-from-LSM-hooks-as-kfunc-const-string-arguments/20251127-125352
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master
patch link:    https://lore.kernel.org/r/20251127005011.1872209-6-song%40kernel.org
patch subject: [PATCH bpf-next 1/3] bpf: Allow const char * from LSM hooks as kfunc const string arguments
config: loongarch-randconfig-001-20251127 (https://download.01.org/0day-ci/archive/20251128/202511280214.sckLyHDU-lkp@intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project b3428bb966f1de8aa48375ffee0eba04ede133b7)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251128/202511280214.sckLyHDU-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202511280214.sckLyHDU-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> kernel/bpf/verifier.c:9655:14: warning: unused variable 'tname' [-Wunused-variable]
    9655 |         const char *tname;
         |                     ^~~~~
   1 warning generated.


vim +/tname +9655 kernel/bpf/verifier.c

  9649	
  9650	/* Check for const string passed in as input to the bpf program. */
  9651	static int check_reg_const_str_arg(struct bpf_reg_state *reg)
  9652	{
  9653		const struct btf *btf;
  9654		const struct btf_type *t;
> 9655		const char *tname;
  9656	
  9657		if (base_type(reg->type) != PTR_TO_BTF_ID)
  9658			return -EINVAL;
  9659	
  9660		btf = reg->btf;
  9661		t = btf_type_by_id(btf, reg->btf_id);
  9662		if (!t)
  9663			return -EINVAL;
  9664	
  9665		if (btf_type_is_const_char_ptr(btf, t))
  9666			return 0;
  9667		return -EINVAL;
  9668	}
  9669	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH bpf-next 2/3] bpf: Add bpf_kern_path and bpf_path_put kfuncs
  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
  0 siblings, 1 reply; 13+ messages in thread
From: Al Viro @ 2025-11-30  4:23 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, linux-fsdevel, linux-security-module, ast, daniel, andrii,
	kernel-team, brauner, jack, paul, jmorris, serge

On Wed, Nov 26, 2025 at 04:50:06PM -0800, Song Liu wrote:
> Add two new kfuncs to fs/bpf_fs_kfuncs.c that wrap kern_path() for use
> by BPF LSM programs:
> 
> bpf_kern_path():
> - Resolves a pathname string to a struct path

> These kfuncs enable BPF LSM programs to resolve pathnames provided by
> hook arguments (e.g., dev_name from sb_mount) and validate or inspect
> the resolved paths. The verifier enforces proper resource management
> through acquire/release tracking.

Oh, *brilliant*.  Thank you for giving a wonderful example of the reasons
why this is fundamentally worthless.

OK, your "BPF LSM" has been called and it got that dev_name.  You decide
that you want to know what it resolves to (which, BTW, requries a really
non-trivial amount of parsing other arguments - just to figure out whether
it *is* a pathname of some sort).  Thanks to your shiny new kfuncs you
can do that!  You are a proud holder of mount/dentry pair.  You stare at
those and decide whether it's OK to go on.  Then you... drop that pair
and let mount(2) proceed towards the point where it will (if you parsed
the arguments correctly) repeat that pathname resolution and get a mount/dentry
pair of its own, that may very well be different from what you've got the
first time around.

Your primitive is a walking TOCTOU bug - it's impossible to use safely.

NAKed-by: Al Viro <viro@zeniv.linux.org.uk>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH bpf-next 2/3] bpf: Add bpf_kern_path and bpf_path_put kfuncs
  2025-11-30  4:23   ` Al Viro
@ 2025-11-30  5:57     ` Song Liu
  2025-11-30  6:46       ` Al Viro
  0 siblings, 1 reply; 13+ messages in thread
From: Song Liu @ 2025-11-30  5:57 UTC (permalink / raw)
  To: Al Viro
  Cc: bpf, linux-fsdevel, linux-security-module, ast, daniel, andrii,
	kernel-team, brauner, jack, paul, jmorris, serge, Shervin Oloumi

On Sat, Nov 29, 2025 at 8:23 PM Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> On Wed, Nov 26, 2025 at 04:50:06PM -0800, Song Liu wrote:
> > Add two new kfuncs to fs/bpf_fs_kfuncs.c that wrap kern_path() for use
> > by BPF LSM programs:
> >
> > bpf_kern_path():
> > - Resolves a pathname string to a struct path
>
> > These kfuncs enable BPF LSM programs to resolve pathnames provided by
> > hook arguments (e.g., dev_name from sb_mount) and validate or inspect
> > the resolved paths. The verifier enforces proper resource management
> > through acquire/release tracking.
>
> Oh, *brilliant*.  Thank you for giving a wonderful example of the reasons
> why this is fundamentally worthless.
>
> OK, your "BPF LSM" has been called and it got that dev_name.  You decide
> that you want to know what it resolves to (which, BTW, requries a really
> non-trivial amount of parsing other arguments - just to figure out whether
> it *is* a pathname of some sort).  Thanks to your shiny new kfuncs you
> can do that!  You are a proud holder of mount/dentry pair.  You stare at
> those and decide whether it's OK to go on.  Then you... drop that pair
> and let mount(2) proceed towards the point where it will (if you parsed
> the arguments correctly) repeat that pathname resolution and get a mount/dentry
> pair of its own, that may very well be different from what you've got the
> first time around.
>
> Your primitive is a walking TOCTOU bug - it's impossible to use safely.

Good point. AFAICT, the sample TOCTOU bug applies to other LSMs that
care about dev_name in sb_mount, namely, aa_bind_mount() for apparmor
and tomoyo_mount_acl() for tomoyo.

What would you recommend to do this properly? How about we add a new
LSM hook that works on the actual mount/dentry pair? Something like:

diff --git i/fs/namespace.c w/fs/namespace.c
index d82910f33dc4..3d5dc167f15f 100644
--- i/fs/namespace.c
+++ w/fs/namespace.c
@@ -2984,6 +2984,10 @@ static int do_loopback(const struct path *path,
const char *old_name,
        if (err)
                return err;

+       err = security_mount_loopback(old_path, path, recurse);
+       if (err)
+               return err;
+
        if (mnt_ns_loop(old_path.dentry))
                return -EINVAL;

(Or s/security_mount_loopback/some_other_name).

In other words, do you think we should go [1] by Shervin Oloumi?
CCing Shervin here.

We will also need something similar to cover move mount operation
via path_mount()=>do_move_mount_old()=>do_move_mount().

Thanks,
Song

[1] https://lore.kernel.org/linux-security-module/20250110021008.2704246-1-enlightened@chromium.org/

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH bpf-next 2/3] bpf: Add bpf_kern_path and bpf_path_put kfuncs
  2025-11-30  5:57     ` Song Liu
@ 2025-11-30  6:46       ` Al Viro
  2025-12-01  7:32         ` Song Liu
  0 siblings, 1 reply; 13+ messages in thread
From: Al Viro @ 2025-11-30  6:46 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, linux-fsdevel, linux-security-module, ast, daniel, andrii,
	kernel-team, brauner, jack, paul, jmorris, serge, Shervin Oloumi

On Sat, Nov 29, 2025 at 09:57:43PM -0800, Song Liu wrote:

> > Your primitive is a walking TOCTOU bug - it's impossible to use safely.
> 
> Good point. AFAICT, the sample TOCTOU bug applies to other LSMs that
> care about dev_name in sb_mount, namely, aa_bind_mount() for apparmor
> and tomoyo_mount_acl() for tomoyo.

sb_mount needs to be taken out of its misery; it makes very little sense
and it's certainly rife with TOCTOU issues.

What to replace it with is an interesting question, especially considering
how easy it is to bypass the damn thing with fsopen(), open_tree() and friends.

It certainly won't be a single hook; multiplexing thing aside, if
you look at e.g. loopback you'll see that there are two separate
operations involved - one is cloning a tree (that's where dev_name is
parsed in old API; the corresponding spot in the new one is open_tree()
with OPEN_TREE_CLONE in flags) and another - attaching that tree to
destination (move_mount(2) in the new API).

The former is "what", the latter - "where".  And in open_tree()/move_mount()
it literally could be done by different processes - there's no problem
with open_tree() in one process, passing the resulting descriptor to
another process that will attach it.

Any checks you do sb_mount (or in your mount_loopback) would have
to have equivalent counterparts in those, or you get an easy way to
bypass them.

That's a very unpleasant can of worms; if you want to open it, be my
guest, but I would seriously suggest doing that after the end of merge
window - and going over the existing LSMs to see what they are trying to
do in that area before starting that thread.  And yes, that's an example
of the reasons why I'm very sceptical about out-of-tree modules in
that area - with API in that state, we have no realistic way to promise
any kind of stability, with obvious consequences for everyone we can't
even see.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH bpf-next 2/3] bpf: Add bpf_kern_path and bpf_path_put kfuncs
  2025-11-30  6:46       ` Al Viro
@ 2025-12-01  7:32         ` Song Liu
  0 siblings, 0 replies; 13+ messages in thread
From: Song Liu @ 2025-12-01  7:32 UTC (permalink / raw)
  To: Al Viro
  Cc: bpf, linux-fsdevel, linux-security-module, ast, daniel, andrii,
	kernel-team, brauner, jack, paul, jmorris, serge, Shervin Oloumi

On Sat, Nov 29, 2025 at 10:46 PM Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> On Sat, Nov 29, 2025 at 09:57:43PM -0800, Song Liu wrote:
>
> > > Your primitive is a walking TOCTOU bug - it's impossible to use safely.
> >
> > Good point. AFAICT, the sample TOCTOU bug applies to other LSMs that
> > care about dev_name in sb_mount, namely, aa_bind_mount() for apparmor
> > and tomoyo_mount_acl() for tomoyo.
>
> sb_mount needs to be taken out of its misery; it makes very little sense
> and it's certainly rife with TOCTOU issues.
>
> What to replace it with is an interesting question, especially considering
> how easy it is to bypass the damn thing with fsopen(), open_tree() and friends.
>
> It certainly won't be a single hook; multiplexing thing aside, if
> you look at e.g. loopback you'll see that there are two separate
> operations involved - one is cloning a tree (that's where dev_name is
> parsed in old API; the corresponding spot in the new one is open_tree()
> with OPEN_TREE_CLONE in flags) and another - attaching that tree to
> destination (move_mount(2) in the new API).

We currently have security_move_mount(), security_sb_remount(), and
security_sb_kern_mount(), so most things are somewhat covered.

> The former is "what", the latter - "where".  And in open_tree()/move_mount()
> it literally could be done by different processes - there's no problem
> with open_tree() in one process, passing the resulting descriptor to
> another process that will attach it.

For open_tree, security_file_open() can cover the "what" part of it.

>
> Any checks you do sb_mount (or in your mount_loopback) would have
> to have equivalent counterparts in those, or you get an easy way to
> bypass them.
>
> That's a very unpleasant can of worms; if you want to open it, be my
> guest, but I would seriously suggest doing that after the end of merge
> window - and going over the existing LSMs to see what they are trying to
> do in that area before starting that thread.

I very much support fixing it properly, and I don't plan to rush into a
half broken workaround. I am not very optimistic about whether
we can bring everyone to the same page, but I think it is worth a try.

> And yes, that's an example
> of the reasons why I'm very sceptical about out-of-tree modules in
> that area - with API in that state, we have no realistic way to promise
> any kind of stability, with obvious consequences for everyone we can't
> even see.

I am not sure what you mean by "with API in that state". Which API
sets are you talking about: the LSM hooks, the BPF kfuncs in
bpf_fs_kfuncs.c, or all the exported symbols that are available to in-tree
and out-of-tree LSMs? And how would you suggest we make these
APIs into a better state?

Thanks,
Song

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2025-12-01  7:32 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [PATCH bpf-next 3/3] selftests/bpf: Add tests for bpf_kern_path kfunc Song Liu
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).