From nobody Mon Feb 9 13:35:16 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2192424BBF4 for ; Mon, 19 Jan 2026 03:25:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768793134; cv=none; b=kS5p6yjJxKKXR2JC2I9XYu8RZq5TCwcI9MhWvJu8dyWGxA52nzm+QLKml7h2ntfZCB61OPmnBS2PmMhSxV1LycNmLyPB99xd6xtX4+HnmFlpORLjtqw4nG5Bv8RjSRMlOtNthU2smDr2rm/kyjJybfhvy4JJr94eyO7qGHNqQoI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768793134; c=relaxed/simple; bh=w61Zjy29wRsJz3cZu9F5CjXrYJPKyO7BCVnsWG/w14k=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Ua7d9Qz8MIuT1zPTFoXPnVnN8rnXngyWK34CKM9SEtuYXX24ZP2U1w3MCkXBCbzo8frqtNlYLtya7Flgs3F6Da2h/WzpYlCKqUFuR4dXI4LIJU81B7VjcawgNmqtMfvLLFEmSHHOlW4h5lSpK746r8iXoaDSHIEa2DMZ3hz1MrM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=XgAAuE6V; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="XgAAuE6V" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1768793132; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=o5aAmHphuaCuElIjD1nSE+54sJuhoN+zFArjQztPTzw=; b=XgAAuE6V0IO1NYIXjeoTUsYsddk3+zDU+YHlQD37kdAcq2bqwzLXhgGCM+or3MoxYS5U3t n9+/yL9ZlUDHLFZ5gn2D1bv5c/cT31e07vkqQbBRKZSEiFW98e3CA6aPZg74o4g9tGt+m0 mSFZepnqNnJng50sbnBe6scluyxG/Ks= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-103-BmTL6VVUNSi1MjAC_BE4Zg-1; Sun, 18 Jan 2026 22:25:29 -0500 X-MC-Unique: BmTL6VVUNSi1MjAC_BE4Zg-1 X-Mimecast-MFC-AGG-ID: BmTL6VVUNSi1MjAC_BE4Zg_1768793127 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id CE54C1954B0B; Mon, 19 Jan 2026 03:25:25 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.72.112.74]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 896FD195419F; Mon, 19 Jan 2026 03:25:12 +0000 (UTC) From: Pingfan Liu To: bpf@vger.kernel.org Cc: Pingfan Liu , "David S. Miller" , Alexei Starovoitov , Daniel Borkmann , John Fastabend , Andrii Nakryiko , Martin KaFai Lau , Eduard Zingerman , Song Liu , Yonghong Song , Jeremy Linton , Catalin Marinas , Will Deacon , Ard Biesheuvel , Simon Horman , Gerd Hoffmann , Vitaly Kuznetsov , Philipp Rudo , Viktor Malik , Jan Hendrik Farr , Baoquan He , Dave Young , Andrew Morton , kexec@lists.infradead.org, systemd-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, KP Singh , Stanislav Fomichev , Hao Luo , Jiri Olsa Subject: [PATCHv6 01/13] bpf: Introduce kfuncs to parser buffer content Date: Mon, 19 Jan 2026 11:24:12 +0800 Message-ID: <20260119032424.10781-2-piliu@redhat.com> In-Reply-To: <20260119032424.10781-1-piliu@redhat.com> References: <20260119032424.10781-1-piliu@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Content-Type: text/plain; charset="utf-8" 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 Cc: Alexei Starovoitov Cc: Daniel Borkmann Cc: David S. Miller Cc: John Fastabend Cc: Andrii Nakryiko Cc: Martin KaFai Lau Cc: Eduard Zingerman Cc: Song Liu Cc: Yonghong Song Cc: KP Singh Cc: Stanislav Fomichev Cc: Hao Luo Cc: Jiri Olsa To: bpf@vger.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; } =20 +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 f= unc, + 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) +=3D kmem_cache_iter.o ifeq ($(CONFIG_DMA_SHARED_BUFFER),y) obj-$(CONFIG_BPF_SYSCALL) +=3D dmabuf_iter.o endif +ifeq ($(CONFIG_KEXEC_BPF),y) +obj-$(CONFIG_BPF_SYSCALL) +=3D bpf_buffer_parser.o +endif =20 CFLAGS_REMOVE_percpu_freelist.o =3D $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_bpf_lru_list.o =3D $(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 +#include +#include +#include +#include +#include + +#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_c= ontext *ctx) +{ + return hash_ptr(ctx, BPF_CONTEXT_HASH_BITS); +} + +static void release_bpf_parser_context(struct kref *kref) +{ + struct bpf_parser_context *ctx =3D container_of(kref, struct bpf_parser_c= ontext, 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 f= unc, + void *data) +{ + struct bpf_parser_context *ctx; + unsigned int key; + + ctx =3D kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return NULL; + ctx->func =3D func; + ctx->data =3D data; + kref_init(&ctx->ref); + key =3D 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 =3D 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 =3D=3D (struct bpf_parser_context *)id) { + cnt =3D kref_get_unless_zero(&ctx->ref); + if (!cnt) + ctx =3D 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 lon= g id) +{ + struct bpf_parser_context *ctx; + + ctx =3D 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 =3D=3D NULL)) + return -EINVAL; + + b =3D __vmalloc(buf_sz, GFP_KERNEL_ACCOUNT | __GFP_ZERO); + if (!b) + return -ENOMEM; + ret =3D copy_from_kernel_nofault(b, buf, buf_sz); + if (!!ret) { + vfree(b); + return ret; + } + + parser_buf =3D kmalloc(sizeof(struct bpf_parser_buf), GFP_KERNEL); + if (!parser_buf) { + vfree(b); + return -ENOMEM; + } + parser_buf->buf =3D b; + parser_buf->size =3D buf_sz; + context->buf =3D parser_buf; + ret =3D 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 =3D { + .owner =3D THIS_MODULE, + .set =3D &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[] =3D { + { + .btf_id =3D buffer_parser_dtor_ids[0], + .kfunc_btf_id =3D buffer_parser_dtor_ids[1] + }, + }; + + ret =3D register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &buffer_parser_k= func_set); + return ret ?: register_btf_id_dtor_kfuncs(buffer_parser_dtors, + ARRAY_SIZE(buffer_parser_dtors), + THIS_MODULE); +} + +late_initcall(buffer_parser_kfunc_init); --=20 2.49.0