bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] BPF signature verification
@ 2025-05-28 21:49 Blaise Boscaccy
  2025-05-28 21:49 ` [PATCH 1/3] bpf: Add bpf_check_signature Blaise Boscaccy
                   ` (4 more replies)
  0 siblings, 5 replies; 25+ messages in thread
From: Blaise Boscaccy @ 2025-05-28 21:49 UTC (permalink / raw)
  To: Paul Moore, bboscaccy, jarkko, zeffron, xiyou.wangcong,
	kysrinivasan, code, linux-security-module, roberto.sassu,
	James.Bottomley, Alexei Starovoitov, Daniel Borkmann,
	John Fastabend, Andrii Nakryiko, Martin KaFai Lau,
	Eduard Zingerman, Song Liu, Yonghong Song, KP Singh,
	Stanislav Fomichev, Hao Luo, Jiri Olsa, David Howells,
	Lukas Wunner, Ignat Korchagin, Quentin Monnet, Jason Xing,
	Willem de Bruijn, Anton Protopopov, Jordan Rome, Martin Kelly,
	Alan Maguire, Matteo Croce, bpf, linux-kernel, keyrings,
	linux-crypto

As suggested or mandated by KP Singh
https://lore.kernel.org/linux-security-module/CACYkzJ6VQUExfyt0=-FmXz46GHJh3d=FXh5j4KfexcEFbHV-vg@mail.gmail.com/,
this patchset proposes and implements an alternative hash-chain
algorithm for signature verification of BPF programs.

This design diverges in two key ways:

1. Signature Strategy

Two different signature strategies are
implemented. One verifies only the signature of the loader program in
the kernel, as described in the link above. The other verifies the
program’s maps in-kernel via a hash chain.  The original design
required loader programs to be “self-aborting” and embedded the
terminal hash verification logic as metaprogramming code generation
routines inside libbpf. While this patchset supports that scheme, it
is considered undesirable in certain environments due to the potential
for supply-chain attack vectors and the lack of visibility for the LSM
subsystem.  Additionally, it is impossible to verify the code
performing the signature verification, as it is uniquely regenerated
for every program.

2. Timing of Signature Check

This patchset moves the signature check to a point before
security_bpf_prog_load is invoked, due to an unresolved discussion
here:
https://lore.kernel.org/linux-security-module/CAHC9VhTj3=ZXgrYMNA+G64zsOyZO+78uDs1g=kh91=GR5KypYg@mail.gmail.com/
This change allows the LSM subsystem to be informed of the signature
verification result—if it occurred—and the method used, all without
introducing a new hook. It improves visibility and auditability,
reducing the “trust me, friend” aspect of the original design.


Blaise Boscaccy (3):
  bpf: Add bpf_check_signature
  bpf: Support light-skeleton signatures in autogenerated code
  bpftool: Allow signing of light-skeleton programs

 include/linux/bpf.h            |   2 +
 include/linux/verification.h   |   1 +
 include/uapi/linux/bpf.h       |   4 +
 kernel/bpf/arraymap.c          |  11 +-
 kernel/bpf/syscall.c           | 123 +++++++++++++++++++-
 tools/bpf/bpftool/Makefile     |   4 +-
 tools/bpf/bpftool/common.c     | 204 +++++++++++++++++++++++++++++++++
 tools/bpf/bpftool/gen.c        |  66 ++++++++++-
 tools/bpf/bpftool/main.c       |  24 +++-
 tools/bpf/bpftool/main.h       |  23 ++++
 tools/include/uapi/linux/bpf.h |   4 +
 tools/lib/bpf/libbpf.h         |   4 +
 tools/lib/bpf/skel_internal.h  |  28 ++++-
 13 files changed, 491 insertions(+), 7 deletions(-)

-- 
2.48.1


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

* [PATCH 1/3] bpf: Add bpf_check_signature
  2025-05-28 21:49 [PATCH 0/3] BPF signature verification Blaise Boscaccy
@ 2025-05-28 21:49 ` Blaise Boscaccy
  2025-05-29 10:11   ` Lukas Wunner
                     ` (2 more replies)
  2025-05-28 21:49 ` [PATCH 2/3] bpf: Support light-skeleton signatures in autogenerated code Blaise Boscaccy
                   ` (3 subsequent siblings)
  4 siblings, 3 replies; 25+ messages in thread
From: Blaise Boscaccy @ 2025-05-28 21:49 UTC (permalink / raw)
  To: Paul Moore, bboscaccy, jarkko, zeffron, xiyou.wangcong,
	kysrinivasan, code, linux-security-module, roberto.sassu,
	James.Bottomley, Alexei Starovoitov, Daniel Borkmann,
	John Fastabend, Andrii Nakryiko, Martin KaFai Lau,
	Eduard Zingerman, Song Liu, Yonghong Song, KP Singh,
	Stanislav Fomichev, Hao Luo, Jiri Olsa, David Howells,
	Lukas Wunner, Ignat Korchagin, Quentin Monnet, Jason Xing,
	Willem de Bruijn, Anton Protopopov, Jordan Rome, Martin Kelly,
	Alan Maguire, Matteo Croce, bpf, linux-kernel, keyrings,
	linux-crypto

This introduces signature verification for eBPF programs inside of the
bpf subsystem. Two signature validation schemes are included, one that
only checks the instruction buffer, and another that checks over a
hash chain constructed from the program and a list of maps. The
alternative algorithm is designed to provide support to scenarios
where having self-aborting light-skeletons or signature checking
living outside the kernel-proper is insufficient or undesirable.

An abstract hash method is introduced to allow calculating the hash of
maps, only arrays are implemented at this time.

A simple UAPI is introduced to provide passing signature information.

The signature check is performed before the call to
security_bpf_prog_load. This allows the LSM subsystem to be clued into
the result of the signature check, whilst granting knowledge of the
method and apparatus which was employed.

Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com>
---
 include/linux/bpf.h            |   2 +
 include/linux/verification.h   |   1 +
 include/uapi/linux/bpf.h       |   4 ++
 kernel/bpf/arraymap.c          |  11 ++-
 kernel/bpf/syscall.c           | 123 ++++++++++++++++++++++++++++++++-
 tools/include/uapi/linux/bpf.h |   4 ++
 6 files changed, 143 insertions(+), 2 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 3f0cc89c0622..298e0db34c28 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -109,6 +109,7 @@ struct bpf_map_ops {
 	long (*map_pop_elem)(struct bpf_map *map, void *value);
 	long (*map_peek_elem)(struct bpf_map *map, void *value);
 	void *(*map_lookup_percpu_elem)(struct bpf_map *map, void *key, u32 cpu);
+	int (*map_get_hash)(struct bpf_map *map, u8 *out);
 
 	/* funcs called by prog_array and perf_event_array map */
 	void *(*map_fd_get_ptr)(struct bpf_map *map, struct file *map_file,
@@ -1592,6 +1593,7 @@ struct bpf_prog_aux {
 #ifdef CONFIG_SECURITY
 	void *security;
 #endif
+	bool signature_verified;
 	struct bpf_token *token;
 	struct bpf_prog_offload *offload;
 	struct btf *btf;
diff --git a/include/linux/verification.h b/include/linux/verification.h
index 4f3022d081c3..812be8ad5f74 100644
--- a/include/linux/verification.h
+++ b/include/linux/verification.h
@@ -35,6 +35,7 @@ enum key_being_used_for {
 	VERIFYING_KEXEC_PE_SIGNATURE,
 	VERIFYING_KEY_SIGNATURE,
 	VERIFYING_KEY_SELF_SIGNATURE,
+	VERIFYING_EBPF_SIGNATURE,
 	VERIFYING_UNSPECIFIED_SIGNATURE,
 	NR__KEY_BEING_USED_FOR
 };
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index fd404729b115..f79af999c480 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -1587,6 +1587,10 @@ union bpf_attr {
 		 * continuous.
 		 */
 		__u32		fd_array_cnt;
+		__aligned_u64	signature;	/* program signature */
+		__u32		signature_size;	/* size of program signature */
+		__aligned_u64	signature_maps;	/* maps used in signature */
+		__u32		signature_maps_size;	/* size of maps used in signature */
 	};
 
 	struct { /* anonymous struct used by BPF_OBJ_* commands */
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index eb28c0f219ee..5459ab6bf6e2 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -12,6 +12,7 @@
 #include <uapi/linux/btf.h>
 #include <linux/rcupdate_trace.h>
 #include <linux/btf_ids.h>
+#include <crypto/sha2.h>
 
 #include "map_in_map.h"
 
@@ -426,6 +427,14 @@ static long array_map_delete_elem(struct bpf_map *map, void *key)
 	return -EINVAL;
 }
 
+static int array_map_get_hash(struct bpf_map *map, u8 *out)
+{
+	struct bpf_array *array = container_of(map, struct bpf_array, map);
+
+	sha256(array->value, array->elem_size * array->map.max_entries, out);
+	return 0;
+}
+
 static void *array_map_vmalloc_addr(struct bpf_array *array)
 {
 	return (void *)round_down((unsigned long)array, PAGE_SIZE);
@@ -792,6 +801,7 @@ const struct bpf_map_ops array_map_ops = {
 	.map_lookup_elem = array_map_lookup_elem,
 	.map_update_elem = array_map_update_elem,
 	.map_delete_elem = array_map_delete_elem,
+	.map_get_hash = array_map_get_hash,
 	.map_gen_lookup = array_map_gen_lookup,
 	.map_direct_value_addr = array_map_direct_value_addr,
 	.map_direct_value_meta = array_map_direct_value_meta,
@@ -940,7 +950,6 @@ static long fd_array_map_delete_elem(struct bpf_map *map, void *key)
 {
 	return __fd_array_map_delete_elem(map, key, true);
 }
-
 static void *prog_fd_array_get_ptr(struct bpf_map *map,
 				   struct file *map_file, int fd)
 {
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 64c3393e8270..7dc35681d3f8 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -36,6 +36,8 @@
 #include <linux/memcontrol.h>
 #include <linux/trace_events.h>
 #include <linux/tracepoint.h>
+#include <crypto/pkcs7.h>
+#include <crypto/sha2.h>
 
 #include <net/netfilter/nf_bpf_link.h>
 #include <net/netkit.h>
@@ -2216,6 +2218,15 @@ static int map_freeze(const union bpf_attr *attr)
 	return err;
 }
 
+static int __map_get_hash(struct bpf_map *map, u8 *out)
+{
+	if (map->ops->map_get_hash) {
+		map->ops->map_get_hash(map, out);
+		return 0;
+	}
+	return -EINVAL;
+}
+
 static const struct bpf_prog_ops * const bpf_prog_types[] = {
 #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) \
 	[_id] = & _name ## _prog_ops,
@@ -2753,8 +2764,113 @@ static bool is_perfmon_prog_type(enum bpf_prog_type prog_type)
 	}
 }
 
+static int bpf_check_signature(struct bpf_prog *prog, union bpf_attr *attr, bpfptr_t uattr,
+			       __u32 uattr_size)
+{
+	u64 hash[4];
+	u64 buffer[8];
+	int err;
+	char *signature;
+	int *used_maps;
+	int n;
+	int map_fd;
+	struct bpf_map *map;
+
+	if (!attr->signature)
+		return 0;
+
+	signature = kmalloc(attr->signature_size, GFP_KERNEL);
+	if (!signature) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	if (copy_from_bpfptr(signature,
+			     make_bpfptr(attr->signature, uattr.is_kernel),
+			     attr->signature_size) != 0) {
+		err = -EINVAL;
+		goto free_sig;
+	}
+
+	if (!attr->signature_maps_size) {
+		sha256((u8 *)prog->insnsi, prog->len * sizeof(struct bpf_insn), (u8 *)&hash);
+		err = verify_pkcs7_signature(hash, sizeof(hash), signature, attr->signature_size,
+				     VERIFY_USE_SECONDARY_KEYRING,
+				     VERIFYING_EBPF_SIGNATURE,
+				     NULL, NULL);
+	} else {
+		used_maps = kmalloc_array(attr->signature_maps_size,
+					  sizeof(*used_maps), GFP_KERNEL);
+		if (!used_maps) {
+			err = -ENOMEM;
+			goto free_sig;
+		}
+		n = attr->signature_maps_size;
+		n--;
+
+		err = copy_from_bpfptr_offset(&map_fd, make_bpfptr(attr->fd_array, uattr.is_kernel),
+					      used_maps[n] * sizeof(map_fd),
+					      sizeof(map_fd));
+		if (err < 0)
+			goto free_maps;
+
+		/* calculate the terminal hash */
+		CLASS(fd, f)(map_fd);
+		map = __bpf_map_get(f);
+		if (IS_ERR(map)) {
+			err = PTR_ERR(map);
+			goto free_maps;
+		}
+		if (__map_get_hash(map, (u8 *)hash)) {
+			err = -EINVAL;
+			goto free_maps;
+		}
+
+		n--;
+		/* calculate a link in the hash chain */
+		while (n >= 0) {
+			memcpy(buffer, hash, sizeof(hash));
+			err = copy_from_bpfptr_offset(&map_fd,
+						      make_bpfptr(attr->fd_array, uattr.is_kernel),
+						      used_maps[n] * sizeof(map_fd),
+						      sizeof(map_fd));
+			if (err < 0)
+				goto free_maps;
+
+			CLASS(fd, f)(map_fd);
+			map = __bpf_map_get(f);
+			if (!map) {
+				err = -EINVAL;
+				goto free_maps;
+			}
+			if (__map_get_hash(map, (u8 *)buffer+4)) {
+				err = -EINVAL;
+				goto free_maps;
+			}
+			sha256((u8 *)buffer, sizeof(buffer), (u8 *)&hash);
+			n--;
+		}
+		/* calculate the root hash and verify it's signature */
+		sha256((u8 *)prog->insnsi, prog->len * sizeof(struct bpf_insn), (u8 *)&buffer);
+		memcpy(buffer+4, hash, sizeof(hash));
+		sha256((u8 *)buffer, sizeof(buffer), (u8 *)&hash);
+		err = verify_pkcs7_signature(hash, sizeof(hash), signature, attr->signature_size,
+				     VERIFY_USE_SECONDARY_KEYRING,
+				     VERIFYING_EBPF_SIGNATURE,
+				     NULL, NULL);
+free_maps:
+		kfree(used_maps);
+	}
+
+free_sig:
+	kfree(signature);
+out:
+	prog->aux->signature_verified = !err;
+	return err;
+}
+
 /* last field in 'union bpf_attr' used by this command */
-#define BPF_PROG_LOAD_LAST_FIELD fd_array_cnt
+#define BPF_PROG_LOAD_LAST_FIELD signature_maps_size
 
 static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
 {
@@ -2963,6 +3079,11 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
 	if (err < 0)
 		goto free_prog;
 
+	/* run eBPF signature verifier */
+	err = bpf_check_signature(prog, attr, uattr, uattr_size);
+	if (err < 0)
+		goto free_prog;
+
 	err = security_bpf_prog_load(prog, attr, token, uattr.is_kernel);
 	if (err)
 		goto free_prog_sec;
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index fd404729b115..f79af999c480 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -1587,6 +1587,10 @@ union bpf_attr {
 		 * continuous.
 		 */
 		__u32		fd_array_cnt;
+		__aligned_u64	signature;	/* program signature */
+		__u32		signature_size;	/* size of program signature */
+		__aligned_u64	signature_maps;	/* maps used in signature */
+		__u32		signature_maps_size;	/* size of maps used in signature */
 	};
 
 	struct { /* anonymous struct used by BPF_OBJ_* commands */
-- 
2.48.1


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

* [PATCH 2/3] bpf: Support light-skeleton signatures in autogenerated code
  2025-05-28 21:49 [PATCH 0/3] BPF signature verification Blaise Boscaccy
  2025-05-28 21:49 ` [PATCH 1/3] bpf: Add bpf_check_signature Blaise Boscaccy
@ 2025-05-28 21:49 ` Blaise Boscaccy
  2025-05-28 21:49 ` [PATCH 3/3] bpftool: Allow signing of light-skeleton programs Blaise Boscaccy
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 25+ messages in thread
From: Blaise Boscaccy @ 2025-05-28 21:49 UTC (permalink / raw)
  To: Paul Moore, bboscaccy, jarkko, zeffron, xiyou.wangcong,
	kysrinivasan, code, linux-security-module, roberto.sassu,
	James.Bottomley, Alexei Starovoitov, Daniel Borkmann,
	John Fastabend, Andrii Nakryiko, Martin KaFai Lau,
	Eduard Zingerman, Song Liu, Yonghong Song, KP Singh,
	Stanislav Fomichev, Hao Luo, Jiri Olsa, David Howells,
	Lukas Wunner, Ignat Korchagin, Quentin Monnet, Jason Xing,
	Willem de Bruijn, Anton Protopopov, Jordan Rome, Martin Kelly,
	Alan Maguire, Matteo Croce, bpf, linux-kernel, keyrings,
	linux-crypto

This adds optional signature UAPI support to lskels. Additionally map
freezing support is added as well.

Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com>
---
 tools/lib/bpf/skel_internal.h | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/tools/lib/bpf/skel_internal.h b/tools/lib/bpf/skel_internal.h
index 4d5fa079b5d6..106103b1edc7 100644
--- a/tools/lib/bpf/skel_internal.h
+++ b/tools/lib/bpf/skel_internal.h
@@ -61,8 +61,12 @@ struct bpf_load_and_run_opts {
 	struct bpf_loader_ctx *ctx;
 	const void *data;
 	const void *insns;
+	const void *signature;
+	const void *signature_maps;
 	__u32 data_sz;
 	__u32 insns_sz;
+	__u32 signature_sz;
+	__u32 signature_maps_sz;
 	const char *errstr;
 };
 
@@ -263,6 +267,17 @@ static inline int skel_map_delete_elem(int fd, const void *key)
 	return skel_sys_bpf(BPF_MAP_DELETE_ELEM, &attr, attr_sz);
 }
 
+static inline int skel_map_freeze(int fd)
+{
+	const size_t attr_sz = offsetofend(union bpf_attr, map_fd);
+	union bpf_attr attr;
+
+	memset(&attr, 0, attr_sz);
+	attr.map_fd = fd;
+
+	return skel_sys_bpf(BPF_MAP_FREEZE, &attr, attr_sz);
+}
+
 static inline int skel_map_get_fd_by_id(__u32 id)
 {
 	const size_t attr_sz = offsetofend(union bpf_attr, flags);
@@ -308,7 +323,7 @@ static inline int skel_link_create(int prog_fd, int target_fd,
 
 static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
 {
-	const size_t prog_load_attr_sz = offsetofend(union bpf_attr, fd_array);
+	const size_t prog_load_attr_sz = offsetofend(union bpf_attr, signature_maps_size);
 	const size_t test_run_attr_sz = offsetofend(union bpf_attr, test);
 	int map_fd = -1, prog_fd = -1, key = 0, err;
 	union bpf_attr attr;
@@ -327,6 +342,13 @@ static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
 		goto out;
 	}
 
+	err = skel_map_freeze(map_fd);
+	if (err < 0) {
+		opts->errstr = "failed to freeze map";
+		set_err;
+		goto out;
+	}
+
 	memset(&attr, 0, prog_load_attr_sz);
 	attr.prog_type = BPF_PROG_TYPE_SYSCALL;
 	attr.insns = (long) opts->insns;
@@ -338,6 +360,10 @@ static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
 	attr.log_size = opts->ctx->log_size;
 	attr.log_buf = opts->ctx->log_buf;
 	attr.prog_flags = BPF_F_SLEEPABLE;
+	attr.signature = (long) opts->signature;
+	attr.signature_size = opts->signature_sz;
+	attr.signature_maps = (long) opts->signature_maps;
+	attr.signature_maps_size = opts->signature_maps_sz;
 	err = prog_fd = skel_sys_bpf(BPF_PROG_LOAD, &attr, prog_load_attr_sz);
 	if (prog_fd < 0) {
 		opts->errstr = "failed to load loader prog";
-- 
2.48.1


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

* [PATCH 3/3] bpftool: Allow signing of light-skeleton programs
  2025-05-28 21:49 [PATCH 0/3] BPF signature verification Blaise Boscaccy
  2025-05-28 21:49 ` [PATCH 1/3] bpf: Add bpf_check_signature Blaise Boscaccy
  2025-05-28 21:49 ` [PATCH 2/3] bpf: Support light-skeleton signatures in autogenerated code Blaise Boscaccy
@ 2025-05-28 21:49 ` Blaise Boscaccy
  2025-05-30 16:42 ` [PATCH 0/3] BPF signature verification KP Singh
  2025-06-04 16:22 ` Jarkko Sakkinen
  4 siblings, 0 replies; 25+ messages in thread
From: Blaise Boscaccy @ 2025-05-28 21:49 UTC (permalink / raw)
  To: Paul Moore, bboscaccy, jarkko, zeffron, xiyou.wangcong,
	kysrinivasan, code, linux-security-module, roberto.sassu,
	James.Bottomley, Alexei Starovoitov, Daniel Borkmann,
	John Fastabend, Andrii Nakryiko, Martin KaFai Lau,
	Eduard Zingerman, Song Liu, Yonghong Song, KP Singh,
	Stanislav Fomichev, Hao Luo, Jiri Olsa, David Howells,
	Lukas Wunner, Ignat Korchagin, Quentin Monnet, Jason Xing,
	Willem de Bruijn, Anton Protopopov, Jordan Rome, Martin Kelly,
	Alan Maguire, Matteo Croce, bpf, linux-kernel, keyrings,
	linux-crypto

This introduces hash-chain signature support into bpftool. The
signature generated code was adapted from sign-file and follows a
similar set of command line switches.  The algorithm used here
supports the signature of both the loader program and it's map
containing the target program.

Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com>
---
 tools/bpf/bpftool/Makefile |   4 +-
 tools/bpf/bpftool/common.c | 204 +++++++++++++++++++++++++++++++++++++
 tools/bpf/bpftool/gen.c    |  66 +++++++++++-
 tools/bpf/bpftool/main.c   |  24 ++++-
 tools/bpf/bpftool/main.h   |  23 +++++
 tools/lib/bpf/libbpf.h     |   4 +
 6 files changed, 321 insertions(+), 4 deletions(-)

diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile
index 9e9a5f006cd2..b17e295f4954 100644
--- a/tools/bpf/bpftool/Makefile
+++ b/tools/bpf/bpftool/Makefile
@@ -130,8 +130,8 @@ include $(FEATURES_DUMP)
 endif
 endif
 
-LIBS = $(LIBBPF) -lelf -lz
-LIBS_BOOTSTRAP = $(LIBBPF_BOOTSTRAP) -lelf -lz
+LIBS = $(LIBBPF) -lelf -lz -lcrypto
+LIBS_BOOTSTRAP = $(LIBBPF_BOOTSTRAP) -lelf -lz -lcrypto
 
 ifeq ($(feature-libelf-zstd),1)
 LIBS += -lzstd
diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c
index ecfa790adc13..e6cfb855fc8a 100644
--- a/tools/bpf/bpftool/common.c
+++ b/tools/bpf/bpftool/common.c
@@ -5,6 +5,7 @@
 #define _GNU_SOURCE
 #endif
 #include <ctype.h>
+#include <err.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <ftw.h>
@@ -31,6 +32,24 @@
 #include <bpf/libbpf.h> /* libbpf_num_possible_cpus */
 #include <bpf/btf.h>
 
+#include <openssl/opensslv.h>
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#include <openssl/cms.h>
+#if OPENSSL_VERSION_MAJOR >= 3
+# define USE_PKCS11_PROVIDER
+# include <openssl/provider.h>
+# include <openssl/store.h>
+#else
+# if !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_DEPRECATED_3_0)
+#  define USE_PKCS11_ENGINE
+#  include <openssl/engine.h>
+# endif
+#endif
+#include "../../scripts/ssl-common.h"
+
 #include "main.h"
 
 #ifndef BPF_FS_MAGIC
@@ -1181,3 +1200,188 @@ int pathname_concat(char *buf, int buf_sz, const char *path,
 
 	return 0;
 }
+
+static const char *key_pass;
+
+static int pem_pw_cb(char *buf, int len, int w, void *v)
+{
+	int pwlen;
+
+	if (!key_pass)
+		return -1;
+
+	pwlen = strlen(key_pass);
+	if (pwlen >= len)
+		return -1;
+
+	strcpy(buf, key_pass);
+
+	/* If it's wrong, don't keep trying it. */
+	key_pass = NULL;
+
+	return pwlen;
+}
+
+static EVP_PKEY *read_private_key_pkcs11(const char *private_key_name)
+{
+	EVP_PKEY *pk = NULL;
+#ifdef USE_PKCS11_PROVIDER
+	OSSL_STORE_CTX *store;
+
+	if (!OSSL_PROVIDER_try_load(NULL, "pkcs11", true))
+		ERR(1, "OSSL_PROVIDER_try_load(pkcs11)");
+	if (!OSSL_PROVIDER_try_load(NULL, "default", true))
+		ERR(1, "OSSL_PROVIDER_try_load(default)");
+
+	store = OSSL_STORE_open(private_key_name, NULL, NULL, NULL, NULL);
+	ERR(!store, "OSSL_STORE_open");
+
+	while (!OSSL_STORE_eof(store)) {
+		OSSL_STORE_INFO *info = OSSL_STORE_load(store);
+
+		if (!info) {
+			drain_openssl_errors(__LINE__, 0);
+			continue;
+		}
+		if (OSSL_STORE_INFO_get_type(info) == OSSL_STORE_INFO_PKEY) {
+			pk = OSSL_STORE_INFO_get1_PKEY(info);
+			ERR(!pk, "OSSL_STORE_INFO_get1_PKEY");
+		}
+		OSSL_STORE_INFO_free(info);
+		if (pk)
+			break;
+	}
+	OSSL_STORE_close(store);
+#elif defined(USE_PKCS11_ENGINE)
+	ENGINE *e;
+
+	ENGINE_load_builtin_engines();
+	drain_openssl_errors(__LINE__, 1);
+	e = ENGINE_by_id("pkcs11");
+	ERR(!e, "Load PKCS#11 ENGINE");
+	if (ENGINE_init(e))
+		drain_openssl_errors(__LINE__, 1);
+	else
+		ERR(1, "ENGINE_init");
+	if (key_pass)
+		ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN");
+	pk = ENGINE_load_private_key(e, private_key_name, NULL, NULL);
+	ERR(!pk, "%s", private_key_name);
+#else
+	fprintf(stderr, "no pkcs11 engine/provider available\n");
+	exit(1);
+#endif
+	return pk;
+}
+
+EVP_PKEY *read_private_key(const char *private_key_name)
+{
+	if (!strncmp(private_key_name, "pkcs11:", 7)) {
+		return read_private_key_pkcs11(private_key_name);
+	} else {
+		EVP_PKEY *pk;
+		BIO *b;
+
+		b = BIO_new_file(private_key_name, "rb");
+		ERR(!b, "%s", private_key_name);
+		pk = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb,
+					     NULL);
+		ERR(!pk, "%s", private_key_name);
+		BIO_free(b);
+
+		return pk;
+	}
+}
+
+X509 *read_x509(const char *x509_name)
+{
+	unsigned char buf[2];
+	X509 *x509_cert;
+	BIO *b;
+	int n;
+
+	b = BIO_new_file(x509_name, "rb");
+	ERR(!b, "%s", x509_name);
+
+	/* Look at the first two bytes of the file to determine the encoding */
+	n = BIO_read(b, buf, 2);
+	if (n != 2) {
+		if (BIO_should_retry(b)) {
+			fprintf(stderr, "%s: Read wanted retry\n", x509_name);
+			exit(1);
+		}
+		if (n >= 0) {
+			fprintf(stderr, "%s: Short read\n", x509_name);
+			exit(1);
+		}
+		ERR(1, "%s", x509_name);
+	}
+
+	ERR(BIO_reset(b) != 0, "%s", x509_name);
+
+	if (buf[0] == 0x30 && buf[1] >= 0x81 && buf[1] <= 0x84)
+		/* Assume raw DER encoded X.509 */
+		x509_cert = d2i_X509_bio(b, NULL);
+	else
+		/* Assume PEM encoded X.509 */
+		x509_cert = PEM_read_bio_X509(b, NULL, NULL, NULL);
+
+	BIO_free(b);
+	ERR(!x509_cert, "%s", x509_name);
+
+	return x509_cert;
+}
+
+BIO* generate_signature(const void *buffer, size_t length)
+{
+	const EVP_MD *digest_algo;
+	unsigned int use_signed_attrs;
+#ifndef USE_PKCS7
+	CMS_ContentInfo *cms = NULL;
+	unsigned int use_keyid = 0;
+#else
+	PKCS7 *pkcs7 = NULL;
+#endif
+	BIO *mem = BIO_new_mem_buf(buffer, length);
+	BIO *bd = BIO_new(BIO_s_mem());
+
+#ifndef USE_PKCS7
+	use_signed_attrs = CMS_NOATTR;
+#else
+	use_signed_attrs = PKCS7_NOATTR;
+#endif
+	/* Digest the module data. */
+	OpenSSL_add_all_digests();
+	drain_openssl_errors(__LINE__, 0);
+	digest_algo = EVP_get_digestbyname(hash_algo);
+	ERR(!digest_algo, "EVP_get_digestbyname");
+
+#ifndef USE_PKCS7
+	/* Load the signature message from the digest buffer. */
+	cms = CMS_sign(NULL, NULL, NULL, NULL,
+		       CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY |
+		       CMS_DETACHED | CMS_STREAM);
+	ERR(!cms, "CMS_sign");
+
+	ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo,
+			     CMS_NOCERTS | CMS_BINARY |
+			     CMS_NOSMIMECAP | use_keyid |
+			     use_signed_attrs),
+	    "CMS_add1_signer");
+	ERR(CMS_final(cms, mem, NULL, CMS_NOCERTS | CMS_BINARY) != 1,
+	    "CMS_final");
+
+#else
+	pkcs7 = PKCS7_sign(x509, private_key, NULL, mem,
+			   PKCS7_NOCERTS | PKCS7_BINARY |
+			   PKCS7_DETACHED | use_signed_attrs);
+	ERR(!pkcs7, "PKCS7_sign");
+#endif
+
+#ifndef USE_PKCS7
+	ERR(i2d_CMS_bio_stream(bd, cms, NULL, 0) != 1, "%s", "bpftool");
+#else
+	ERR(i2d_PKCS7_bio(bd, pkcs7) != 1, "%s", "bpftool");
+#endif
+	return bd;
+}
diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c
index 67a60114368f..318b1f36d869 100644
--- a/tools/bpf/bpftool/gen.c
+++ b/tools/bpf/bpftool/gen.c
@@ -20,6 +20,7 @@
 #include <sys/stat.h>
 #include <sys/mman.h>
 #include <bpf/btf.h>
+#include <openssl/sha.h>
 
 #include "json_writer.h"
 #include "main.h"
@@ -493,6 +494,30 @@ static size_t bpf_map_mmap_sz(const struct bpf_map *map)
 	return map_sz;
 }
 
+static int sign_loader_and_map(struct gen_loader_opts *opts)
+{
+	BIO *bo;
+	BUF_MEM *bptr;
+	unsigned char hash[SHA256_DIGEST_LENGTH  * 2];
+	unsigned char term[SHA256_DIGEST_LENGTH];
+
+	if (!x509)
+		return 0;
+
+	SHA256((const unsigned char *)opts->insns, opts->insns_sz, hash);
+	SHA256((const unsigned char *)opts->data, opts->data_sz, hash + SHA256_DIGEST_LENGTH);
+	SHA256(hash, sizeof(hash), term);
+
+	bo = generate_signature(term, sizeof(term));
+	if (IS_ERR(bo))
+		return -EINVAL;
+	BIO_get_mem_ptr(bo, &bptr);
+	opts->signature = bptr->data;
+	opts->signature_sz = bptr->length;
+
+	return 0;
+}
+
 /* Emit type size asserts for all top-level fields in memory-mapped internal maps. */
 static void codegen_asserts(struct bpf_object *obj, const char *obj_name)
 {
@@ -701,6 +726,11 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
 		p_err("failed to load object file");
 		goto out;
 	}
+	err = sign_loader_and_map(&opts);
+	if (err) {
+		p_err("failed to sign loader");
+		goto out;
+	}
 	/* If there was no error during load then gen_loader_opts
 	 * are populated with the loader program.
 	 */
@@ -778,20 +808,54 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
 			static const char opts_insn[] __attribute__((__aligned__(8))) = \"\\\n\
 		");
 	print_hex(opts.insns, opts.insns_sz);
-	codegen("\
+	if (opts.signature) {
+		codegen("\
 		\n\
 		\";							    \n\
+			static const char opts_signature[] __attribute__((__aligned__(8))) = \"\\\n\
+		");
+		print_hex(opts.signature, opts.signature_sz);
+		codegen("\
+		\n\
+		\";							    \n\
+			static const int opts_signature_maps[1] __attribute__((__aligned__(8))) = {0}; \n\
+		");
+		codegen("\
+		\n\
 									    \n\
 			opts.ctx = (struct bpf_loader_ctx *)skel;	    \n\
 			opts.data_sz = sizeof(opts_data) - 1;		    \n\
 			opts.data = (void *)opts_data;			    \n\
 			opts.insns_sz = sizeof(opts_insn) - 1;		    \n\
 			opts.insns = (void *)opts_insn;			    \n\
+			opts.signature_sz = sizeof(opts_signature) - 1;	    \n\
+			opts.signature = (void *)opts_signature;	    \n\
+			opts.signature_maps_sz = 1;	                    \n\
+			opts.signature_maps = (void *)opts_signature_maps;  \n\
 									    \n\
 			err = bpf_load_and_run(&opts);			    \n\
 			if (err < 0)					    \n\
 				return err;				    \n\
 		");
+
+	} else {
+		codegen("\
+		\n\
+		\";							    \n\
+									    \n\
+			opts.ctx = (struct bpf_loader_ctx *)skel;	    \n\
+			opts.data_sz = sizeof(opts_data) - 1;		    \n\
+			opts.data = (void *)opts_data;			    \n\
+			opts.insns_sz = sizeof(opts_insn) - 1;		    \n\
+			opts.insns = (void *)opts_insn;			    \n\
+			opts.signature_sz  = 0;		                    \n\
+			opts.signature = NULL;			            \n\
+									    \n\
+			err = bpf_load_and_run(&opts);			    \n\
+			if (err < 0)					    \n\
+				return err;				    \n\
+		");
+	}
 	bpf_object__for_each_map(map, obj) {
 		const char *mmap_flags;
 
diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c
index cd5963cb6058..01020e5f37c2 100644
--- a/tools/bpf/bpftool/main.c
+++ b/tools/bpf/bpftool/main.c
@@ -33,6 +33,9 @@ bool relaxed_maps;
 bool use_loader;
 struct btf *base_btf;
 struct hashmap *refs_table;
+const char *hash_algo;
+EVP_PKEY *private_key;
+X509 *x509;
 
 static void __noreturn clean_and_exit(int i)
 {
@@ -473,7 +476,7 @@ int main(int argc, char **argv)
 	bin_name = "bpftool";
 
 	opterr = 0;
-	while ((opt = getopt_long(argc, argv, "VhpjfLmndB:l",
+	while ((opt = getopt_long(argc, argv, "VhpjfLmndB:lH:lP:lX:l",
 				  options, NULL)) >= 0) {
 		switch (opt) {
 		case 'V':
@@ -519,6 +522,25 @@ int main(int argc, char **argv)
 		case 'L':
 			use_loader = true;
 			break;
+		case 'H':
+			hash_algo = optarg;
+			break;
+		case 'P':
+			private_key = read_private_key(optarg);
+			if (!private_key) {
+				p_err("failed to parse private key '%s': %d\n",
+				      optarg, -errno);
+				return -1;
+			}
+			break;
+		case 'X':
+			x509 = read_x509(optarg);
+			if (!x509) {
+				p_err("failed to parse x509 '%s': %d\n",
+				      optarg, -errno);
+				return -1;
+			}
+			break;
 		default:
 			p_err("unrecognized option '%s'", argv[optind - 1]);
 			if (json_output)
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 9eb764fe4cc8..2f4aee1a8da7 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -16,6 +16,22 @@
 #include <bpf/hashmap.h>
 #include <bpf/libbpf.h>
 
+#include <openssl/opensslv.h>
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#if OPENSSL_VERSION_MAJOR >= 3
+# define USE_PKCS11_PROVIDER
+# include <openssl/provider.h>
+# include <openssl/store.h>
+#else
+# if !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_DEPRECATED_3_0)
+#  define USE_PKCS11_ENGINE
+#  include <openssl/engine.h>
+# endif
+#endif
+
 #include "json_writer.h"
 
 /* Make sure we do not use kernel-only integer typedefs */
@@ -84,6 +100,9 @@ extern bool relaxed_maps;
 extern bool use_loader;
 extern struct btf *base_btf;
 extern struct hashmap *refs_table;
+extern const char *hash_algo;
+extern EVP_PKEY *private_key;
+extern X509 *x509;
 
 void __printf(1, 2) p_err(const char *fmt, ...);
 void __printf(1, 2) p_info(const char *fmt, ...);
@@ -271,4 +290,8 @@ int pathname_concat(char *buf, int buf_sz, const char *path,
 /* print netfilter bpf_link info */
 void netfilter_dump_plain(const struct bpf_link_info *info);
 void netfilter_dump_json(const struct bpf_link_info *info, json_writer_t *wtr);
+
+X509 *read_x509(const char *x509_name);
+EVP_PKEY *read_private_key(const char *private_key_name);
+BIO *generate_signature(const void *buffer, size_t length);
 #endif
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index e0605403f977..c6c67e8931a6 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -1782,8 +1782,12 @@ struct gen_loader_opts {
 	size_t sz; /* size of this struct, for forward/backward compatibility */
 	const char *data;
 	const char *insns;
+	const char *signature;
+	const int *signature_maps;
 	__u32 data_sz;
 	__u32 insns_sz;
+	__u32 signature_sz;
+	__u32 signature_maps_sz;
 };
 
 #define gen_loader_opts__last_field insns_sz
-- 
2.48.1


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

* Re: [PATCH 1/3] bpf: Add bpf_check_signature
  2025-05-28 21:49 ` [PATCH 1/3] bpf: Add bpf_check_signature Blaise Boscaccy
@ 2025-05-29 10:11   ` Lukas Wunner
  2025-05-29 15:32     ` Blaise Boscaccy
  2025-06-02 22:40   ` Paul Moore
  2025-06-04 16:25   ` Jarkko Sakkinen
  2 siblings, 1 reply; 25+ messages in thread
From: Lukas Wunner @ 2025-05-29 10:11 UTC (permalink / raw)
  To: Blaise Boscaccy
  Cc: Paul Moore, jarkko, zeffron, xiyou.wangcong, kysrinivasan, code,
	linux-security-module, roberto.sassu, James.Bottomley,
	Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	David Howells, Ignat Korchagin, Quentin Monnet, Jason Xing,
	Willem de Bruijn, Anton Protopopov, Jordan Rome, Martin Kelly,
	Alan Maguire, Matteo Croce, bpf, linux-kernel, keyrings,
	linux-crypto

On Wed, May 28, 2025 at 02:49:03PM -0700, Blaise Boscaccy wrote:
> +	if (!attr->signature_maps_size) {
> +		sha256((u8 *)prog->insnsi, prog->len * sizeof(struct bpf_insn), (u8 *)&hash);
> +		err = verify_pkcs7_signature(hash, sizeof(hash), signature, attr->signature_size,
> +				     VERIFY_USE_SECONDARY_KEYRING,
> +				     VERIFYING_EBPF_SIGNATURE,
> +				     NULL, NULL);

Has this ever been tested?

It looks like it will always return -EINVAL because:

  verify_pkcs7_signature()
    verify_pkcs7_message_sig()
      pkcs7_verify()

... pkcs7_verify() contains a switch statement which you're not
amending with a "case VERIFYING_EBPF_SIGNATURE" but which returns
-EINVAL in the "default" case.

Aside from that, you may want to consider introducing a new ".ebpf"
keyring to allow adding trusted keys specifically for eBPF verification
without having to rely on the system keyring.

Constraining oneself to sha256 doesn't seem future-proof.

Some minor style issues in the commit message caught my eye:

> This introduces signature verification for eBPF programs inside of the
> bpf subsystem. Two signature validation schemes are included, one that

Use imperative mood, avoid repetitive "This ...", e.g.
"Introduce signature verification of eBPF programs..."

> The signature check is performed before the call to
> security_bpf_prog_load. This allows the LSM subsystem to be clued into
> the result of the signature check, whilst granting knowledge of the
> method and apparatus which was employed.

"Perform the signature check before calling security_bpf_prog_load()
to allow..."

Thanks,

Lukas

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

* Re: [PATCH 1/3] bpf: Add bpf_check_signature
  2025-05-29 10:11   ` Lukas Wunner
@ 2025-05-29 15:32     ` Blaise Boscaccy
  2025-05-29 19:31       ` Lukas Wunner
  0 siblings, 1 reply; 25+ messages in thread
From: Blaise Boscaccy @ 2025-05-29 15:32 UTC (permalink / raw)
  To: Lukas Wunner
  Cc: Paul Moore, jarkko, zeffron, xiyou.wangcong, kysrinivasan, code,
	linux-security-module, roberto.sassu, James.Bottomley,
	Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	David Howells, Ignat Korchagin, Quentin Monnet, Jason Xing,
	Willem de Bruijn, Anton Protopopov, Jordan Rome, Martin Kelly,
	Alan Maguire, Matteo Croce, bpf, linux-kernel, keyrings,
	linux-crypto

Lukas Wunner <lukas@wunner.de> writes:

> On Wed, May 28, 2025 at 02:49:03PM -0700, Blaise Boscaccy wrote:
>> +	if (!attr->signature_maps_size) {
>> +		sha256((u8 *)prog->insnsi, prog->len * sizeof(struct bpf_insn), (u8 *)&hash);
>> +		err = verify_pkcs7_signature(hash, sizeof(hash), signature, attr->signature_size,
>> +				     VERIFY_USE_SECONDARY_KEYRING,
>> +				     VERIFYING_EBPF_SIGNATURE,
>> +				     NULL, NULL);
>
> Has this ever been tested?
>
> It looks like it will always return -EINVAL because:
>
>   verify_pkcs7_signature()
>     verify_pkcs7_message_sig()
>       pkcs7_verify()
>
> ... pkcs7_verify() contains a switch statement which you're not
> amending with a "case VERIFYING_EBPF_SIGNATURE" but which returns
> -EINVAL in the "default" case.
>

Looks like I missed a commit when sending this patchset. Thanks for
finding that. 

> Aside from that, you may want to consider introducing a new ".ebpf"
> keyring to allow adding trusted keys specifically for eBPF verification
> without having to rely on the system keyring.
>
> Constraining oneself to sha256 doesn't seem future-proof.
>

Definitely not a bad idea, curious, how would you envision that looking
from an UAPI perspective? 

> Some minor style issues in the commit message caught my eye:
>
>> This introduces signature verification for eBPF programs inside of the
>> bpf subsystem. Two signature validation schemes are included, one that
>
> Use imperative mood, avoid repetitive "This ...", e.g.
> "Introduce signature verification of eBPF programs..."
>
>> The signature check is performed before the call to
>> security_bpf_prog_load. This allows the LSM subsystem to be clued into
>> the result of the signature check, whilst granting knowledge of the
>> method and apparatus which was employed.
>
> "Perform the signature check before calling security_bpf_prog_load()
> to allow..."
>
> Thanks,
>
> Lukas

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

* Re: [PATCH 1/3] bpf: Add bpf_check_signature
  2025-05-29 15:32     ` Blaise Boscaccy
@ 2025-05-29 19:31       ` Lukas Wunner
  2025-05-29 19:36         ` James Bottomley
  0 siblings, 1 reply; 25+ messages in thread
From: Lukas Wunner @ 2025-05-29 19:31 UTC (permalink / raw)
  To: Blaise Boscaccy
  Cc: Paul Moore, jarkko, zeffron, xiyou.wangcong, kysrinivasan, code,
	linux-security-module, roberto.sassu, James.Bottomley,
	Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	David Howells, Ignat Korchagin, Quentin Monnet, Jason Xing,
	Willem de Bruijn, Anton Protopopov, Jordan Rome, Martin Kelly,
	Alan Maguire, Matteo Croce, bpf, linux-kernel, keyrings,
	linux-crypto

On Thu, May 29, 2025 at 08:32:43AM -0700, Blaise Boscaccy wrote:
> Lukas Wunner <lukas@wunner.de> writes:
> > Constraining oneself to sha256 doesn't seem future-proof.
> 
> Definitely not a bad idea, curious, how would you envision that looking
> from an UAPI perspective?

If possible, extend the anonymous struct used by BPF_PROG_LOAD command
with an additional parameter to select the hash algorithm.

Alternatively, create a new command to set the hash algorithm for
subsequent BPF_PROG_LOAD commands.

Use enum hash_algo in include/uapi/linux/hash_info.h to encode the
selected algorithm.  You don't need to support all of these
(some of them are deprecated), but at least the sha3 and possibly
sha2 family is a good idea.

Note that CNSA 2.0 has raised the minimum approved hash size to
384 bits both for sha2 and sha3 in light of PQC:

https://www.fortanix.com/blog/which-post-quantum-cryptography-pqc-algorithm-should-i-use

https://media.defense.gov/2022/Sep/07/2003071836/-1/-1/0/CSI_CNSA_2.0_FAQ_.PDF

Granted, there's no mainline support for PQC signature algorithms yet,
but there's at least one out-of-tree implementation, it's only a question
of when not if something like this is submitted for mainline:

https://github.com/smuellerDD/leancrypto

Thanks,

Lukas

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

* Re: [PATCH 1/3] bpf: Add bpf_check_signature
  2025-05-29 19:31       ` Lukas Wunner
@ 2025-05-29 19:36         ` James Bottomley
  0 siblings, 0 replies; 25+ messages in thread
From: James Bottomley @ 2025-05-29 19:36 UTC (permalink / raw)
  To: Lukas Wunner, Blaise Boscaccy
  Cc: Paul Moore, jarkko, zeffron, xiyou.wangcong, kysrinivasan, code,
	linux-security-module, roberto.sassu, Alexei Starovoitov,
	Daniel Borkmann, John Fastabend, Andrii Nakryiko,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa, David Howells,
	Ignat Korchagin, Quentin Monnet, Jason Xing, Willem de Bruijn,
	Anton Protopopov, Jordan Rome, Martin Kelly, Alan Maguire,
	Matteo Croce, bpf, linux-kernel, keyrings, linux-crypto

On Thu, 2025-05-29 at 21:31 +0200, Lukas Wunner wrote:
> On Thu, May 29, 2025 at 08:32:43AM -0700, Blaise Boscaccy wrote:
> > Lukas Wunner <lukas@wunner.de> writes:
> > > Constraining oneself to sha256 doesn't seem future-proof.
> > 
> > Definitely not a bad idea, curious, how would you envision that
> > looking from an UAPI perspective?
> 
> If possible, extend the anonymous struct used by BPF_PROG_LOAD
> command with an additional parameter to select the hash algorithm.
> 
> Alternatively, create a new command to set the hash algorithm for
> subsequent BPF_PROG_LOAD commands.

Both of those look like less than good ideas.  There's not much point
having a hash that's different from the hash used in the signature
(which is currently sha256), so we could simply extract the hash from
the PKCS7 bundle and use that.  We can also get bonus points this way
for not modifying any internal APIs ...

Regards,

James


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

* Re: [PATCH 0/3] BPF signature verification
  2025-05-28 21:49 [PATCH 0/3] BPF signature verification Blaise Boscaccy
                   ` (2 preceding siblings ...)
  2025-05-28 21:49 ` [PATCH 3/3] bpftool: Allow signing of light-skeleton programs Blaise Boscaccy
@ 2025-05-30 16:42 ` KP Singh
  2025-05-30 20:14   ` Paul Moore
  2025-05-30 21:19   ` Blaise Boscaccy
  2025-06-04 16:22 ` Jarkko Sakkinen
  4 siblings, 2 replies; 25+ messages in thread
From: KP Singh @ 2025-05-30 16:42 UTC (permalink / raw)
  To: Blaise Boscaccy
  Cc: Paul Moore, jarkko, zeffron, xiyou.wangcong, kysrinivasan, code,
	linux-security-module, roberto.sassu, James.Bottomley,
	Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	David Howells, Lukas Wunner, Ignat Korchagin, Quentin Monnet,
	Jason Xing, Willem de Bruijn, Anton Protopopov, Jordan Rome,
	Martin Kelly, Alan Maguire, Matteo Croce, bpf, linux-kernel,
	keyrings, linux-crypto, kys

On Wed, May 28, 2025 at 11:50 PM Blaise Boscaccy
<bboscaccy@linux.microsoft.com> wrote:
>
> As suggested or mandated by KP Singh
> https://lore.kernel.org/linux-security-module/CACYkzJ6VQUExfyt0=-FmXz46GHJh3d=FXh5j4KfexcEFbHV-vg@mail.gmail.com/,
> this patchset proposes and implements an alternative hash-chain
> algorithm for signature verification of BPF programs.
>
>
>
> This design diverges in two key ways:
>
> 1. Signature Strategy
>
> Two different signature strategies are
> implemented. One verifies only the signature of the loader program in
> the kernel, as described in the link above. The other verifies the
> program’s maps in-kernel via a hash chain.  The original design
> required loader programs to be “self-aborting” and embedded the
> terminal hash verification logic as metaprogramming code generation
> routines inside libbpf. While this patchset supports that scheme, it
> is considered undesirable in certain environments due to the potential
> for supply-chain attack vectors and the lack of visibility for the LSM

The loader program is signed by a trusted entity, If you trust the
signature, then you trust it to do the signature verification. This is
a fairly common pattern in security and a pattern that we will be
using in other signed bpf use-cases which can choose to depend on
signed loaders.

If your build environment that signs the BPF program is compromised
and can inject arbitrary code, then signing does not help.  Can you
explain what a supply chain attack would look like here?

> subsystem.  Additionally, it is impossible to verify the code
> performing the signature verification, as it is uniquely regenerated

The LSM needs to ensure that it allows trusted LOADER programs i.e.
with signatures and potentially trusted signed user-space binaries
with unsigned or delegated signing (this will be needed for Cilium and
bpftrace that dynamically generate BPF programs), that's a more
important aspect of the LSM policy from a BPF perspective.

MAP_EXCLUSIVE is missing and is required which prevents maps from
being accessed by other programs as explained in the proposal.

Please hold off on further iterations, I am working on a series and
will share these patches based on the design that was proposed.

>
> for every program.
>
>
>
> 2. Timing of Signature Check
>
> This patchset moves the signature check to a point before
> security_bpf_prog_load is invoked, due to an unresolved discussion
> here:

This is fine and what I had in mind, signature verification does not
need to happen in the verifier and the existing hooks are good enough.
I did not reply to Paul's comment since this is a fairly trivial
detail and would be obvious in the implementation that the verifier is
not the right place to check the signature anyways as the instruction
buffer is only stable pre-verification.

> https://lore.kernel.org/linux-security-module/CAHC9VhTj3=ZXgrYMNA+G64zsOyZO+78uDs1g=kh91=GR5KypYg@mail.gmail.com/
> This change allows the LSM subsystem to be informed of the signature
> verification result—if it occurred—and the method used, all without
> introducing a new hook. It improves visibility and auditability,
> reducing the “trust me, friend” aspect of the original design.


On Wed, May 28, 2025 at 11:50 PM Blaise Boscaccy
<bboscaccy@linux.microsoft.com> wrote:
>
> As suggested or mandated by KP Singh
> https://lore.kernel.org/linux-security-module/CACYkzJ6VQUExfyt0=-FmXz46GHJh3d=FXh5j4KfexcEFbHV-vg@mail.gmail.com/,
> this patchset proposes and implements an alternative hash-chain
> algorithm for signature verification of BPF programs.
>
> This design diverges in two key ways:
>
> 1. Signature Strategy
>
> Two different signature strategies are
> implemented. One verifies only the signature of the loader program in
> the kernel, as described in the link above. The other verifies the
> program’s maps in-kernel via a hash chain.  The original design
> required loader programs to be “self-aborting” and embedded the
> terminal hash verification logic as metaprogramming code generation
> routines inside libbpf. While this patchset supports that scheme, it
> is considered undesirable in certain environments due to the potential
> for supply-chain attack vectors and the lack of visibility for the LSM
> subsystem.  Additionally, it is impossible to verify the code
> performing the signature verification, as it is uniquely regenerated
> for every program.
>
> 2. Timing of Signature Check
>
> This patchset moves the signature check to a point before
> security_bpf_prog_load is invoked, due to an unresolved discussion
> here:
> https://lore.kernel.org/linux-security-module/CAHC9VhTj3=ZXgrYMNA+G64zsOyZO+78uDs1g=kh91=GR5KypYg@mail.gmail.com/
> This change allows the LSM subsystem to be informed of the signature
> verification result—if it occurred—and the method used, all without
> introducing a new hook. It improves visibility and auditability,
> reducing the “trust me, friend” aspect of the original design.
>
>
> Blaise Boscaccy (3):
>   bpf: Add bpf_check_signature
>   bpf: Support light-skeleton signatures in autogenerated code
>   bpftool: Allow signing of light-skeleton programs
>
>  include/linux/bpf.h            |   2 +
>  include/linux/verification.h   |   1 +
>  include/uapi/linux/bpf.h       |   4 +
>  kernel/bpf/arraymap.c          |  11 +-
>  kernel/bpf/syscall.c           | 123 +++++++++++++++++++-
>  tools/bpf/bpftool/Makefile     |   4 +-
>  tools/bpf/bpftool/common.c     | 204 +++++++++++++++++++++++++++++++++
>  tools/bpf/bpftool/gen.c        |  66 ++++++++++-
>  tools/bpf/bpftool/main.c       |  24 +++-
>  tools/bpf/bpftool/main.h       |  23 ++++
>  tools/include/uapi/linux/bpf.h |   4 +
>  tools/lib/bpf/libbpf.h         |   4 +
>  tools/lib/bpf/skel_internal.h  |  28 ++++-
>  13 files changed, 491 insertions(+), 7 deletions(-)
>
> --
> 2.48.1
>

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

* Re: [PATCH 0/3] BPF signature verification
  2025-05-30 16:42 ` [PATCH 0/3] BPF signature verification KP Singh
@ 2025-05-30 20:14   ` Paul Moore
  2025-05-30 20:44     ` KP Singh
  2025-05-30 21:19   ` Blaise Boscaccy
  1 sibling, 1 reply; 25+ messages in thread
From: Paul Moore @ 2025-05-30 20:14 UTC (permalink / raw)
  To: KP Singh
  Cc: Blaise Boscaccy, jarkko, zeffron, xiyou.wangcong, kysrinivasan,
	code, linux-security-module, roberto.sassu, James.Bottomley,
	Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	David Howells, Lukas Wunner, Ignat Korchagin, Quentin Monnet,
	Jason Xing, Willem de Bruijn, Anton Protopopov, Jordan Rome,
	Martin Kelly, Alan Maguire, Matteo Croce, bpf, linux-kernel,
	keyrings, linux-crypto, kys

On Fri, May 30, 2025 at 12:42 PM KP Singh <kpsingh@kernel.org> wrote:
> On Wed, May 28, 2025 at 11:50 PM Blaise Boscaccy
> <bboscaccy@linux.microsoft.com> wrote:

...

> Please hold off on further iterations, I am working on a series and
> will share these patches based on the design that was proposed.

I don't think there is any harm in Blaise continuing his work in this
area, especially as he seems to be making reasonable progress towards
a solution that satisfies everyone's needs.  Considering all of the
work that Blaise has already invested in this, and his continued
willingness to try to work with everyone in the community to converge
on a solution, wouldn't it be more beneficial to work with Blaise on
further developing/refining his patchset instead of posting a parallel
effort?  It's your call of course, I'm not going to tell you, or
anyone else, to refrain from posting patches upstream, but it seems
like this is a good opportunity to help foster the development of a
new contributor.

> > 2. Timing of Signature Check
> >
> > This patchset moves the signature check to a point before
> > security_bpf_prog_load is invoked, due to an unresolved discussion
> > here:
>
> This is fine and what I had in mind, signature verification does not
> need to happen in the verifier and the existing hooks are good enough.

Excellent, I'm glad we can agree on the relative placement of the
signature verification and the LSM hook.  Perhaps I misunderstood your
design idea, but I took your comment:

"The signature check in the verifier (during BPF_PROG_LOAD):

 verify_pkcs7_signature(prog->aux->sha, sizeof(prog->aux->sha),
   sig_from_bpf_attr, …);"

https://lore.kernel.org/linux-security-module/CACYkzJ6VQUExfyt0=-FmXz46GHJh3d=FXh5j4KfexcEFbHV-vg@mail.gmail.com/

... to mean that the PKCS7 signature verification was going to happen
*in* the verifier, with the verifier being bpf_check().  Simply for my
own education, if bpf_check() and/or the bpf_check() call in
bpf_prog_load() is not the verifier, it would be helpful to know that,
and also what code is considered the be the BPF verifier.  Regardless,
it's a good step forward that we are all on the same page with respect
to the authorization of signed/unsigned BPF programs.  We still have a
ways to go it looks like, but we're making good progress.

-- 
paul-moore.com

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

* Re: [PATCH 0/3] BPF signature verification
  2025-05-30 20:14   ` Paul Moore
@ 2025-05-30 20:44     ` KP Singh
  0 siblings, 0 replies; 25+ messages in thread
From: KP Singh @ 2025-05-30 20:44 UTC (permalink / raw)
  To: Paul Moore
  Cc: Blaise Boscaccy, jarkko, zeffron, xiyou.wangcong, kysrinivasan,
	code, linux-security-module, roberto.sassu, James.Bottomley,
	Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	David Howells, Lukas Wunner, Ignat Korchagin, Quentin Monnet,
	Jason Xing, Willem de Bruijn, Anton Protopopov, Jordan Rome,
	Martin Kelly, Alan Maguire, Matteo Croce, bpf, linux-kernel,
	keyrings, linux-crypto, kys

On Fri, May 30, 2025 at 10:15 PM Paul Moore <paul@paul-moore.com> wrote:
>
> On Fri, May 30, 2025 at 12:42 PM KP Singh <kpsingh@kernel.org> wrote:
> > On Wed, May 28, 2025 at 11:50 PM Blaise Boscaccy
> > <bboscaccy@linux.microsoft.com> wrote:
>
> ...
>
> > Please hold off on further iterations, I am working on a series and
> > will share these patches based on the design that was proposed.
>
> I don't think there is any harm in Blaise continuing his work in this
> area, especially as he seems to be making reasonable progress towards
> a solution that satisfies everyone's needs.  Considering all of the
> work that Blaise has already invested in this, and his continued
> willingness to try to work with everyone in the community to converge
> on a solution, wouldn't it be more beneficial to work with Blaise on
> further developing/refining his patchset instead of posting a parallel
> effort?  It's your call of course, I'm not going to tell you, or
> anyone else, to refrain from posting patches upstream, but it seems
> like this is a good opportunity to help foster the development of a
> new contributor.

I think Blaise's interactions leave a lot to be desired, especially as
a new contributor with the replies being unnecessarily abrasive, which
I am choosing to ignore.

Regardless, it would be more efficient to handle the subtleties here
if someone from the core BPF community implements this. This is why I
volunteered myself, but I need some time to wrap up the code and send
it on the list. Blaise can continue to send patches that don't
incorporate the feedback, it will only delay me further.

>
> > > 2. Timing of Signature Check
> > >
> > > This patchset moves the signature check to a point before
> > > security_bpf_prog_load is invoked, due to an unresolved discussion
> > > here:
> >
> > This is fine and what I had in mind, signature verification does not
> > need to happen in the verifier and the existing hooks are good enough.
>
> Excellent, I'm glad we can agree on the relative placement of the
> signature verification and the LSM hook.  Perhaps I misunderstood your
> design idea, but I took your comment:
>
> "The signature check in the verifier (during BPF_PROG_LOAD):

I meant during BPF_PROG_LOAD i.e. before the bpf_check is triggered,
as I said this is better explained when implemented.

>> trust me, friend” aspect of the original design.

The kernel is the TCB, both LSM and BPF are a part of the kernel and
part of the same trust domain, LSM has sufficient information in the
existing LSM hooks to enforce a signature policy and there is no need
for a boolean:

* If attr.signature is set, it's enforced, a new boolean does not
convey any new information here.
* If we specifically need auditing here, we can add an audit call in
the signature_verification method, this can be done in a follow-up
series.


>
>  verify_pkcs7_signature(prog->aux->sha, sizeof(prog->aux->sha),
>    sig_from_bpf_attr, …);"
>
> https://lore.kernel.org/linux-security-module/CACYkzJ6VQUExfyt0=-FmXz46GHJh3d=FXh5j4KfexcEFbHV-vg@mail.gmail.com/
>
> ... to mean that the PKCS7 signature verification was going to happen
> *in* the verifier, with the verifier being bpf_check().  Simply for my
> own education, if bpf_check() and/or the bpf_check() call in
> bpf_prog_load() is not the verifier, it would be helpful to know that,
> and also what code is considered the be the BPF verifier.  Regardless,
> it's a good step forward that we are all on the same page with respect
> to the authorization of signed/unsigned BPF programs.  We still have a
> ways to go it looks like, but we're making good progress.
>
> --
> paul-moore.com

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

* Re: [PATCH 0/3] BPF signature verification
  2025-05-30 16:42 ` [PATCH 0/3] BPF signature verification KP Singh
  2025-05-30 20:14   ` Paul Moore
@ 2025-05-30 21:19   ` Blaise Boscaccy
  2025-05-30 21:32     ` KP Singh
  1 sibling, 1 reply; 25+ messages in thread
From: Blaise Boscaccy @ 2025-05-30 21:19 UTC (permalink / raw)
  To: KP Singh
  Cc: Paul Moore, jarkko, zeffron, xiyou.wangcong, kysrinivasan, code,
	linux-security-module, roberto.sassu, James.Bottomley,
	Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	David Howells, Lukas Wunner, Ignat Korchagin, Quentin Monnet,
	Jason Xing, Willem de Bruijn, Anton Protopopov, Jordan Rome,
	Martin Kelly, Alan Maguire, Matteo Croce, bpf, linux-kernel,
	keyrings, linux-crypto, kys

KP Singh <kpsingh@kernel.org> writes:

> On Wed, May 28, 2025 at 11:50 PM Blaise Boscaccy
> <bboscaccy@linux.microsoft.com> wrote:
>>
>> As suggested or mandated by KP Singh
>> https://lore.kernel.org/linux-security-module/CACYkzJ6VQUExfyt0=-FmXz46GHJh3d=FXh5j4KfexcEFbHV-vg@mail.gmail.com/,
>> this patchset proposes and implements an alternative hash-chain
>> algorithm for signature verification of BPF programs.
>>
>>
>>
>> This design diverges in two key ways:
>>
>> 1. Signature Strategy
>>
>> Two different signature strategies are
>> implemented. One verifies only the signature of the loader program in
>> the kernel, as described in the link above. The other verifies the
>> program’s maps in-kernel via a hash chain.  The original design
>> required loader programs to be “self-aborting” and embedded the
>> terminal hash verification logic as metaprogramming code generation
>> routines inside libbpf. While this patchset supports that scheme, it
>> is considered undesirable in certain environments due to the potential
>> for supply-chain attack vectors and the lack of visibility for the LSM
>
> The loader program is signed by a trusted entity, If you trust the
> signature, then you trust it to do the signature verification.

That's the whole point. I explicitly don't want to be forced, by you,
to trust unspecified third parties, BPF programs or the BPF virtual
machine/JIT to perform signature verification, when it's demonstrably
trivial to do this in the kernel, without precluding or limiting the
chain loader scheme that you wish to have for Cilium/bpftrace.

> This is
> a fairly common pattern in security and a pattern that we will be
> using in other signed bpf use-cases which can choose to depend on
> signed loaders.
>

And that isn't at odds with the kernel being able to do it nor is it
with what I posted.

> If your build environment that signs the BPF program is compromised
> and can inject arbitrary code, then signing does not help.  Can you
> explain what a supply chain attack would look like here?
>

Most people here can read C code. The number of people that can read
ebpf assembly metaprogramming code is much smaller. Compromising clang
is one thing, compromising libbpf is another. Your proposal increases
the attack surface with no observable benefit. If I was going to leave a
hard-to-find backdoor into ring0, gen.c would be a fun place to explore
doing it. Module and UEFI signature verification code doesn't live
inside of GCC or Clang as set of meta-instructions that get emitted, and
there are very good reasons for that.

Further, since the signature verification code is unique for each and
every program it needs to be verified/proved/tested for each and every
program. Additionally, since all these checks are being forced outside
of the kernel proper, with the insistence of keeping the LSM layer in
the dark of the ultimate result, the only way to test that a program
will fail if the map is corrupted is to physically corrupt each and
every program and test that individually. That isn't "elegant" nor "user
friendly" in any way, shape or form.

>> subsystem.  Additionally, it is impossible to verify the code
>> performing the signature verification, as it is uniquely regenerated
>
> The LSM needs to ensure that it allows trusted LOADER programs i.e.
> with signatures and potentially trusted signed user-space binaries
> with unsigned or delegated signing (this will be needed for Cilium and
> bpftrace that dynamically generate BPF programs), that's a more
> important aspect of the LSM policy from a BPF perspective.
>

I would like to be able to sign my programs please and have the kernel
verify it was done correctly. Why are you insisting that I *don't* do
that?  I'm yet to see any technical objection to doing that. Do you have
one that you'd like to share at this point?

> MAP_EXCLUSIVE is missing and is required which prevents maps from
> being accessed by other programs as explained in the proposal.
>
> Please hold off on further iterations, I am working on a series and
> will share these patches based on the design that was proposed.
>

So the premise here seems to be that people should only be allowed to
sign trusted loaders, and that trusted loaders must additionally be
authored by you, correct?

When can we expect to see your patchset posted?

>>
>> for every program.
>>
>>
>>
>> 2. Timing of Signature Check
>>
>> This patchset moves the signature check to a point before
>> security_bpf_prog_load is invoked, due to an unresolved discussion
>> here:
>
> This is fine and what I had in mind, signature verification does not
> need to happen in the verifier and the existing hooks are good enough.
> I did not reply to Paul's comment since this is a fairly trivial
> detail and would be obvious in the implementation that the verifier is
> not the right place to check the signature anyways as the instruction
> buffer is only stable pre-verification.
>
>> https://lore.kernel.org/linux-security-module/CAHC9VhTj3=ZXgrYMNA+G64zsOyZO+78uDs1g=kh91=GR5KypYg@mail.gmail.com/
>> This change allows the LSM subsystem to be informed of the signature
>> verification result—if it occurred—and the method used, all without
>> introducing a new hook. It improves visibility and auditability,
>> reducing the “trust me, friend” aspect of the original design.
>
>
> On Wed, May 28, 2025 at 11:50 PM Blaise Boscaccy
> <bboscaccy@linux.microsoft.com> wrote:
>>
>> As suggested or mandated by KP Singh
>> https://lore.kernel.org/linux-security-module/CACYkzJ6VQUExfyt0=-FmXz46GHJh3d=FXh5j4KfexcEFbHV-vg@mail.gmail.com/,
>> this patchset proposes and implements an alternative hash-chain
>> algorithm for signature verification of BPF programs.
>>
>> This design diverges in two key ways:
>>
>> 1. Signature Strategy
>>
>> Two different signature strategies are
>> implemented. One verifies only the signature of the loader program in
>> the kernel, as described in the link above. The other verifies the
>> program’s maps in-kernel via a hash chain.  The original design
>> required loader programs to be “self-aborting” and embedded the
>> terminal hash verification logic as metaprogramming code generation
>> routines inside libbpf. While this patchset supports that scheme, it
>> is considered undesirable in certain environments due to the potential
>> for supply-chain attack vectors and the lack of visibility for the LSM
>> subsystem.  Additionally, it is impossible to verify the code
>> performing the signature verification, as it is uniquely regenerated
>> for every program.
>>
>> 2. Timing of Signature Check
>>
>> This patchset moves the signature check to a point before
>> security_bpf_prog_load is invoked, due to an unresolved discussion
>> here:
>> https://lore.kernel.org/linux-security-module/CAHC9VhTj3=ZXgrYMNA+G64zsOyZO+78uDs1g=kh91=GR5KypYg@mail.gmail.com/
>> This change allows the LSM subsystem to be informed of the signature
>> verification result—if it occurred—and the method used, all without
>> introducing a new hook. It improves visibility and auditability,
>> reducing the “trust me, friend” aspect of the original design.
>>
>>
>> Blaise Boscaccy (3):
>>   bpf: Add bpf_check_signature
>>   bpf: Support light-skeleton signatures in autogenerated code
>>   bpftool: Allow signing of light-skeleton programs
>>
>>  include/linux/bpf.h            |   2 +
>>  include/linux/verification.h   |   1 +
>>  include/uapi/linux/bpf.h       |   4 +
>>  kernel/bpf/arraymap.c          |  11 +-
>>  kernel/bpf/syscall.c           | 123 +++++++++++++++++++-
>>  tools/bpf/bpftool/Makefile     |   4 +-
>>  tools/bpf/bpftool/common.c     | 204 +++++++++++++++++++++++++++++++++
>>  tools/bpf/bpftool/gen.c        |  66 ++++++++++-
>>  tools/bpf/bpftool/main.c       |  24 +++-
>>  tools/bpf/bpftool/main.h       |  23 ++++
>>  tools/include/uapi/linux/bpf.h |   4 +
>>  tools/lib/bpf/libbpf.h         |   4 +
>>  tools/lib/bpf/skel_internal.h  |  28 ++++-
>>  13 files changed, 491 insertions(+), 7 deletions(-)
>>
>> --
>> 2.48.1
>>

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

* Re: [PATCH 0/3] BPF signature verification
  2025-05-30 21:19   ` Blaise Boscaccy
@ 2025-05-30 21:32     ` KP Singh
  2025-05-30 21:33       ` KP Singh
  2025-05-30 22:14       ` Blaise Boscaccy
  0 siblings, 2 replies; 25+ messages in thread
From: KP Singh @ 2025-05-30 21:32 UTC (permalink / raw)
  To: Blaise Boscaccy
  Cc: Paul Moore, jarkko, zeffron, xiyou.wangcong, kysrinivasan, code,
	linux-security-module, roberto.sassu, James.Bottomley,
	Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	David Howells, Lukas Wunner, Ignat Korchagin, Quentin Monnet,
	Jason Xing, Willem de Bruijn, Anton Protopopov, Jordan Rome,
	Martin Kelly, Alan Maguire, Matteo Croce, bpf, linux-kernel,
	keyrings, linux-crypto, kys

On Fri, May 30, 2025 at 11:19 PM Blaise Boscaccy
<bboscaccy@linux.microsoft.com> wrote:
>
> KP Singh <kpsingh@kernel.org> writes:
>

[...]

> >
>
> And that isn't at odds with the kernel being able to do it nor is it
> with what I posted.
>
> > If your build environment that signs the BPF program is compromised
> > and can inject arbitrary code, then signing does not help.  Can you
> > explain what a supply chain attack would look like here?
> >
>
> Most people here can read C code. The number of people that can read
> ebpf assembly metaprogramming code is much smaller. Compromising clang
> is one thing, compromising libbpf is another. Your proposal increases
> the attack surface with no observable benefit. If I was going to leave a
> hard-to-find backdoor into ring0, gen.c would be a fun place to explore
> doing it. Module and UEFI signature verification code doesn't live
> inside of GCC or Clang as set of meta-instructions that get emitted, and
> there are very good reasons for that.
>
> Further, since the signature verification code is unique for each and
> every program it needs to be verified/proved/tested for each and every
> program. Additionally, since all these checks are being forced outside
> of the kernel proper, with the insistence of keeping the LSM layer in
> the dark of the ultimate result, the only way to test that a program
> will fail if the map is corrupted is to physically corrupt each and
> every program and test that individually. That isn't "elegant" nor "user
> friendly" in any way, shape or form.
>
> >> subsystem.  Additionally, it is impossible to verify the code
> >> performing the signature verification, as it is uniquely regenerated
> >
> > The LSM needs to ensure that it allows trusted LOADER programs i.e.
> > with signatures and potentially trusted signed user-space binaries
> > with unsigned or delegated signing (this will be needed for Cilium and
> > bpftrace that dynamically generate BPF programs), that's a more
> > important aspect of the LSM policy from a BPF perspective.
> >
>
> I would like to be able to sign my programs please and have the kernel
> verify it was done correctly. Why are you insisting that I *don't* do
> that?  I'm yet to see any technical objection to doing that. Do you have
> one that you'd like to share at this point?

The kernel allows a trusted loader that's signed with your private
key, that runs in the kernel context to delegate the verification.
This pattern of a trusted / delegated loader is going to be required
for many of the BPF use-cases that are out there (Cilium, bpftrace)
that dynamically generate eBPF programs.

The technical objection is that:

* It does not align with most BPF use-cases out there as most
use-cases need a trusted loader.
* Locks us into a UAPI, whereas a signed LOADER allows us to
incrementally build signing for all use-cases without compromising the
security properties.

BPF's philosophy is that of flexibility and not locking the users into
a rigid in-kernel implementation and UAPI.

- KP

>
> > MAP_EXCLUSIVE is missing and is required which prevents maps from
> > being accessed by other programs as explained in the proposal.
> >
> > Please hold off on further iterations, I am working on a series and
> > will share these patches based on the design that was proposed.
> >
>
> So the premise here seems to be that people should only be allowed to
> sign trusted loaders, and that trusted loaders must additionally be
> authored by you, correct?
>
> When can we expect to see your patchset posted?
>
> >>
> >> for every program.
> >>
> >>
> >>
> >> 2. Timing of Signature Check
> >>
> >> This patchset moves the signature check to a point before
> >> security_bpf_prog_load is invoked, due to an unresolved discussion
> >> here:
> >
> > This is fine and what I had in mind, signature verification does not
> > need to happen in the verifier and the existing hooks are good enough.
> > I did not reply to Paul's comment since this is a fairly trivial
> > detail and would be obvious in the implementation that the verifier is
> > not the right place to check the signature anyways as the instruction
> > buffer is only stable pre-verification.
> >
> >> https://lore.kernel.org/linux-security-module/CAHC9VhTj3=ZXgrYMNA+G64zsOyZO+78uDs1g=kh91=GR5KypYg@mail.gmail.com/
> >> This change allows the LSM subsystem to be informed of the signature
> >> verification result—if it occurred—and the method used, all without
> >> introducing a new hook. It improves visibility and auditability,
> >> reducing the “trust me, friend” aspect of the original design.
> >
> >
> > On Wed, May 28, 2025 at 11:50 PM Blaise Boscaccy
> > <bboscaccy@linux.microsoft.com> wrote:
> >>
> >> As suggested or mandated by KP Singh
> >> https://lore.kernel.org/linux-security-module/CACYkzJ6VQUExfyt0=-FmXz46GHJh3d=FXh5j4KfexcEFbHV-vg@mail.gmail.com/,
> >> this patchset proposes and implements an alternative hash-chain
> >> algorithm for signature verification of BPF programs.
> >>
> >> This design diverges in two key ways:
> >>
> >> 1. Signature Strategy
> >>
> >> Two different signature strategies are
> >> implemented. One verifies only the signature of the loader program in
> >> the kernel, as described in the link above. The other verifies the
> >> program’s maps in-kernel via a hash chain.  The original design
> >> required loader programs to be “self-aborting” and embedded the
> >> terminal hash verification logic as metaprogramming code generation
> >> routines inside libbpf. While this patchset supports that scheme, it
> >> is considered undesirable in certain environments due to the potential
> >> for supply-chain attack vectors and the lack of visibility for the LSM
> >> subsystem.  Additionally, it is impossible to verify the code
> >> performing the signature verification, as it is uniquely regenerated
> >> for every program.
> >>
> >> 2. Timing of Signature Check
> >>
> >> This patchset moves the signature check to a point before
> >> security_bpf_prog_load is invoked, due to an unresolved discussion
> >> here:
> >> https://lore.kernel.org/linux-security-module/CAHC9VhTj3=ZXgrYMNA+G64zsOyZO+78uDs1g=kh91=GR5KypYg@mail.gmail.com/
> >> This change allows the LSM subsystem to be informed of the signature
> >> verification result—if it occurred—and the method used, all without
> >> introducing a new hook. It improves visibility and auditability,
> >> reducing the “trust me, friend” aspect of the original design.
> >>
> >>
> >> Blaise Boscaccy (3):
> >>   bpf: Add bpf_check_signature
> >>   bpf: Support light-skeleton signatures in autogenerated code
> >>   bpftool: Allow signing of light-skeleton programs
> >>
> >>  include/linux/bpf.h            |   2 +
> >>  include/linux/verification.h   |   1 +
> >>  include/uapi/linux/bpf.h       |   4 +
> >>  kernel/bpf/arraymap.c          |  11 +-
> >>  kernel/bpf/syscall.c           | 123 +++++++++++++++++++-
> >>  tools/bpf/bpftool/Makefile     |   4 +-
> >>  tools/bpf/bpftool/common.c     | 204 +++++++++++++++++++++++++++++++++
> >>  tools/bpf/bpftool/gen.c        |  66 ++++++++++-
> >>  tools/bpf/bpftool/main.c       |  24 +++-
> >>  tools/bpf/bpftool/main.h       |  23 ++++
> >>  tools/include/uapi/linux/bpf.h |   4 +
> >>  tools/lib/bpf/libbpf.h         |   4 +
> >>  tools/lib/bpf/skel_internal.h  |  28 ++++-
> >>  13 files changed, 491 insertions(+), 7 deletions(-)
> >>
> >> --
> >> 2.48.1
> >>

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

* Re: [PATCH 0/3] BPF signature verification
  2025-05-30 21:32     ` KP Singh
@ 2025-05-30 21:33       ` KP Singh
  2025-05-30 22:15         ` Blaise Boscaccy
  2025-05-30 22:14       ` Blaise Boscaccy
  1 sibling, 1 reply; 25+ messages in thread
From: KP Singh @ 2025-05-30 21:33 UTC (permalink / raw)
  To: Blaise Boscaccy
  Cc: Paul Moore, jarkko, zeffron, xiyou.wangcong, kysrinivasan, code,
	linux-security-module, roberto.sassu, James.Bottomley,
	Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	David Howells, Lukas Wunner, Ignat Korchagin, Quentin Monnet,
	Jason Xing, Willem de Bruijn, Anton Protopopov, Jordan Rome,
	Martin Kelly, Alan Maguire, Matteo Croce, bpf, linux-kernel,
	keyrings, linux-crypto, kys

On Fri, May 30, 2025 at 11:32 PM KP Singh <kpsingh@kernel.org> wrote:
>
> On Fri, May 30, 2025 at 11:19 PM Blaise Boscaccy
> <bboscaccy@linux.microsoft.com> wrote:
> >
> > KP Singh <kpsingh@kernel.org> writes:
> >
>
> [...]
>
> > >
> >
> > And that isn't at odds with the kernel being able to do it nor is it
> > with what I posted.
> >
> > > If your build environment that signs the BPF program is compromised
> > > and can inject arbitrary code, then signing does not help.  Can you
> > > explain what a supply chain attack would look like here?
> > >
> >
> > Most people here can read C code. The number of people that can read
> > ebpf assembly metaprogramming code is much smaller. Compromising clang
> > is one thing, compromising libbpf is another. Your proposal increases
> > the attack surface with no observable benefit. If I was going to leave a
> > hard-to-find backdoor into ring0, gen.c would be a fun place to explore
> > doing it. Module and UEFI signature verification code doesn't live
> > inside of GCC or Clang as set of meta-instructions that get emitted, and
> > there are very good reasons for that.
> >
> > Further, since the signature verification code is unique for each and
> > every program it needs to be verified/proved/tested for each and every
> > program. Additionally, since all these checks are being forced outside
> > of the kernel proper, with the insistence of keeping the LSM layer in
> > the dark of the ultimate result, the only way to test that a program
> > will fail if the map is corrupted is to physically corrupt each and
> > every program and test that individually. That isn't "elegant" nor "user
> > friendly" in any way, shape or form.
> >
> > >> subsystem.  Additionally, it is impossible to verify the code
> > >> performing the signature verification, as it is uniquely regenerated
> > >
> > > The LSM needs to ensure that it allows trusted LOADER programs i.e.
> > > with signatures and potentially trusted signed user-space binaries
> > > with unsigned or delegated signing (this will be needed for Cilium and
> > > bpftrace that dynamically generate BPF programs), that's a more
> > > important aspect of the LSM policy from a BPF perspective.
> > >
> >
> > I would like to be able to sign my programs please and have the kernel
> > verify it was done correctly. Why are you insisting that I *don't* do
> > that?  I'm yet to see any technical objection to doing that. Do you have
> > one that you'd like to share at this point?
>
> The kernel allows a trusted loader that's signed with your private
> key, that runs in the kernel context to delegate the verification.
> This pattern of a trusted / delegated loader is going to be required
> for many of the BPF use-cases that are out there (Cilium, bpftrace)
> that dynamically generate eBPF programs.
>
> The technical objection is that:
>
> * It does not align with most BPF use-cases out there as most
> use-cases need a trusted loader.
> * Locks us into a UAPI, whereas a signed LOADER allows us to
> incrementally build signing for all use-cases without compromising the
> security properties.
>
> BPF's philosophy is that of flexibility and not locking the users into
> a rigid in-kernel implementation and UAPI.
>
> - KP
>
> >
> > > MAP_EXCLUSIVE is missing and is required which prevents maps from
> > > being accessed by other programs as explained in the proposal.
> > >
> > > Please hold off on further iterations, I am working on a series and
> > > will share these patches based on the design that was proposed.
> > >
> >
> > So the premise here seems to be that people should only be allowed to
> > sign trusted loaders, and that trusted loaders must additionally be
> > authored by you, correct?
> >
> > When can we expect to see your patchset posted?

I will try to get this out by the end of next week.

- KP

> >

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

* Re: [PATCH 0/3] BPF signature verification
  2025-05-30 21:32     ` KP Singh
  2025-05-30 21:33       ` KP Singh
@ 2025-05-30 22:14       ` Blaise Boscaccy
  2025-05-30 22:19         ` KP Singh
  1 sibling, 1 reply; 25+ messages in thread
From: Blaise Boscaccy @ 2025-05-30 22:14 UTC (permalink / raw)
  To: KP Singh
  Cc: Paul Moore, jarkko, zeffron, xiyou.wangcong, kysrinivasan, code,
	linux-security-module, roberto.sassu, James.Bottomley,
	Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	David Howells, Lukas Wunner, Ignat Korchagin, Quentin Monnet,
	Jason Xing, Willem de Bruijn, Anton Protopopov, Jordan Rome,
	Martin Kelly, Alan Maguire, Matteo Croce, bpf, linux-kernel,
	keyrings, linux-crypto, kys

KP Singh <kpsingh@kernel.org> writes:

> On Fri, May 30, 2025 at 11:19 PM Blaise Boscaccy
> <bboscaccy@linux.microsoft.com> wrote:
>>
>> KP Singh <kpsingh@kernel.org> writes:
>>
>
> [...]
>
>> >
>>
>> And that isn't at odds with the kernel being able to do it nor is it
>> with what I posted.
>>
>> > If your build environment that signs the BPF program is compromised
>> > and can inject arbitrary code, then signing does not help.  Can you
>> > explain what a supply chain attack would look like here?
>> >
>>
>> Most people here can read C code. The number of people that can read
>> ebpf assembly metaprogramming code is much smaller. Compromising clang
>> is one thing, compromising libbpf is another. Your proposal increases
>> the attack surface with no observable benefit. If I was going to leave a
>> hard-to-find backdoor into ring0, gen.c would be a fun place to explore
>> doing it. Module and UEFI signature verification code doesn't live
>> inside of GCC or Clang as set of meta-instructions that get emitted, and
>> there are very good reasons for that.
>>
>> Further, since the signature verification code is unique for each and
>> every program it needs to be verified/proved/tested for each and every
>> program. Additionally, since all these checks are being forced outside
>> of the kernel proper, with the insistence of keeping the LSM layer in
>> the dark of the ultimate result, the only way to test that a program
>> will fail if the map is corrupted is to physically corrupt each and
>> every program and test that individually. That isn't "elegant" nor "user
>> friendly" in any way, shape or form.
>>
>> >> subsystem.  Additionally, it is impossible to verify the code
>> >> performing the signature verification, as it is uniquely regenerated
>> >
>> > The LSM needs to ensure that it allows trusted LOADER programs i.e.
>> > with signatures and potentially trusted signed user-space binaries
>> > with unsigned or delegated signing (this will be needed for Cilium and
>> > bpftrace that dynamically generate BPF programs), that's a more
>> > important aspect of the LSM policy from a BPF perspective.
>> >
>>
>> I would like to be able to sign my programs please and have the kernel
>> verify it was done correctly. Why are you insisting that I *don't* do
>> that?  I'm yet to see any technical objection to doing that. Do you have
>> one that you'd like to share at this point?
>
> The kernel allows a trusted loader that's signed with your private
> key, that runs in the kernel context to delegate the verification.
> This pattern of a trusted / delegated loader is going to be required
> for many of the BPF use-cases that are out there (Cilium, bpftrace)
> that dynamically generate eBPF programs.
>
> The technical objection is that:
>
> * It does not align with most BPF use-cases out there as most
> use-cases need a trusted loader.

No, it's definitely a use case. It's trivial to support both a trusted
loader and a signature over the hash chain of supplied assets.

> * Locks us into a UAPI, whereas a signed LOADER allows us to
> incrementally build signing for all use-cases without compromising the
> security properties.
>

Your proposal locks us into a UAPI as well. There is no way to make to
do this via UAPI without making a UAPI design choice.

> BPF's philosophy is that of flexibility and not locking the users into
> a rigid in-kernel implementation and UAPI.
>

Then why are you locking us into a rigid
only-signing-the-loader-is-allowed implementation?

> - KP
>
>>
>> > MAP_EXCLUSIVE is missing and is required which prevents maps from
>> > being accessed by other programs as explained in the proposal.
>> >
>> > Please hold off on further iterations, I am working on a series and
>> > will share these patches based on the design that was proposed.
>> >
>>
>> So the premise here seems to be that people should only be allowed to
>> sign trusted loaders, and that trusted loaders must additionally be
>> authored by you, correct?
>>
>> When can we expect to see your patchset posted?
>>
>> >>
>> >> for every program.
>> >>
>> >>
>> >>
>> >> 2. Timing of Signature Check
>> >>
>> >> This patchset moves the signature check to a point before
>> >> security_bpf_prog_load is invoked, due to an unresolved discussion
>> >> here:
>> >
>> > This is fine and what I had in mind, signature verification does not
>> > need to happen in the verifier and the existing hooks are good enough.
>> > I did not reply to Paul's comment since this is a fairly trivial
>> > detail and would be obvious in the implementation that the verifier is
>> > not the right place to check the signature anyways as the instruction
>> > buffer is only stable pre-verification.
>> >
>> >> https://lore.kernel.org/linux-security-module/CAHC9VhTj3=ZXgrYMNA+G64zsOyZO+78uDs1g=kh91=GR5KypYg@mail.gmail.com/
>> >> This change allows the LSM subsystem to be informed of the signature
>> >> verification result—if it occurred—and the method used, all without
>> >> introducing a new hook. It improves visibility and auditability,
>> >> reducing the “trust me, friend” aspect of the original design.
>> >
>> >
>> > On Wed, May 28, 2025 at 11:50 PM Blaise Boscaccy
>> > <bboscaccy@linux.microsoft.com> wrote:
>> >>
>> >> As suggested or mandated by KP Singh
>> >> https://lore.kernel.org/linux-security-module/CACYkzJ6VQUExfyt0=-FmXz46GHJh3d=FXh5j4KfexcEFbHV-vg@mail.gmail.com/,
>> >> this patchset proposes and implements an alternative hash-chain
>> >> algorithm for signature verification of BPF programs.
>> >>
>> >> This design diverges in two key ways:
>> >>
>> >> 1. Signature Strategy
>> >>
>> >> Two different signature strategies are
>> >> implemented. One verifies only the signature of the loader program in
>> >> the kernel, as described in the link above. The other verifies the
>> >> program’s maps in-kernel via a hash chain.  The original design
>> >> required loader programs to be “self-aborting” and embedded the
>> >> terminal hash verification logic as metaprogramming code generation
>> >> routines inside libbpf. While this patchset supports that scheme, it
>> >> is considered undesirable in certain environments due to the potential
>> >> for supply-chain attack vectors and the lack of visibility for the LSM
>> >> subsystem.  Additionally, it is impossible to verify the code
>> >> performing the signature verification, as it is uniquely regenerated
>> >> for every program.
>> >>
>> >> 2. Timing of Signature Check
>> >>
>> >> This patchset moves the signature check to a point before
>> >> security_bpf_prog_load is invoked, due to an unresolved discussion
>> >> here:
>> >> https://lore.kernel.org/linux-security-module/CAHC9VhTj3=ZXgrYMNA+G64zsOyZO+78uDs1g=kh91=GR5KypYg@mail.gmail.com/
>> >> This change allows the LSM subsystem to be informed of the signature
>> >> verification result—if it occurred—and the method used, all without
>> >> introducing a new hook. It improves visibility and auditability,
>> >> reducing the “trust me, friend” aspect of the original design.
>> >>
>> >>
>> >> Blaise Boscaccy (3):
>> >>   bpf: Add bpf_check_signature
>> >>   bpf: Support light-skeleton signatures in autogenerated code
>> >>   bpftool: Allow signing of light-skeleton programs
>> >>
>> >>  include/linux/bpf.h            |   2 +
>> >>  include/linux/verification.h   |   1 +
>> >>  include/uapi/linux/bpf.h       |   4 +
>> >>  kernel/bpf/arraymap.c          |  11 +-
>> >>  kernel/bpf/syscall.c           | 123 +++++++++++++++++++-
>> >>  tools/bpf/bpftool/Makefile     |   4 +-
>> >>  tools/bpf/bpftool/common.c     | 204 +++++++++++++++++++++++++++++++++
>> >>  tools/bpf/bpftool/gen.c        |  66 ++++++++++-
>> >>  tools/bpf/bpftool/main.c       |  24 +++-
>> >>  tools/bpf/bpftool/main.h       |  23 ++++
>> >>  tools/include/uapi/linux/bpf.h |   4 +
>> >>  tools/lib/bpf/libbpf.h         |   4 +
>> >>  tools/lib/bpf/skel_internal.h  |  28 ++++-
>> >>  13 files changed, 491 insertions(+), 7 deletions(-)
>> >>
>> >> --
>> >> 2.48.1
>> >>

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

* Re: [PATCH 0/3] BPF signature verification
  2025-05-30 21:33       ` KP Singh
@ 2025-05-30 22:15         ` Blaise Boscaccy
  0 siblings, 0 replies; 25+ messages in thread
From: Blaise Boscaccy @ 2025-05-30 22:15 UTC (permalink / raw)
  To: KP Singh
  Cc: Paul Moore, jarkko, zeffron, xiyou.wangcong, kysrinivasan, code,
	linux-security-module, roberto.sassu, James.Bottomley,
	Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	David Howells, Lukas Wunner, Ignat Korchagin, Quentin Monnet,
	Jason Xing, Willem de Bruijn, Anton Protopopov, Jordan Rome,
	Martin Kelly, Alan Maguire, Matteo Croce, bpf, linux-kernel,
	keyrings, linux-crypto, kys

KP Singh <kpsingh@kernel.org> writes:

> On Fri, May 30, 2025 at 11:32 PM KP Singh <kpsingh@kernel.org> wrote:
>>
>> On Fri, May 30, 2025 at 11:19 PM Blaise Boscaccy
>> <bboscaccy@linux.microsoft.com> wrote:
>> >
>> > KP Singh <kpsingh@kernel.org> writes:
>> >
>>
>> [...]
>>
>> > >
>> >
>> > And that isn't at odds with the kernel being able to do it nor is it
>> > with what I posted.
>> >
>> > > If your build environment that signs the BPF program is compromised
>> > > and can inject arbitrary code, then signing does not help.  Can you
>> > > explain what a supply chain attack would look like here?
>> > >
>> >
>> > Most people here can read C code. The number of people that can read
>> > ebpf assembly metaprogramming code is much smaller. Compromising clang
>> > is one thing, compromising libbpf is another. Your proposal increases
>> > the attack surface with no observable benefit. If I was going to leave a
>> > hard-to-find backdoor into ring0, gen.c would be a fun place to explore
>> > doing it. Module and UEFI signature verification code doesn't live
>> > inside of GCC or Clang as set of meta-instructions that get emitted, and
>> > there are very good reasons for that.
>> >
>> > Further, since the signature verification code is unique for each and
>> > every program it needs to be verified/proved/tested for each and every
>> > program. Additionally, since all these checks are being forced outside
>> > of the kernel proper, with the insistence of keeping the LSM layer in
>> > the dark of the ultimate result, the only way to test that a program
>> > will fail if the map is corrupted is to physically corrupt each and
>> > every program and test that individually. That isn't "elegant" nor "user
>> > friendly" in any way, shape or form.
>> >
>> > >> subsystem.  Additionally, it is impossible to verify the code
>> > >> performing the signature verification, as it is uniquely regenerated
>> > >
>> > > The LSM needs to ensure that it allows trusted LOADER programs i.e.
>> > > with signatures and potentially trusted signed user-space binaries
>> > > with unsigned or delegated signing (this will be needed for Cilium and
>> > > bpftrace that dynamically generate BPF programs), that's a more
>> > > important aspect of the LSM policy from a BPF perspective.
>> > >
>> >
>> > I would like to be able to sign my programs please and have the kernel
>> > verify it was done correctly. Why are you insisting that I *don't* do
>> > that?  I'm yet to see any technical objection to doing that. Do you have
>> > one that you'd like to share at this point?
>>
>> The kernel allows a trusted loader that's signed with your private
>> key, that runs in the kernel context to delegate the verification.
>> This pattern of a trusted / delegated loader is going to be required
>> for many of the BPF use-cases that are out there (Cilium, bpftrace)
>> that dynamically generate eBPF programs.
>>
>> The technical objection is that:
>>
>> * It does not align with most BPF use-cases out there as most
>> use-cases need a trusted loader.
>> * Locks us into a UAPI, whereas a signed LOADER allows us to
>> incrementally build signing for all use-cases without compromising the
>> security properties.
>>
>> BPF's philosophy is that of flexibility and not locking the users into
>> a rigid in-kernel implementation and UAPI.
>>
>> - KP
>>
>> >
>> > > MAP_EXCLUSIVE is missing and is required which prevents maps from
>> > > being accessed by other programs as explained in the proposal.
>> > >
>> > > Please hold off on further iterations, I am working on a series and
>> > > will share these patches based on the design that was proposed.
>> > >
>> >
>> > So the premise here seems to be that people should only be allowed to
>> > sign trusted loaders, and that trusted loaders must additionally be
>> > authored by you, correct?
>> >
>> > When can we expect to see your patchset posted?
>
> I will try to get this out by the end of next week.

Wonderful, we look forward to seeing your patchset.

-blaise

>
> - KP
>
>> >

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

* Re: [PATCH 0/3] BPF signature verification
  2025-05-30 22:14       ` Blaise Boscaccy
@ 2025-05-30 22:19         ` KP Singh
  2025-05-30 22:27           ` Blaise Boscaccy
  0 siblings, 1 reply; 25+ messages in thread
From: KP Singh @ 2025-05-30 22:19 UTC (permalink / raw)
  To: Blaise Boscaccy
  Cc: Paul Moore, jarkko, zeffron, xiyou.wangcong, kysrinivasan, code,
	linux-security-module, roberto.sassu, James.Bottomley,
	Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	David Howells, Lukas Wunner, Ignat Korchagin, Quentin Monnet,
	Jason Xing, Willem de Bruijn, Anton Protopopov, Jordan Rome,
	Martin Kelly, Alan Maguire, Matteo Croce, bpf, linux-kernel,
	keyrings, linux-crypto, kys

On Sat, May 31, 2025 at 12:14 AM Blaise Boscaccy
<bboscaccy@linux.microsoft.com> wrote:
>
> KP Singh <kpsingh@kernel.org> writes:
>
> > On Fri, May 30, 2025 at 11:19 PM Blaise Boscaccy
> > <bboscaccy@linux.microsoft.com> wrote:
> >>
> >> KP Singh <kpsingh@kernel.org> writes:
> >>
> >
> > [...]
> >
> >> >
> >>
> >> And that isn't at odds with the kernel being able to do it nor is it
> >> with what I posted.
> >>
> >> > If your build environment that signs the BPF program is compromised
> >> > and can inject arbitrary code, then signing does not help.  Can you
> >> > explain what a supply chain attack would look like here?
> >> >
> >>
> >> Most people here can read C code. The number of people that can read
> >> ebpf assembly metaprogramming code is much smaller. Compromising clang
> >> is one thing, compromising libbpf is another. Your proposal increases
> >> the attack surface with no observable benefit. If I was going to leave a
> >> hard-to-find backdoor into ring0, gen.c would be a fun place to explore
> >> doing it. Module and UEFI signature verification code doesn't live
> >> inside of GCC or Clang as set of meta-instructions that get emitted, and
> >> there are very good reasons for that.
> >>
> >> Further, since the signature verification code is unique for each and
> >> every program it needs to be verified/proved/tested for each and every
> >> program. Additionally, since all these checks are being forced outside
> >> of the kernel proper, with the insistence of keeping the LSM layer in
> >> the dark of the ultimate result, the only way to test that a program
> >> will fail if the map is corrupted is to physically corrupt each and
> >> every program and test that individually. That isn't "elegant" nor "user
> >> friendly" in any way, shape or form.
> >>
> >> >> subsystem.  Additionally, it is impossible to verify the code
> >> >> performing the signature verification, as it is uniquely regenerated
> >> >
> >> > The LSM needs to ensure that it allows trusted LOADER programs i.e.
> >> > with signatures and potentially trusted signed user-space binaries
> >> > with unsigned or delegated signing (this will be needed for Cilium and
> >> > bpftrace that dynamically generate BPF programs), that's a more
> >> > important aspect of the LSM policy from a BPF perspective.
> >> >
> >>
> >> I would like to be able to sign my programs please and have the kernel
> >> verify it was done correctly. Why are you insisting that I *don't* do
> >> that?  I'm yet to see any technical objection to doing that. Do you have
> >> one that you'd like to share at this point?
> >
> > The kernel allows a trusted loader that's signed with your private
> > key, that runs in the kernel context to delegate the verification.
> > This pattern of a trusted / delegated loader is going to be required
> > for many of the BPF use-cases that are out there (Cilium, bpftrace)
> > that dynamically generate eBPF programs.
> >
> > The technical objection is that:
> >
> > * It does not align with most BPF use-cases out there as most
> > use-cases need a trusted loader.
>
> No, it's definitely a use case. It's trivial to support both a trusted
> loader and a signature over the hash chain of supplied assets.
>
> > * Locks us into a UAPI, whereas a signed LOADER allows us to
> > incrementally build signing for all use-cases without compromising the
> > security properties.
> >
>
> Your proposal locks us into a UAPI as well. There is no way to make to
> do this via UAPI without making a UAPI design choice.
>
> > BPF's philosophy is that of flexibility and not locking the users into
> > a rigid in-kernel implementation and UAPI.
> >
>
> Then why are you locking us into a rigid
> only-signing-the-loader-is-allowed implementation?

I explained this before, the delegated / trusted loader is needed by
many BPF use-cases. A UAPI is forever, thus the lock-in.

- KP

>
> > - KP
> >
> >>
> >> > MAP_EXCLUSIVE is missing and is required which prevents maps from
> >> > being accessed by other programs as explained in the proposal.
> >> >
> >> > Please hold off on further iterations, I am working on a series and
> >> > will share these patches based on the design that was proposed.
> >> >
> >>
> >> So the premise here seems to be that people should only be allowed to
> >> sign trusted loaders, and that trusted loaders must additionally be
> >> authored by you, correct?
> >>
> >> When can we expect to see your patchset posted?
> >>
> >> >>
> >> >> for every program.
> >> >>
> >> >>
> >> >>
> >> >> 2. Timing of Signature Check
> >> >>
> >> >> This patchset moves the signature check to a point before
> >> >> security_bpf_prog_load is invoked, due to an unresolved discussion
> >> >> here:
> >> >
> >> > This is fine and what I had in mind, signature verification does not
> >> > need to happen in the verifier and the existing hooks are good enough.
> >> > I did not reply to Paul's comment since this is a fairly trivial
> >> > detail and would be obvious in the implementation that the verifier is
> >> > not the right place to check the signature anyways as the instruction
> >> > buffer is only stable pre-verification.
> >> >
> >> >> https://lore.kernel.org/linux-security-module/CAHC9VhTj3=ZXgrYMNA+G64zsOyZO+78uDs1g=kh91=GR5KypYg@mail.gmail.com/
> >> >> This change allows the LSM subsystem to be informed of the signature
> >> >> verification result—if it occurred—and the method used, all without
> >> >> introducing a new hook. It improves visibility and auditability,
> >> >> reducing the “trust me, friend” aspect of the original design.
> >> >
> >> >
> >> > On Wed, May 28, 2025 at 11:50 PM Blaise Boscaccy
> >> > <bboscaccy@linux.microsoft.com> wrote:
> >> >>
> >> >> As suggested or mandated by KP Singh
> >> >> https://lore.kernel.org/linux-security-module/CACYkzJ6VQUExfyt0=-FmXz46GHJh3d=FXh5j4KfexcEFbHV-vg@mail.gmail.com/,
> >> >> this patchset proposes and implements an alternative hash-chain
> >> >> algorithm for signature verification of BPF programs.
> >> >>
> >> >> This design diverges in two key ways:
> >> >>
> >> >> 1. Signature Strategy
> >> >>
> >> >> Two different signature strategies are
> >> >> implemented. One verifies only the signature of the loader program in
> >> >> the kernel, as described in the link above. The other verifies the
> >> >> program’s maps in-kernel via a hash chain.  The original design
> >> >> required loader programs to be “self-aborting” and embedded the
> >> >> terminal hash verification logic as metaprogramming code generation
> >> >> routines inside libbpf. While this patchset supports that scheme, it
> >> >> is considered undesirable in certain environments due to the potential
> >> >> for supply-chain attack vectors and the lack of visibility for the LSM
> >> >> subsystem.  Additionally, it is impossible to verify the code
> >> >> performing the signature verification, as it is uniquely regenerated
> >> >> for every program.
> >> >>
> >> >> 2. Timing of Signature Check
> >> >>
> >> >> This patchset moves the signature check to a point before
> >> >> security_bpf_prog_load is invoked, due to an unresolved discussion
> >> >> here:
> >> >> https://lore.kernel.org/linux-security-module/CAHC9VhTj3=ZXgrYMNA+G64zsOyZO+78uDs1g=kh91=GR5KypYg@mail.gmail.com/
> >> >> This change allows the LSM subsystem to be informed of the signature
> >> >> verification result—if it occurred—and the method used, all without
> >> >> introducing a new hook. It improves visibility and auditability,
> >> >> reducing the “trust me, friend” aspect of the original design.
> >> >>
> >> >>
> >> >> Blaise Boscaccy (3):
> >> >>   bpf: Add bpf_check_signature
> >> >>   bpf: Support light-skeleton signatures in autogenerated code
> >> >>   bpftool: Allow signing of light-skeleton programs
> >> >>
> >> >>  include/linux/bpf.h            |   2 +
> >> >>  include/linux/verification.h   |   1 +
> >> >>  include/uapi/linux/bpf.h       |   4 +
> >> >>  kernel/bpf/arraymap.c          |  11 +-
> >> >>  kernel/bpf/syscall.c           | 123 +++++++++++++++++++-
> >> >>  tools/bpf/bpftool/Makefile     |   4 +-
> >> >>  tools/bpf/bpftool/common.c     | 204 +++++++++++++++++++++++++++++++++
> >> >>  tools/bpf/bpftool/gen.c        |  66 ++++++++++-
> >> >>  tools/bpf/bpftool/main.c       |  24 +++-
> >> >>  tools/bpf/bpftool/main.h       |  23 ++++
> >> >>  tools/include/uapi/linux/bpf.h |   4 +
> >> >>  tools/lib/bpf/libbpf.h         |   4 +
> >> >>  tools/lib/bpf/skel_internal.h  |  28 ++++-
> >> >>  13 files changed, 491 insertions(+), 7 deletions(-)
> >> >>
> >> >> --
> >> >> 2.48.1
> >> >>

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

* Re: [PATCH 0/3] BPF signature verification
  2025-05-30 22:19         ` KP Singh
@ 2025-05-30 22:27           ` Blaise Boscaccy
  2025-05-30 22:47             ` KP Singh
  0 siblings, 1 reply; 25+ messages in thread
From: Blaise Boscaccy @ 2025-05-30 22:27 UTC (permalink / raw)
  To: KP Singh
  Cc: Paul Moore, jarkko, zeffron, xiyou.wangcong, kysrinivasan, code,
	linux-security-module, roberto.sassu, James.Bottomley,
	Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	David Howells, Lukas Wunner, Ignat Korchagin, Quentin Monnet,
	Jason Xing, Willem de Bruijn, Anton Protopopov, Jordan Rome,
	Martin Kelly, Alan Maguire, Matteo Croce, bpf, linux-kernel,
	keyrings, linux-crypto, kys

KP Singh <kpsingh@kernel.org> writes:

> On Sat, May 31, 2025 at 12:14 AM Blaise Boscaccy
> <bboscaccy@linux.microsoft.com> wrote:
>>
>> KP Singh <kpsingh@kernel.org> writes:
>>
>> > On Fri, May 30, 2025 at 11:19 PM Blaise Boscaccy
>> > <bboscaccy@linux.microsoft.com> wrote:
>> >>
>> >> KP Singh <kpsingh@kernel.org> writes:
>> >>
>> >
>> > [...]
>> >
>> >> >
>> >>
>> >> And that isn't at odds with the kernel being able to do it nor is it
>> >> with what I posted.
>> >>
>> >> > If your build environment that signs the BPF program is compromised
>> >> > and can inject arbitrary code, then signing does not help.  Can you
>> >> > explain what a supply chain attack would look like here?
>> >> >
>> >>
>> >> Most people here can read C code. The number of people that can read
>> >> ebpf assembly metaprogramming code is much smaller. Compromising clang
>> >> is one thing, compromising libbpf is another. Your proposal increases
>> >> the attack surface with no observable benefit. If I was going to leave a
>> >> hard-to-find backdoor into ring0, gen.c would be a fun place to explore
>> >> doing it. Module and UEFI signature verification code doesn't live
>> >> inside of GCC or Clang as set of meta-instructions that get emitted, and
>> >> there are very good reasons for that.
>> >>
>> >> Further, since the signature verification code is unique for each and
>> >> every program it needs to be verified/proved/tested for each and every
>> >> program. Additionally, since all these checks are being forced outside
>> >> of the kernel proper, with the insistence of keeping the LSM layer in
>> >> the dark of the ultimate result, the only way to test that a program
>> >> will fail if the map is corrupted is to physically corrupt each and
>> >> every program and test that individually. That isn't "elegant" nor "user
>> >> friendly" in any way, shape or form.
>> >>
>> >> >> subsystem.  Additionally, it is impossible to verify the code
>> >> >> performing the signature verification, as it is uniquely regenerated
>> >> >
>> >> > The LSM needs to ensure that it allows trusted LOADER programs i.e.
>> >> > with signatures and potentially trusted signed user-space binaries
>> >> > with unsigned or delegated signing (this will be needed for Cilium and
>> >> > bpftrace that dynamically generate BPF programs), that's a more
>> >> > important aspect of the LSM policy from a BPF perspective.
>> >> >
>> >>
>> >> I would like to be able to sign my programs please and have the kernel
>> >> verify it was done correctly. Why are you insisting that I *don't* do
>> >> that?  I'm yet to see any technical objection to doing that. Do you have
>> >> one that you'd like to share at this point?
>> >
>> > The kernel allows a trusted loader that's signed with your private
>> > key, that runs in the kernel context to delegate the verification.
>> > This pattern of a trusted / delegated loader is going to be required
>> > for many of the BPF use-cases that are out there (Cilium, bpftrace)
>> > that dynamically generate eBPF programs.
>> >
>> > The technical objection is that:
>> >
>> > * It does not align with most BPF use-cases out there as most
>> > use-cases need a trusted loader.
>>
>> No, it's definitely a use case. It's trivial to support both a trusted
>> loader and a signature over the hash chain of supplied assets.
>>
>> > * Locks us into a UAPI, whereas a signed LOADER allows us to
>> > incrementally build signing for all use-cases without compromising the
>> > security properties.
>> >
>>
>> Your proposal locks us into a UAPI as well. There is no way to make to
>> do this via UAPI without making a UAPI design choice.
>>
>> > BPF's philosophy is that of flexibility and not locking the users into
>> > a rigid in-kernel implementation and UAPI.
>> >
>>
>> Then why are you locking us into a rigid
>> only-signing-the-loader-is-allowed implementation?
>
> I explained this before, the delegated / trusted loader is needed by
> many BPF use-cases. A UAPI is forever, thus the lock-in.
>

Again, I'm not following. What is technically wrong with supporting both
signing a loader only and allowing for the signature of multiple
passed-in assets? It's trivial to support both and any path forward will
force a UAPI lock-in.

Do you simply feel that it isn't a valid use case and therefore we
shouldn't be allowed to do it?

> - KP
>
>>
>> > - KP
>> >
>> >>
>> >> > MAP_EXCLUSIVE is missing and is required which prevents maps from
>> >> > being accessed by other programs as explained in the proposal.
>> >> >
>> >> > Please hold off on further iterations, I am working on a series and
>> >> > will share these patches based on the design that was proposed.
>> >> >
>> >>
>> >> So the premise here seems to be that people should only be allowed to
>> >> sign trusted loaders, and that trusted loaders must additionally be
>> >> authored by you, correct?
>> >>
>> >> When can we expect to see your patchset posted?
>> >>
>> >> >>
>> >> >> for every program.
>> >> >>
>> >> >>
>> >> >>
>> >> >> 2. Timing of Signature Check
>> >> >>
>> >> >> This patchset moves the signature check to a point before
>> >> >> security_bpf_prog_load is invoked, due to an unresolved discussion
>> >> >> here:
>> >> >
>> >> > This is fine and what I had in mind, signature verification does not
>> >> > need to happen in the verifier and the existing hooks are good enough.
>> >> > I did not reply to Paul's comment since this is a fairly trivial
>> >> > detail and would be obvious in the implementation that the verifier is
>> >> > not the right place to check the signature anyways as the instruction
>> >> > buffer is only stable pre-verification.
>> >> >
>> >> >> https://lore.kernel.org/linux-security-module/CAHC9VhTj3=ZXgrYMNA+G64zsOyZO+78uDs1g=kh91=GR5KypYg@mail.gmail.com/
>> >> >> This change allows the LSM subsystem to be informed of the signature
>> >> >> verification result—if it occurred—and the method used, all without
>> >> >> introducing a new hook. It improves visibility and auditability,
>> >> >> reducing the “trust me, friend” aspect of the original design.
>> >> >
>> >> >
>> >> > On Wed, May 28, 2025 at 11:50 PM Blaise Boscaccy
>> >> > <bboscaccy@linux.microsoft.com> wrote:
>> >> >>
>> >> >> As suggested or mandated by KP Singh
>> >> >> https://lore.kernel.org/linux-security-module/CACYkzJ6VQUExfyt0=-FmXz46GHJh3d=FXh5j4KfexcEFbHV-vg@mail.gmail.com/,
>> >> >> this patchset proposes and implements an alternative hash-chain
>> >> >> algorithm for signature verification of BPF programs.
>> >> >>
>> >> >> This design diverges in two key ways:
>> >> >>
>> >> >> 1. Signature Strategy
>> >> >>
>> >> >> Two different signature strategies are
>> >> >> implemented. One verifies only the signature of the loader program in
>> >> >> the kernel, as described in the link above. The other verifies the
>> >> >> program’s maps in-kernel via a hash chain.  The original design
>> >> >> required loader programs to be “self-aborting” and embedded the
>> >> >> terminal hash verification logic as metaprogramming code generation
>> >> >> routines inside libbpf. While this patchset supports that scheme, it
>> >> >> is considered undesirable in certain environments due to the potential
>> >> >> for supply-chain attack vectors and the lack of visibility for the LSM
>> >> >> subsystem.  Additionally, it is impossible to verify the code
>> >> >> performing the signature verification, as it is uniquely regenerated
>> >> >> for every program.
>> >> >>
>> >> >> 2. Timing of Signature Check
>> >> >>
>> >> >> This patchset moves the signature check to a point before
>> >> >> security_bpf_prog_load is invoked, due to an unresolved discussion
>> >> >> here:
>> >> >> https://lore.kernel.org/linux-security-module/CAHC9VhTj3=ZXgrYMNA+G64zsOyZO+78uDs1g=kh91=GR5KypYg@mail.gmail.com/
>> >> >> This change allows the LSM subsystem to be informed of the signature
>> >> >> verification result—if it occurred—and the method used, all without
>> >> >> introducing a new hook. It improves visibility and auditability,
>> >> >> reducing the “trust me, friend” aspect of the original design.
>> >> >>
>> >> >>
>> >> >> Blaise Boscaccy (3):
>> >> >>   bpf: Add bpf_check_signature
>> >> >>   bpf: Support light-skeleton signatures in autogenerated code
>> >> >>   bpftool: Allow signing of light-skeleton programs
>> >> >>
>> >> >>  include/linux/bpf.h            |   2 +
>> >> >>  include/linux/verification.h   |   1 +
>> >> >>  include/uapi/linux/bpf.h       |   4 +
>> >> >>  kernel/bpf/arraymap.c          |  11 +-
>> >> >>  kernel/bpf/syscall.c           | 123 +++++++++++++++++++-
>> >> >>  tools/bpf/bpftool/Makefile     |   4 +-
>> >> >>  tools/bpf/bpftool/common.c     | 204 +++++++++++++++++++++++++++++++++
>> >> >>  tools/bpf/bpftool/gen.c        |  66 ++++++++++-
>> >> >>  tools/bpf/bpftool/main.c       |  24 +++-
>> >> >>  tools/bpf/bpftool/main.h       |  23 ++++
>> >> >>  tools/include/uapi/linux/bpf.h |   4 +
>> >> >>  tools/lib/bpf/libbpf.h         |   4 +
>> >> >>  tools/lib/bpf/skel_internal.h  |  28 ++++-
>> >> >>  13 files changed, 491 insertions(+), 7 deletions(-)
>> >> >>
>> >> >> --
>> >> >> 2.48.1
>> >> >>

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

* Re: [PATCH 0/3] BPF signature verification
  2025-05-30 22:27           ` Blaise Boscaccy
@ 2025-05-30 22:47             ` KP Singh
  2025-05-30 23:25               ` Blaise Boscaccy
  0 siblings, 1 reply; 25+ messages in thread
From: KP Singh @ 2025-05-30 22:47 UTC (permalink / raw)
  To: Blaise Boscaccy
  Cc: Paul Moore, jarkko, zeffron, xiyou.wangcong, kysrinivasan, code,
	linux-security-module, roberto.sassu, James.Bottomley,
	Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	David Howells, Lukas Wunner, Ignat Korchagin, Quentin Monnet,
	Jason Xing, Willem de Bruijn, Anton Protopopov, Jordan Rome,
	Martin Kelly, Alan Maguire, Matteo Croce, bpf, linux-kernel,
	keyrings, linux-crypto, kys

On Sat, May 31, 2025 at 12:27 AM Blaise Boscaccy
<bboscaccy@linux.microsoft.com> wrote:
>
> KP Singh <kpsingh@kernel.org> writes:
>
> > On Sat, May 31, 2025 at 12:14 AM Blaise Boscaccy
> > <bboscaccy@linux.microsoft.com> wrote:
> >>
> >> KP Singh <kpsingh@kernel.org> writes:
> >>
> >> > On Fri, May 30, 2025 at 11:19 PM Blaise Boscaccy
> >> > <bboscaccy@linux.microsoft.com> wrote:
> >> >>
> >> >> KP Singh <kpsingh@kernel.org> writes:
> >> >>
> >> >
> >> > [...]
> >> >
> >> >> >
> >> >>
> >> >> And that isn't at odds with the kernel being able to do it nor is it
> >> >> with what I posted.
> >> >>
> >> >> > If your build environment that signs the BPF program is compromised
> >> >> > and can inject arbitrary code, then signing does not help.  Can you
> >> >> > explain what a supply chain attack would look like here?
> >> >> >
> >> >>
> >> >> Most people here can read C code. The number of people that can read
> >> >> ebpf assembly metaprogramming code is much smaller. Compromising clang
> >> >> is one thing, compromising libbpf is another. Your proposal increases
> >> >> the attack surface with no observable benefit. If I was going to leave a
> >> >> hard-to-find backdoor into ring0, gen.c would be a fun place to explore
> >> >> doing it. Module and UEFI signature verification code doesn't live
> >> >> inside of GCC or Clang as set of meta-instructions that get emitted, and
> >> >> there are very good reasons for that.
> >> >>
> >> >> Further, since the signature verification code is unique for each and
> >> >> every program it needs to be verified/proved/tested for each and every
> >> >> program. Additionally, since all these checks are being forced outside
> >> >> of the kernel proper, with the insistence of keeping the LSM layer in
> >> >> the dark of the ultimate result, the only way to test that a program
> >> >> will fail if the map is corrupted is to physically corrupt each and
> >> >> every program and test that individually. That isn't "elegant" nor "user
> >> >> friendly" in any way, shape or form.
> >> >>
> >> >> >> subsystem.  Additionally, it is impossible to verify the code
> >> >> >> performing the signature verification, as it is uniquely regenerated
> >> >> >
> >> >> > The LSM needs to ensure that it allows trusted LOADER programs i.e.
> >> >> > with signatures and potentially trusted signed user-space binaries
> >> >> > with unsigned or delegated signing (this will be needed for Cilium and
> >> >> > bpftrace that dynamically generate BPF programs), that's a more
> >> >> > important aspect of the LSM policy from a BPF perspective.
> >> >> >
> >> >>
> >> >> I would like to be able to sign my programs please and have the kernel
> >> >> verify it was done correctly. Why are you insisting that I *don't* do
> >> >> that?  I'm yet to see any technical objection to doing that. Do you have
> >> >> one that you'd like to share at this point?
> >> >
> >> > The kernel allows a trusted loader that's signed with your private
> >> > key, that runs in the kernel context to delegate the verification.
> >> > This pattern of a trusted / delegated loader is going to be required
> >> > for many of the BPF use-cases that are out there (Cilium, bpftrace)
> >> > that dynamically generate eBPF programs.
> >> >
> >> > The technical objection is that:
> >> >
> >> > * It does not align with most BPF use-cases out there as most
> >> > use-cases need a trusted loader.
> >>
> >> No, it's definitely a use case. It's trivial to support both a trusted
> >> loader and a signature over the hash chain of supplied assets.
> >>
> >> > * Locks us into a UAPI, whereas a signed LOADER allows us to
> >> > incrementally build signing for all use-cases without compromising the
> >> > security properties.
> >> >
> >>
> >> Your proposal locks us into a UAPI as well. There is no way to make to
> >> do this via UAPI without making a UAPI design choice.
> >>
> >> > BPF's philosophy is that of flexibility and not locking the users into
> >> > a rigid in-kernel implementation and UAPI.
> >> >
> >>
> >> Then why are you locking us into a rigid
> >> only-signing-the-loader-is-allowed implementation?
> >
> > I explained this before, the delegated / trusted loader is needed by
> > many BPF use-cases. A UAPI is forever, thus the lock-in.
> >
>
> Again, I'm not following. What is technically wrong with supporting both
> signing a loader only and allowing for the signature of multiple
> passed-in assets? It's trivial to support both and any path forward will
> force a UAPI lock-in.
>
> Do you simply feel that it isn't a valid use case and therefore we
> shouldn't be allowed to do it?
>

I am saying both are not needed when one (trusted loader) handles all
cases. You are writing / generating the loader anyways, you have the
private key, the only thing to be done is add a few lines to the
loader to verify an embedded hash.

Let's have this discussion in the patch series, much easier to discuss
with the code.

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

* Re: [PATCH 0/3] BPF signature verification
  2025-05-30 22:47             ` KP Singh
@ 2025-05-30 23:25               ` Blaise Boscaccy
  2025-05-30 23:32                 ` KP Singh
  0 siblings, 1 reply; 25+ messages in thread
From: Blaise Boscaccy @ 2025-05-30 23:25 UTC (permalink / raw)
  To: KP Singh
  Cc: Paul Moore, jarkko, zeffron, xiyou.wangcong, kysrinivasan, code,
	linux-security-module, roberto.sassu, James.Bottomley,
	Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	David Howells, Lukas Wunner, Ignat Korchagin, Quentin Monnet,
	Jason Xing, Willem de Bruijn, Anton Protopopov, Jordan Rome,
	Martin Kelly, Alan Maguire, Matteo Croce, bpf, linux-kernel,
	keyrings, linux-crypto, kys

KP Singh <kpsingh@kernel.org> writes:

> On Sat, May 31, 2025 at 12:27 AM Blaise Boscaccy
> <bboscaccy@linux.microsoft.com> wrote:
>>
>> KP Singh <kpsingh@kernel.org> writes:
>>
>> > On Sat, May 31, 2025 at 12:14 AM Blaise Boscaccy
>> > <bboscaccy@linux.microsoft.com> wrote:
>> >>
>> >> KP Singh <kpsingh@kernel.org> writes:
>> >>
>> >> > On Fri, May 30, 2025 at 11:19 PM Blaise Boscaccy
>> >> > <bboscaccy@linux.microsoft.com> wrote:
>> >> >>
>> >> >> KP Singh <kpsingh@kernel.org> writes:
>> >> >>
>> >> >
>> >> > [...]
>> >> >
>> >> >> >
>> >> >>
>> >> >> And that isn't at odds with the kernel being able to do it nor is it
>> >> >> with what I posted.
>> >> >>
>> >> >> > If your build environment that signs the BPF program is compromised
>> >> >> > and can inject arbitrary code, then signing does not help.  Can you
>> >> >> > explain what a supply chain attack would look like here?
>> >> >> >
>> >> >>
>> >> >> Most people here can read C code. The number of people that can read
>> >> >> ebpf assembly metaprogramming code is much smaller. Compromising clang
>> >> >> is one thing, compromising libbpf is another. Your proposal increases
>> >> >> the attack surface with no observable benefit. If I was going to leave a
>> >> >> hard-to-find backdoor into ring0, gen.c would be a fun place to explore
>> >> >> doing it. Module and UEFI signature verification code doesn't live
>> >> >> inside of GCC or Clang as set of meta-instructions that get emitted, and
>> >> >> there are very good reasons for that.
>> >> >>
>> >> >> Further, since the signature verification code is unique for each and
>> >> >> every program it needs to be verified/proved/tested for each and every
>> >> >> program. Additionally, since all these checks are being forced outside
>> >> >> of the kernel proper, with the insistence of keeping the LSM layer in
>> >> >> the dark of the ultimate result, the only way to test that a program
>> >> >> will fail if the map is corrupted is to physically corrupt each and
>> >> >> every program and test that individually. That isn't "elegant" nor "user
>> >> >> friendly" in any way, shape or form.
>> >> >>
>> >> >> >> subsystem.  Additionally, it is impossible to verify the code
>> >> >> >> performing the signature verification, as it is uniquely regenerated
>> >> >> >
>> >> >> > The LSM needs to ensure that it allows trusted LOADER programs i.e.
>> >> >> > with signatures and potentially trusted signed user-space binaries
>> >> >> > with unsigned or delegated signing (this will be needed for Cilium and
>> >> >> > bpftrace that dynamically generate BPF programs), that's a more
>> >> >> > important aspect of the LSM policy from a BPF perspective.
>> >> >> >
>> >> >>
>> >> >> I would like to be able to sign my programs please and have the kernel
>> >> >> verify it was done correctly. Why are you insisting that I *don't* do
>> >> >> that?  I'm yet to see any technical objection to doing that. Do you have
>> >> >> one that you'd like to share at this point?
>> >> >
>> >> > The kernel allows a trusted loader that's signed with your private
>> >> > key, that runs in the kernel context to delegate the verification.
>> >> > This pattern of a trusted / delegated loader is going to be required
>> >> > for many of the BPF use-cases that are out there (Cilium, bpftrace)
>> >> > that dynamically generate eBPF programs.
>> >> >
>> >> > The technical objection is that:
>> >> >
>> >> > * It does not align with most BPF use-cases out there as most
>> >> > use-cases need a trusted loader.
>> >>
>> >> No, it's definitely a use case. It's trivial to support both a trusted
>> >> loader and a signature over the hash chain of supplied assets.
>> >>
>> >> > * Locks us into a UAPI, whereas a signed LOADER allows us to
>> >> > incrementally build signing for all use-cases without compromising the
>> >> > security properties.
>> >> >
>> >>
>> >> Your proposal locks us into a UAPI as well. There is no way to make to
>> >> do this via UAPI without making a UAPI design choice.
>> >>
>> >> > BPF's philosophy is that of flexibility and not locking the users into
>> >> > a rigid in-kernel implementation and UAPI.
>> >> >
>> >>
>> >> Then why are you locking us into a rigid
>> >> only-signing-the-loader-is-allowed implementation?
>> >
>> > I explained this before, the delegated / trusted loader is needed by
>> > many BPF use-cases. A UAPI is forever, thus the lock-in.
>> >
>>
>> Again, I'm not following. What is technically wrong with supporting both
>> signing a loader only and allowing for the signature of multiple
>> passed-in assets? It's trivial to support both and any path forward will
>> force a UAPI lock-in.
>>
>> Do you simply feel that it isn't a valid use case and therefore we
>> shouldn't be allowed to do it?
>>
>
> I am saying both are not needed when one (trusted loader) handles all
> cases. You are writing / generating the loader anyways, you have the
> private key, the only thing to be done is add a few lines to the
> loader to verify an embedded hash.
>

And I'm saying that they are, based on wanting visibility in the LSM
layer, passing that along to the end user, and wanting to be able to
show correctness, along with mitigating an entire vector of supply chain
attacks targeting gen.c.

So in summary, your objection to this is that you feel it's simply "not
needed", and those above risks/design problems aren't actually an issue?

> Let's have this discussion in the patch series, much easier to discuss
> with the code.

I think we've all been waiting for that. Yes, lets.

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

* Re: [PATCH 0/3] BPF signature verification
  2025-05-30 23:25               ` Blaise Boscaccy
@ 2025-05-30 23:32                 ` KP Singh
  2025-06-02 15:01                   ` Blaise Boscaccy
  0 siblings, 1 reply; 25+ messages in thread
From: KP Singh @ 2025-05-30 23:32 UTC (permalink / raw)
  To: Blaise Boscaccy
  Cc: Paul Moore, jarkko, zeffron, xiyou.wangcong, kysrinivasan, code,
	linux-security-module, roberto.sassu, James.Bottomley,
	Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	David Howells, Lukas Wunner, Ignat Korchagin, Quentin Monnet,
	Jason Xing, Willem de Bruijn, Anton Protopopov, Jordan Rome,
	Martin Kelly, Alan Maguire, Matteo Croce, bpf, linux-kernel,
	keyrings, linux-crypto, kys

> And I'm saying that they are, based on wanting visibility in the LSM
> layer, passing that along to the end user, and wanting to be able to
> show correctness, along with mitigating an entire vector of supply chain
> attacks targeting gen.c.

What supply chain attack?I asked this earlier, you never replied, what
does a supply chain attack here really look like?


- KP

>
> So in summary, your objection to this is that you feel it's simply "not
> needed", and those above risks/design problems aren't actually an issue?
>
> > Let's have this discussion in the patch series, much easier to discuss
> > with the code.
>
> I think we've all been waiting for that. Yes, lets.

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

* Re: [PATCH 0/3] BPF signature verification
  2025-05-30 23:32                 ` KP Singh
@ 2025-06-02 15:01                   ` Blaise Boscaccy
  0 siblings, 0 replies; 25+ messages in thread
From: Blaise Boscaccy @ 2025-06-02 15:01 UTC (permalink / raw)
  To: KP Singh
  Cc: Paul Moore, jarkko, zeffron, xiyou.wangcong, kysrinivasan, code,
	linux-security-module, roberto.sassu, James.Bottomley,
	Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	David Howells, Lukas Wunner, Ignat Korchagin, Quentin Monnet,
	Jason Xing, Willem de Bruijn, Anton Protopopov, Jordan Rome,
	Martin Kelly, Alan Maguire, Matteo Croce, bpf, linux-kernel,
	keyrings, linux-crypto, kys

KP Singh <kpsingh@kernel.org> writes:

>> And I'm saying that they are, based on wanting visibility in the LSM
>> layer, passing that along to the end user, and wanting to be able to
>> show correctness, along with mitigating an entire vector of supply chain
>> attacks targeting gen.c.
>
> What supply chain attack?I asked this earlier, you never replied, what
> does a supply chain attack here really look like?
>
>
I responded to that here:
https://lore.kernel.org/linux-security-module/87iklhn6ed.fsf@microsoft.com/

Warmest Regards,
Blaise

> - KP
>
>>
>> So in summary, your objection to this is that you feel it's simply "not
>> needed", and those above risks/design problems aren't actually an issue?
>>
>> > Let's have this discussion in the patch series, much easier to discuss
>> > with the code.
>>
>> I think we've all been waiting for that. Yes, lets.

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

* Re: [PATCH 1/3] bpf: Add bpf_check_signature
  2025-05-28 21:49 ` [PATCH 1/3] bpf: Add bpf_check_signature Blaise Boscaccy
  2025-05-29 10:11   ` Lukas Wunner
@ 2025-06-02 22:40   ` Paul Moore
  2025-06-04 16:25   ` Jarkko Sakkinen
  2 siblings, 0 replies; 25+ messages in thread
From: Paul Moore @ 2025-06-02 22:40 UTC (permalink / raw)
  To: Blaise Boscaccy
  Cc: jarkko, zeffron, xiyou.wangcong, kysrinivasan, code,
	linux-security-module, roberto.sassu, James.Bottomley,
	Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	David Howells, Lukas Wunner, Ignat Korchagin, Quentin Monnet,
	Jason Xing, Willem de Bruijn, Anton Protopopov, Jordan Rome,
	Martin Kelly, Alan Maguire, Matteo Croce, bpf, linux-kernel,
	keyrings, linux-crypto

On Wed, May 28, 2025 at 5:50 PM Blaise Boscaccy
<bboscaccy@linux.microsoft.com> wrote:
>
> This introduces signature verification for eBPF programs inside of the
> bpf subsystem. Two signature validation schemes are included, one that
> only checks the instruction buffer, and another that checks over a
> hash chain constructed from the program and a list of maps. The
> alternative algorithm is designed to provide support to scenarios
> where having self-aborting light-skeletons or signature checking
> living outside the kernel-proper is insufficient or undesirable.
>
> An abstract hash method is introduced to allow calculating the hash of
> maps, only arrays are implemented at this time.
>
> A simple UAPI is introduced to provide passing signature information.
>
> The signature check is performed before the call to
> security_bpf_prog_load. This allows the LSM subsystem to be clued into
> the result of the signature check, whilst granting knowledge of the
> method and apparatus which was employed.
>
> Signed-off-by: Blaise Boscaccy <bboscaccy@linux.microsoft.com>
> ---
>  include/linux/bpf.h            |   2 +
>  include/linux/verification.h   |   1 +
>  include/uapi/linux/bpf.h       |   4 ++
>  kernel/bpf/arraymap.c          |  11 ++-
>  kernel/bpf/syscall.c           | 123 ++++++++++++++++++++++++++++++++-
>  tools/include/uapi/linux/bpf.h |   4 ++
>  6 files changed, 143 insertions(+), 2 deletions(-)

...

> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> index 64c3393e8270..7dc35681d3f8 100644
> --- a/kernel/bpf/syscall.c
> +++ b/kernel/bpf/syscall.c
> @@ -2753,8 +2764,113 @@ static bool is_perfmon_prog_type(enum bpf_prog_type prog_type)
>         }
>  }
>
> +static int bpf_check_signature(struct bpf_prog *prog, union bpf_attr *attr, bpfptr_t uattr,
> +                              __u32 uattr_size)
> +{
> +       u64 hash[4];
> +       u64 buffer[8];
> +       int err;
> +       char *signature;
> +       int *used_maps;
> +       int n;
> +       int map_fd;
> +       struct bpf_map *map;
> +
> +       if (!attr->signature)
> +               return 0;
> +
> +       signature = kmalloc(attr->signature_size, GFP_KERNEL);
> +       if (!signature) {
> +               err = -ENOMEM;
> +               goto out;
> +       }
> +
> +       if (copy_from_bpfptr(signature,
> +                            make_bpfptr(attr->signature, uattr.is_kernel),
> +                            attr->signature_size) != 0) {
> +               err = -EINVAL;
> +               goto free_sig;
> +       }
> +
> +       if (!attr->signature_maps_size) {
> +               sha256((u8 *)prog->insnsi, prog->len * sizeof(struct bpf_insn), (u8 *)&hash);
> +               err = verify_pkcs7_signature(hash, sizeof(hash), signature, attr->signature_size,
> +                                    VERIFY_USE_SECONDARY_KEYRING,
> +                                    VERIFYING_EBPF_SIGNATURE,
> +                                    NULL, NULL);
> +       } else {
> +               used_maps = kmalloc_array(attr->signature_maps_size,
> +                                         sizeof(*used_maps), GFP_KERNEL);
> +               if (!used_maps) {
> +                       err = -ENOMEM;
> +                       goto free_sig;
> +               }
> +               n = attr->signature_maps_size;
> +               n--;
> +
> +               err = copy_from_bpfptr_offset(&map_fd, make_bpfptr(attr->fd_array, uattr.is_kernel),
> +                                             used_maps[n] * sizeof(map_fd),
> +                                             sizeof(map_fd));
> +               if (err < 0)
> +                       goto free_maps;
> +
> +               /* calculate the terminal hash */
> +               CLASS(fd, f)(map_fd);
> +               map = __bpf_map_get(f);
> +               if (IS_ERR(map)) {
> +                       err = PTR_ERR(map);
> +                       goto free_maps;
> +               }
> +               if (__map_get_hash(map, (u8 *)hash)) {
> +                       err = -EINVAL;
> +                       goto free_maps;
> +               }
> +
> +               n--;
> +               /* calculate a link in the hash chain */
> +               while (n >= 0) {
> +                       memcpy(buffer, hash, sizeof(hash));
> +                       err = copy_from_bpfptr_offset(&map_fd,
> +                                                     make_bpfptr(attr->fd_array, uattr.is_kernel),
> +                                                     used_maps[n] * sizeof(map_fd),
> +                                                     sizeof(map_fd));
> +                       if (err < 0)
> +                               goto free_maps;
> +
> +                       CLASS(fd, f)(map_fd);
> +                       map = __bpf_map_get(f);
> +                       if (!map) {
> +                               err = -EINVAL;
> +                               goto free_maps;
> +                       }
> +                       if (__map_get_hash(map, (u8 *)buffer+4)) {
> +                               err = -EINVAL;
> +                               goto free_maps;
> +                       }
> +                       sha256((u8 *)buffer, sizeof(buffer), (u8 *)&hash);

James' comment about using the hash from the PKCS7 data makes a lot of
sense.  I'm not a kernel crypto expert, but if looks like if you call
pkcs7_parse_message() you should be able to get the hash algorithm
from pkcs7_message->signed_infos->sig->hash_algo.

I imagine there might be user/admin concerns over which algorithms
would be considered acceptable for a signature verification, but I
suppose one could make the argument that if you don't trust that
algorithm it shouldn't be enabled in the kernel.

> +                       n--;
> +               }
> +               /* calculate the root hash and verify it's signature */
> +               sha256((u8 *)prog->insnsi, prog->len * sizeof(struct bpf_insn), (u8 *)&buffer);
> +               memcpy(buffer+4, hash, sizeof(hash));
> +               sha256((u8 *)buffer, sizeof(buffer), (u8 *)&hash);
> +               err = verify_pkcs7_signature(hash, sizeof(hash), signature, attr->signature_size,
> +                                    VERIFY_USE_SECONDARY_KEYRING,
> +                                    VERIFYING_EBPF_SIGNATURE,
> +                                    NULL, NULL);
> +free_maps:
> +               kfree(used_maps);
> +       }
> +
> +free_sig:
> +       kfree(signature);
> +out:
> +       prog->aux->signature_verified = !err;

Considering this code supports two signature schemes, signed loader
(with implied loader verification of maps) and signed loader + maps,
it seems like it might be a good idea to have two flags to indicate
what has been verified in bpf_check_signature(); a "prog_sig_verified"
(or similar) flag to indicate the program has been verified and a
"maps_sig_verified" (or similar) to indicate the maps have been
verified.

Beyond that, I wanted to talk a bit about the two different signature
schemes and why I think there is value in supporting both.  The
discussion was happening in patch 0/3, but it looks like KP wanted to
move the discussion away from the cover letter and into that patch, so
I'm doing that here ...

The loader (+ implicit loader verification of maps w/original program)
signature verification scheme has been requested by Alexei/KP, and
that's fine, the code is trivial and if the user/admin is satisfied
with that as a solution, great.  However, the loader + map signature
verification scheme has some advantages and helps satisfy some
requirements that are not satisfied by only verifying the loader and
relying on the loader to verify the original program stored in the
maps.  One obvious advantage is that the lskel loader is much simpler
in this case as it doesn't need to worry about verification of the
program maps as that has already been done in bpf_check_signature().
I'm sure there are probably some other obvious reasons, but beyond the
one mentioned above, the other advantages that I'm interested in are a
little less obvious, or at least I haven't seen them brought up yet.
As I mentioned in an earlier thread, it's important to have the LSM
hook that handles authorization of a BPF program load *after* the BPF
program's signature has been verified.  This is not simply because the
LSM implementation might want to enforce and access control on a BPF
program load due to the signature state (signature verified vs no
signature), but also because the LSM might want to measure system
state and/or provide a record of the operation.  If we only verify the
lskel loader, at the point in time that the security_bpf_prog_load()
hook is called, we haven't properly verified both the loader and the
original BPF program stored in the map, that doesn't happen until much
later when the lskel loader executes.  Yes, I understand that may
sound very pedantic and fussy, but there are users who care very much
about those details, and if they see an event in the logs that
indicates that the BPF program signature has been verified as "good",
they need that log event to be fully, 100% true, and not have an
asterix of "only the lskel loader has been verified, the original BPF
program will potentially be verified later without any additional
events being logged to indicate the verification".

Considering that Blaise has proposed something which satisfies both
the loader-only and loader+maps signature requirements, I don't
understand the objections.  KP described two technical objections in
his replies to patch 0/3:

1. "It does not align with most BPF use-cases out there as most
use-cases need a trusted loader."
2. "Locks us into a UAPI, whereas a signed LOADER allows us to
incrementally build signing for all use-cases without compromising the
security properties."

In response to objection #1, the approach Blaise has described here
fully supports signing only the lskel loader and leaving it to the
loader to verify the original BPF program maps.  The "trusted loader"
use cases are fully supported, as the loader+maps scheme does not
prevent the loader-only signature scheme.

In response to objection #2, honestly this seems like an extension to
objection #1.  The trusted loader-only signature scheme is fully
supported.  Yes, adding support for either signature schemes is an
extension to the BPF program loading UAPI, but both schemes are
optional and supporting both is very much in line with BPF's stated
philosophy of "flexibility and not locking the users into a rigid
in-kernel implementation and UAPI."

> +       return err;
> +}
> +

-- 
paul-moore.com

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

* Re: [PATCH 0/3] BPF signature verification
  2025-05-28 21:49 [PATCH 0/3] BPF signature verification Blaise Boscaccy
                   ` (3 preceding siblings ...)
  2025-05-30 16:42 ` [PATCH 0/3] BPF signature verification KP Singh
@ 2025-06-04 16:22 ` Jarkko Sakkinen
  4 siblings, 0 replies; 25+ messages in thread
From: Jarkko Sakkinen @ 2025-06-04 16:22 UTC (permalink / raw)
  To: Blaise Boscaccy
  Cc: Paul Moore, zeffron, xiyou.wangcong, kysrinivasan, code,
	linux-security-module, roberto.sassu, James.Bottomley,
	Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	David Howells, Lukas Wunner, Ignat Korchagin, Quentin Monnet,
	Jason Xing, Willem de Bruijn, Anton Protopopov, Jordan Rome,
	Martin Kelly, Alan Maguire, Matteo Croce, bpf, linux-kernel,
	keyrings, linux-crypto

On Wed, May 28, 2025 at 02:49:02PM -0700, Blaise Boscaccy wrote:
> As suggested or mandated by KP Singh
> https://lore.kernel.org/linux-security-module/CACYkzJ6VQUExfyt0=-FmXz46GHJh3d=FXh5j4KfexcEFbHV-vg@mail.gmail.com/,
> this patchset proposes and implements an alternative hash-chain
> algorithm for signature verification of BPF programs.
> 
> This design diverges in two key ways:
> 
> 1. Signature Strategy
> 
> Two different signature strategies are
> implemented. One verifies only the signature of the loader program in
> the kernel, as described in the link above. The other verifies the

Describe "the one" briefly, despite having the link.  Label them A and
B, and also, why there are two strategies. Then you can use those labels
as references later on in this description.

> program’s maps in-kernel via a hash chain.  The original design
> required loader programs to be “self-aborting” and embedded the
> terminal hash verification logic as metaprogramming code generation
> routines inside libbpf. While this patchset supports that scheme, it
> is considered undesirable in certain environments due to the potential
> for supply-chain attack vectors and the lack of visibility for the LSM
> subsystem.  Additionally, it is impossible to verify the code
> performing the signature verification, as it is uniquely regenerated
> for every program.
> 
> 2. Timing of Signature Check
> 
> This patchset moves the signature check to a point before
> security_bpf_prog_load is invoked, due to an unresolved discussion
> here:
> https://lore.kernel.org/linux-security-module/CAHC9VhTj3=ZXgrYMNA+G64zsOyZO+78uDs1g=kh91=GR5KypYg@mail.gmail.com/
> This change allows the LSM subsystem to be informed of the signature
> verification result—if it occurred—and the method used, all without
> introducing a new hook. It improves visibility and auditability,
> reducing the “trust me, friend” aspect of the original design.
> 
> 
> Blaise Boscaccy (3):
>   bpf: Add bpf_check_signature
>   bpf: Support light-skeleton signatures in autogenerated code
>   bpftool: Allow signing of light-skeleton programs
> 
>  include/linux/bpf.h            |   2 +
>  include/linux/verification.h   |   1 +
>  include/uapi/linux/bpf.h       |   4 +
>  kernel/bpf/arraymap.c          |  11 +-
>  kernel/bpf/syscall.c           | 123 +++++++++++++++++++-
>  tools/bpf/bpftool/Makefile     |   4 +-
>  tools/bpf/bpftool/common.c     | 204 +++++++++++++++++++++++++++++++++
>  tools/bpf/bpftool/gen.c        |  66 ++++++++++-
>  tools/bpf/bpftool/main.c       |  24 +++-
>  tools/bpf/bpftool/main.h       |  23 ++++
>  tools/include/uapi/linux/bpf.h |   4 +
>  tools/lib/bpf/libbpf.h         |   4 +
>  tools/lib/bpf/skel_internal.h  |  28 ++++-
>  13 files changed, 491 insertions(+), 7 deletions(-)
> 
> -- 
> 2.48.1
> 

BR, Jarkko

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

* Re: [PATCH 1/3] bpf: Add bpf_check_signature
  2025-05-28 21:49 ` [PATCH 1/3] bpf: Add bpf_check_signature Blaise Boscaccy
  2025-05-29 10:11   ` Lukas Wunner
  2025-06-02 22:40   ` Paul Moore
@ 2025-06-04 16:25   ` Jarkko Sakkinen
  2 siblings, 0 replies; 25+ messages in thread
From: Jarkko Sakkinen @ 2025-06-04 16:25 UTC (permalink / raw)
  To: Blaise Boscaccy
  Cc: Paul Moore, zeffron, xiyou.wangcong, kysrinivasan, code,
	linux-security-module, roberto.sassu, James.Bottomley,
	Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	David Howells, Lukas Wunner, Ignat Korchagin, Quentin Monnet,
	Jason Xing, Willem de Bruijn, Anton Protopopov, Jordan Rome,
	Martin Kelly, Alan Maguire, Matteo Croce, bpf, linux-kernel,
	keyrings, linux-crypto

On Wed, May 28, 2025 at 02:49:03PM -0700, Blaise Boscaccy wrote:
> This introduces signature verification for eBPF programs inside of the

s/This introduces signature verification/Introduce a signature verification ???/

I.e. Explain what sort of "thing" is "signature verification thing" ...

BR, Jarkko

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

end of thread, other threads:[~2025-06-04 16:25 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-28 21:49 [PATCH 0/3] BPF signature verification Blaise Boscaccy
2025-05-28 21:49 ` [PATCH 1/3] bpf: Add bpf_check_signature Blaise Boscaccy
2025-05-29 10:11   ` Lukas Wunner
2025-05-29 15:32     ` Blaise Boscaccy
2025-05-29 19:31       ` Lukas Wunner
2025-05-29 19:36         ` James Bottomley
2025-06-02 22:40   ` Paul Moore
2025-06-04 16:25   ` Jarkko Sakkinen
2025-05-28 21:49 ` [PATCH 2/3] bpf: Support light-skeleton signatures in autogenerated code Blaise Boscaccy
2025-05-28 21:49 ` [PATCH 3/3] bpftool: Allow signing of light-skeleton programs Blaise Boscaccy
2025-05-30 16:42 ` [PATCH 0/3] BPF signature verification KP Singh
2025-05-30 20:14   ` Paul Moore
2025-05-30 20:44     ` KP Singh
2025-05-30 21:19   ` Blaise Boscaccy
2025-05-30 21:32     ` KP Singh
2025-05-30 21:33       ` KP Singh
2025-05-30 22:15         ` Blaise Boscaccy
2025-05-30 22:14       ` Blaise Boscaccy
2025-05-30 22:19         ` KP Singh
2025-05-30 22:27           ` Blaise Boscaccy
2025-05-30 22:47             ` KP Singh
2025-05-30 23:25               ` Blaise Boscaccy
2025-05-30 23:32                 ` KP Singh
2025-06-02 15:01                   ` Blaise Boscaccy
2025-06-04 16:22 ` Jarkko Sakkinen

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).