lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260119032424.10781-2-piliu@redhat.com>
Date: Mon, 19 Jan 2026 11:24:12 +0800
From: Pingfan Liu <piliu@...hat.com>
To: bpf@...r.kernel.org
Cc: Pingfan Liu <piliu@...hat.com>,
	"David S. Miller" <davem@...emloft.net>,
	Alexei Starovoitov <ast@...nel.org>,
	Daniel Borkmann <daniel@...earbox.net>,
	John Fastabend <john.fastabend@...il.com>,
	Andrii Nakryiko <andrii@...nel.org>,
	Martin KaFai Lau <martin.lau@...ux.dev>,
	Eduard Zingerman <eddyz87@...il.com>,
	Song Liu <song@...nel.org>,
	Yonghong Song <yonghong.song@...ux.dev>,
	Jeremy Linton <jeremy.linton@....com>,
	Catalin Marinas <catalin.marinas@....com>,
	Will Deacon <will@...nel.org>,
	Ard Biesheuvel <ardb@...nel.org>,
	Simon Horman <horms@...nel.org>,
	Gerd Hoffmann <kraxel@...hat.com>,
	Vitaly Kuznetsov <vkuznets@...hat.com>,
	Philipp Rudo <prudo@...hat.com>,
	Viktor Malik <vmalik@...hat.com>,
	Jan Hendrik Farr <kernel@...rr.cc>,
	Baoquan He <bhe@...hat.com>,
	Dave Young <dyoung@...hat.com>,
	Andrew Morton <akpm@...ux-foundation.org>,
	kexec@...ts.infradead.org,
	systemd-devel@...ts.freedesktop.org,
	linux-kernel@...r.kernel.org,
	KP Singh <kpsingh@...nel.org>,
	Stanislav Fomichev <sdf@...ichev.me>,
	Hao Luo <haoluo@...gle.com>,
	Jiri Olsa <jolsa@...nel.org>
Subject: [PATCHv6 01/13] bpf: Introduce kfuncs to parser buffer content

In the security kexec_file_load case, the buffer holding the kernel
image should not be accessible from userspace.

Typically, BPF data flow occurs between user space and kernel space in
either direction. However, the above case presents a unique scenario
where the kernel, instead of a user task, reads data from a file, passes
it to a BPF program for parsing, and finally stores the parsed result.

This requires a mechanism to channel the intermediate data from the BPF
program directly to the kernel. BPF buffer parser kfuncs are introduced
to serve this purpose:

    BTF_ID_FLAGS(func, bpf_get_parser_context, KF_ACQUIRE | KF_RET_NULL)
    BTF_ID_FLAGS(func, bpf_put_parser_context, KF_RELEASE)
    BTF_ID_FLAGS(func, bpf_buffer_parser, KF_TRUSTED_ARGS | KF_SLEEPABLE)

where bpf_get_parser_context() and bpf_put_parser_context() manage the
trusted argument, and bpf_buffer_parser() forwards data to a callback
that processes the structured buffer constructed by the BPF program.

Signed-off-by: Pingfan Liu <piliu@...hat.com>
Cc: Alexei Starovoitov <ast@...nel.org>
Cc: Daniel Borkmann <daniel@...earbox.net>
Cc: David S. Miller <davem@...emloft.net>
Cc: John Fastabend <john.fastabend@...il.com>
Cc: Andrii Nakryiko <andrii@...nel.org>
Cc: Martin KaFai Lau <martin.lau@...ux.dev>
Cc: Eduard Zingerman <eddyz87@...il.com>
Cc: Song Liu <song@...nel.org>
Cc: Yonghong Song <yonghong.song@...ux.dev>
Cc: KP Singh <kpsingh@...nel.org>
Cc: Stanislav Fomichev <sdf@...ichev.me>
Cc: Hao Luo <haoluo@...gle.com>
Cc: Jiri Olsa <jolsa@...nel.org>
To: bpf@...r.kernel.org
---
 include/linux/bpf.h            |  19 ++++
 kernel/bpf/Makefile            |   3 +
 kernel/bpf/bpf_buffer_parser.c | 170 +++++++++++++++++++++++++++++++++
 3 files changed, 192 insertions(+)
 create mode 100644 kernel/bpf/bpf_buffer_parser.c

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index e5be698256d15..25bc1b6b8a600 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -3843,4 +3843,23 @@ static inline int bpf_map_check_op_flags(struct bpf_map *map, u64 flags, u64 all
 	return 0;
 }
 
+struct bpf_parser_buf {
+	char *buf;
+	int size;
+};
+
+struct bpf_parser_context;
+typedef int (*bpf_parser_handler_t)(struct bpf_parser_context *ctx);
+
+struct bpf_parser_context {
+	struct kref ref;
+	struct hlist_node hash_node;
+	bpf_parser_handler_t func;
+	struct bpf_parser_buf *buf;
+	void *data;
+};
+
+struct bpf_parser_context *alloc_bpf_parser_context(bpf_parser_handler_t func,
+			void *data);
+void put_bpf_parser_context(struct bpf_parser_context *ctx);
 #endif /* _LINUX_BPF_H */
diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile
index 232cbc97434db..309b905a81736 100644
--- a/kernel/bpf/Makefile
+++ b/kernel/bpf/Makefile
@@ -56,6 +56,9 @@ obj-$(CONFIG_BPF_SYSCALL) += kmem_cache_iter.o
 ifeq ($(CONFIG_DMA_SHARED_BUFFER),y)
 obj-$(CONFIG_BPF_SYSCALL) += dmabuf_iter.o
 endif
+ifeq ($(CONFIG_KEXEC_BPF),y)
+obj-$(CONFIG_BPF_SYSCALL) += bpf_buffer_parser.o
+endif
 
 CFLAGS_REMOVE_percpu_freelist.o = $(CC_FLAGS_FTRACE)
 CFLAGS_REMOVE_bpf_lru_list.o = $(CC_FLAGS_FTRACE)
diff --git a/kernel/bpf/bpf_buffer_parser.c b/kernel/bpf/bpf_buffer_parser.c
new file mode 100644
index 0000000000000..6acb4b5da71b3
--- /dev/null
+++ b/kernel/bpf/bpf_buffer_parser.c
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/hashtable.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/vmalloc.h>
+#include <linux/bpf.h>
+
+#define BPF_CONTEXT_HASH_BITS 10
+
+static DEFINE_SPINLOCK(bpf_parser_context_lock);
+static DEFINE_HASHTABLE(bpf_parser_context_map, BPF_CONTEXT_HASH_BITS);
+
+/* Generate a simple hash key from pointer address */
+static inline unsigned int bpf_parser_context_hash_key(struct bpf_parser_context *ctx)
+{
+	return hash_ptr(ctx, BPF_CONTEXT_HASH_BITS);
+}
+
+static void release_bpf_parser_context(struct kref *kref)
+{
+	struct bpf_parser_context *ctx = container_of(kref, struct bpf_parser_context, ref);
+
+	if (!!ctx->buf) {
+		vfree(ctx->buf->buf);
+		kfree(ctx->buf);
+	}
+	spin_lock(&bpf_parser_context_lock);
+	hash_del(&ctx->hash_node);
+	spin_unlock(&bpf_parser_context_lock);
+	kfree(ctx);
+}
+
+struct bpf_parser_context *alloc_bpf_parser_context(bpf_parser_handler_t func,
+		void *data)
+{
+	struct bpf_parser_context *ctx;
+	unsigned int key;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return NULL;
+	ctx->func = func;
+	ctx->data = data;
+	kref_init(&ctx->ref);
+	key = bpf_parser_context_hash_key(ctx);
+	spin_lock(&bpf_parser_context_lock);
+	hash_add(bpf_parser_context_map, &ctx->hash_node, key);
+	spin_unlock(&bpf_parser_context_lock);
+
+	return ctx;
+}
+
+void put_bpf_parser_context(struct bpf_parser_context *ctx)
+{
+	if (!ctx)
+		return;
+	kref_put(&ctx->ref, release_bpf_parser_context);
+}
+
+static struct bpf_parser_context *find_bpf_parser_context(unsigned long id)
+{
+	struct bpf_parser_context *ctx;
+	unsigned int key;
+	int cnt;
+
+	key = bpf_parser_context_hash_key((struct bpf_parser_context *)id);
+	spin_lock(&bpf_parser_context_lock);
+	hash_for_each_possible(bpf_parser_context_map, ctx, hash_node, key) {
+		if (ctx == (struct bpf_parser_context *)id) {
+			cnt = kref_get_unless_zero(&ctx->ref);
+			if (!cnt)
+				ctx = NULL;
+			spin_unlock(&bpf_parser_context_lock);
+			return ctx;
+		}
+	}
+	spin_unlock(&bpf_parser_context_lock);
+
+	return NULL;
+}
+
+__bpf_kfunc_start_defs()
+
+__bpf_kfunc struct bpf_parser_context *bpf_get_parser_context(unsigned long id)
+{
+	struct bpf_parser_context *ctx;
+
+	ctx = find_bpf_parser_context(id);
+
+	return ctx;
+}
+
+__bpf_kfunc void bpf_put_parser_context(struct bpf_parser_context *ctx)
+{
+	put_bpf_parser_context(ctx);
+}
+
+__bpf_kfunc void bpf_parser_context_release_dtor(void *ctx)
+{
+	put_bpf_parser_context(ctx);
+}
+CFI_NOSEAL(bpf_parser_context_release_dtor);
+
+__bpf_kfunc int bpf_buffer_parser(char *buf, int buf_sz,
+		struct bpf_parser_context *context)
+{
+	struct bpf_parser_buf *parser_buf;
+	int ret;
+	char *b;
+
+	if (unlikely(context->func == NULL))
+		return -EINVAL;
+
+	b = __vmalloc(buf_sz, GFP_KERNEL_ACCOUNT | __GFP_ZERO);
+	if (!b)
+		return -ENOMEM;
+	ret = copy_from_kernel_nofault(b, buf, buf_sz);
+	if (!!ret) {
+		vfree(b);
+		return ret;
+	}
+
+	parser_buf = kmalloc(sizeof(struct bpf_parser_buf), GFP_KERNEL);
+	if (!parser_buf) {
+		vfree(b);
+		return -ENOMEM;
+	}
+	parser_buf->buf = b;
+	parser_buf->size = buf_sz;
+	context->buf = parser_buf;
+	ret = context->func(context);
+
+	return ret;
+}
+__bpf_kfunc_end_defs();
+
+BTF_KFUNCS_START(buffer_parser_ids)
+BTF_ID_FLAGS(func, bpf_get_parser_context, KF_ACQUIRE | KF_RET_NULL)
+BTF_ID_FLAGS(func, bpf_put_parser_context, KF_RELEASE)
+BTF_ID_FLAGS(func, bpf_buffer_parser, KF_TRUSTED_ARGS | KF_SLEEPABLE)
+BTF_KFUNCS_END(buffer_parser_ids)
+
+static const struct btf_kfunc_id_set buffer_parser_kfunc_set = {
+        .owner = THIS_MODULE,
+        .set   = &buffer_parser_ids,
+};
+
+
+BTF_ID_LIST(buffer_parser_dtor_ids)
+BTF_ID(struct, bpf_parser_context)
+BTF_ID(func, bpf_parser_context_release_dtor)
+
+static int __init buffer_parser_kfunc_init(void)
+{
+	int ret;
+	const struct btf_id_dtor_kfunc buffer_parser_dtors[] = {
+		{
+			.btf_id	      = buffer_parser_dtor_ids[0],
+			.kfunc_btf_id = buffer_parser_dtor_ids[1]
+		},
+	};
+
+	ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &buffer_parser_kfunc_set);
+	return  ret ?: register_btf_id_dtor_kfuncs(buffer_parser_dtors,
+						   ARRAY_SIZE(buffer_parser_dtors),
+						   THIS_MODULE);
+}
+
+late_initcall(buffer_parser_kfunc_init);
-- 
2.49.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ