xref: /linux/tools/testing/selftests/bpf/prog_tests/signed_loader.c (revision 25a2e54999b0b93e8ecebb5863e3ecbcafb0ed18)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2026 Isovalent */
3 
4 #include <test_progs.h>
5 #include <sys/syscall.h>
6 #include <sys/mman.h>
7 #include <sys/wait.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <limits.h>
11 #include <linux/keyctl.h>
12 #include <linux/bpf.h>
13 
14 #include <bpf/btf.h>
15 
16 #include "bpf/libbpf_internal.h" /* for libbpf_sha256() */
17 #include "bpf/skel_internal.h"	 /* for loader ctx layout (bpf_loader_ctx etc) */
18 
19 #include "test_signed_loader.skel.h"
20 #include "test_signed_loader_map.skel.h"
21 #include "test_signed_loader_data.skel.h"
22 #include "test_signed_loader_lsm.skel.h"
23 
24 enum {
25 	BPF_SIG_UNSIGNED = 0,
26 	BPF_SIG_VERIFIED,
27 };
28 
29 enum {
30 	BPF_SIG_KEYRING_NONE = 0,
31 	BPF_SIG_KEYRING_BUILTIN,
32 	BPF_SIG_KEYRING_SECONDARY,
33 	BPF_SIG_KEYRING_PLATFORM,
34 	BPF_SIG_KEYRING_USER,
35 	BPF_SIG_KEYRING_BPF,
36 };
37 
38 #ifndef KEY_SPEC_BPF_KEYRING
39 #define KEY_SPEC_BPF_KEYRING	-9
40 #endif
41 
42 /* verify_sig_setup.sh exits with this when openssl cannot do ML-DSA. */
43 #define SETUP_SKIP		(-77)
44 
45 /* FIPS-204 ML-DSA-87 signature size, see include/crypto/mldsa.h. */
46 #define MLDSA87_SIGNATURE_SIZE	4627
47 
48 static int load_loader_log(const void *insns, __u32 insns_sz, int map_fd,
49 			   const void *sig, __u32 sig_sz, __s32 keyring_id,
50 			   __u32 fd_array_cnt, char *log_buf, __u32 log_sz)
51 {
52 	union bpf_attr attr;
53 	int fd;
54 
55 	memset(&attr, 0, sizeof(attr));
56 	attr.prog_type = BPF_PROG_TYPE_SYSCALL;
57 	attr.insns = ptr_to_u64(insns);
58 	attr.insn_cnt = insns_sz / sizeof(struct bpf_insn);
59 	attr.license = ptr_to_u64("Dual BSD/GPL");
60 	attr.prog_flags = BPF_F_SLEEPABLE;
61 	attr.fd_array = ptr_to_u64(&map_fd);
62 	attr.fd_array_cnt = fd_array_cnt;
63 	if (sig) {
64 		attr.signature = ptr_to_u64(sig);
65 		attr.signature_size = sig_sz;
66 		attr.keyring_id = keyring_id;
67 	}
68 	if (log_buf) {
69 		attr.log_level = 1;
70 		attr.log_buf = ptr_to_u64(log_buf);
71 		attr.log_size = log_sz;
72 	}
73 	memcpy(attr.prog_name, "__loader.prog", sizeof("__loader.prog"));
74 	fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr,
75 		     offsetofend(union bpf_attr, keyring_id));
76 	return fd < 0 ? -errno : fd;
77 }
78 
79 static int load_loader(const void *insns, __u32 insns_sz, int map_fd,
80 		       const void *sig, __u32 sig_sz, __s32 keyring_id,
81 		       __u32 fd_array_cnt)
82 {
83 	return load_loader_log(insns, insns_sz, map_fd, sig, sig_sz, keyring_id,
84 			       fd_array_cnt, NULL, 0);
85 }
86 
87 static int run_gen_loader(const void *insns, __u32 insns_sz,
88 			  const void *data, __u32 data_sz,
89 			  const void *excl, __u32 excl_sz,
90 			  const void *sig, __u32 sig_sz,
91 			  void *ctx, __u32 ctx_sz, bool *loader_ran)
92 {
93 	LIBBPF_OPTS(bpf_map_create_opts, mopts,
94 		    .excl_prog_hash = excl,
95 		    .excl_prog_hash_size = excl_sz);
96 	__u32 key = 0;
97 	union bpf_attr attr;
98 	int map_fd, prog_fd, ret;
99 
100 	*loader_ran = false;
101 
102 	map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "__loader.map",
103 				4, data_sz, 1, &mopts);
104 	if (map_fd < 0)
105 		return -errno;
106 	if (bpf_map_update_elem(map_fd, &key, data, 0)) {
107 		ret = -errno;
108 		goto out_map;
109 	}
110 	if (bpf_map_freeze(map_fd)) {
111 		ret = -errno;
112 		goto out_map;
113 	}
114 
115 	memset(&attr, 0, sizeof(attr));
116 	attr.prog_type = BPF_PROG_TYPE_SYSCALL;
117 	attr.insns = ptr_to_u64(insns);
118 	attr.insn_cnt = insns_sz / sizeof(struct bpf_insn);
119 	attr.license = ptr_to_u64("Dual BSD/GPL");
120 	attr.prog_flags = BPF_F_SLEEPABLE;
121 	attr.fd_array = ptr_to_u64(&map_fd);
122 	if (sig) {
123 		attr.signature = ptr_to_u64(sig);
124 		attr.signature_size = sig_sz;
125 		attr.keyring_id = KEY_SPEC_SESSION_KEYRING;
126 		attr.fd_array_cnt = 1;
127 	}
128 	memcpy(attr.prog_name, "__loader.prog", sizeof("__loader.prog"));
129 	prog_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr,
130 			  offsetofend(union bpf_attr, keyring_id));
131 	if (prog_fd < 0) {
132 		ret = -errno;
133 		goto out_map;
134 	}
135 
136 	memset(&attr, 0, sizeof(attr));
137 	attr.test.prog_fd = prog_fd;
138 	attr.test.ctx_in = ptr_to_u64(ctx);
139 	attr.test.ctx_size_in = ctx_sz;
140 	if (syscall(__NR_bpf, BPF_PROG_RUN, &attr,
141 		    offsetofend(union bpf_attr, test)) < 0) {
142 		ret = -errno;
143 		goto out_prog;
144 	}
145 	*loader_ran = true;
146 	ret = (int)attr.test.retval;
147 out_prog:
148 	close(prog_fd);
149 out_map:
150 	close(map_fd);
151 	return ret;
152 }
153 
154 static void close_loader_ctx_fds(void *ctx, int nr_maps, int nr_progs)
155 {
156 	struct bpf_map_desc *md = (struct bpf_map_desc *)((char *)ctx +
157 				  sizeof(struct bpf_loader_ctx));
158 	struct bpf_prog_desc *pd = (struct bpf_prog_desc *)(md + nr_maps);
159 	int i;
160 
161 	for (i = 0; i < nr_maps; i++)
162 		if (md[i].map_fd > 0)
163 			close(md[i].map_fd);
164 	for (i = 0; i < nr_progs; i++)
165 		if (pd[i].prog_fd > 0)
166 			close(pd[i].prog_fd);
167 }
168 
169 static int run_setup(const char *cmd, const char *dir)
170 {
171 	int pid, status;
172 
173 	pid = fork();
174 	if (pid < 0)
175 		return -errno;
176 	if (pid == 0) {
177 		execlp("./verify_sig_setup.sh", "./verify_sig_setup.sh",
178 		       cmd, dir, NULL);
179 		exit(1);
180 	}
181 	if (waitpid(pid, &status, 0) < 0)
182 		return -errno;
183 	if (!WIFEXITED(status))
184 		return -EINVAL;
185 	return -WEXITSTATUS(status);
186 }
187 
188 static void genkey_dir_fini(const char *dir)
189 {
190 	static const char * const files[] = {
191 		"signing_key.der", "signing_key.pem", "x509.genkey",
192 	};
193 	char path[PATH_MAX];
194 	size_t i;
195 
196 	if (!dir)
197 		return;
198 	for (i = 0; i < ARRAY_SIZE(files); i++) {
199 		snprintf(path, sizeof(path), "%s/%s", dir, files[i]);
200 		unlink(path);
201 	}
202 	rmdir(dir);
203 }
204 
205 static int sign_buf_digest(const char *dir, const void *buf, __u32 len,
206 			   void *sig, __u32 *sig_sz, const char *digest)
207 {
208 	char data_tmpl[PATH_MAX], key[PATH_MAX];
209 	char sigpath[PATH_MAX + sizeof(".p7s")];
210 	int fd, pid, status, ret;
211 	struct stat st;
212 
213 	ret = snprintf(data_tmpl, sizeof(data_tmpl), "%s/dataXXXXXX", dir);
214 	if (ret < 0 || ret >= (int)sizeof(data_tmpl))
215 		return -ENAMETOOLONG;
216 	ret = 0;
217 
218 	fd = mkstemp(data_tmpl);
219 	if (fd < 0)
220 		return -errno;
221 	snprintf(sigpath, sizeof(sigpath), "%s.p7s", data_tmpl);
222 	if (write(fd, buf, len) != (ssize_t)len) {
223 		close(fd);
224 		ret = -EIO;
225 		goto out;
226 	}
227 	close(fd);
228 
229 	pid = fork();
230 	if (pid < 0) {
231 		ret = -errno;
232 		goto out;
233 	}
234 	if (pid == 0) {
235 		snprintf(key, sizeof(key), "%s/signing_key.pem", dir);
236 		execlp("./sign-file", "./sign-file", "-d", digest,
237 		       key, key, data_tmpl, NULL);
238 		exit(1);
239 	}
240 	if (waitpid(pid, &status, 0) < 0 ||
241 	    !WIFEXITED(status) || WEXITSTATUS(status)) {
242 		ret = -EINVAL;
243 		goto out;
244 	}
245 
246 	if (stat(sigpath, &st) < 0) {
247 		ret = -errno;
248 		goto out;
249 	}
250 	if (st.st_size > (off_t)*sig_sz) {
251 		ret = -E2BIG;
252 		goto out;
253 	}
254 	fd = open(sigpath, O_RDONLY);
255 	if (fd < 0) {
256 		ret = -errno;
257 		goto out;
258 	}
259 	if (read(fd, sig, st.st_size) != st.st_size) {
260 		close(fd);
261 		ret = -EIO;
262 		goto out;
263 	}
264 	close(fd);
265 	*sig_sz = st.st_size;
266 out:
267 	unlink(sigpath);
268 	unlink(data_tmpl);
269 	return ret;
270 }
271 
272 static int sign_buf(const char *dir, const void *buf, __u32 len,
273 		    void *sig, __u32 *sig_sz)
274 {
275 	return sign_buf_digest(dir, buf, len, sig, sig_sz, "sha256");
276 }
277 
278 struct gen_loader_fixture {
279 	struct test_signed_loader *skel;
280 	struct gen_loader_opts gopts;
281 	unsigned char *blob;
282 	void *ctx;
283 	__u32 data_sz;
284 	__u32 ctx_sz;
285 	int nr_maps;
286 	int nr_progs;
287 	__u8 excl[SHA256_DIGEST_LENGTH];
288 };
289 
290 static int gen_loader_fixture_init(struct gen_loader_fixture *f)
291 {
292 	LIBBPF_OPTS(gen_loader_opts, gopts, .gen_hash = true);
293 	int nr_maps = 0, nr_progs = 0;
294 	struct bpf_program *p;
295 	struct bpf_map *m;
296 
297 	memset(f, 0, sizeof(*f));
298 	f->skel = test_signed_loader__open();
299 	if (!ASSERT_OK_PTR(f->skel, "skel_open"))
300 		return -1;
301 	if (!ASSERT_OK(bpf_object__gen_loader(f->skel->obj, &gopts), "gen_loader"))
302 		return -1;
303 	if (!ASSERT_OK(bpf_object__load(f->skel->obj), "gen_load"))
304 		return -1;
305 	f->gopts = gopts;
306 
307 	bpf_object__for_each_program(p, f->skel->obj)
308 		nr_progs++;
309 	bpf_object__for_each_map(m, f->skel->obj)
310 		nr_maps++;
311 	f->nr_maps = nr_maps;
312 	f->nr_progs = nr_progs;
313 	f->ctx_sz = sizeof(struct bpf_loader_ctx) +
314 		    nr_maps * sizeof(struct bpf_map_desc) +
315 		    nr_progs * sizeof(struct bpf_prog_desc);
316 	f->ctx = calloc(1, f->ctx_sz);
317 	if (!ASSERT_OK_PTR(f->ctx, "ctx_alloc"))
318 		return -1;
319 	((struct bpf_loader_ctx *)f->ctx)->sz = f->ctx_sz;
320 
321 	f->data_sz = gopts.data_sz;
322 	f->blob = malloc(f->data_sz);
323 	if (!ASSERT_OK_PTR(f->blob, "blob_alloc"))
324 		return -1;
325 	memcpy(f->blob, gopts.data, f->data_sz);
326 
327 	/* excl_prog_hash = SHA256(loader insns) == the loader's prog->digest. */
328 	libbpf_sha256(gopts.insns, gopts.insns_sz, f->excl);
329 	return 0;
330 }
331 
332 static void gen_loader_fixture_fini(struct gen_loader_fixture *f)
333 {
334 	if (f->ctx)
335 		close_loader_ctx_fds(f->ctx, f->nr_maps, f->nr_progs);
336 	free(f->blob);
337 	free(f->ctx);
338 	test_signed_loader__destroy(f->skel);
339 }
340 
341 static void metadata_match(void)
342 {
343 	struct gen_loader_fixture f;
344 	bool ran;
345 	int r;
346 
347 	if (gen_loader_fixture_init(&f) == 0) {
348 		r = run_gen_loader(f.gopts.insns, f.gopts.insns_sz, f.blob,
349 				   f.data_sz, f.excl, sizeof(f.excl), NULL, 0,
350 				   f.ctx, f.ctx_sz, &ran);
351 		ASSERT_TRUE(ran, "loader ran");
352 		ASSERT_EQ(r, 0, "honest loader retval");
353 	}
354 	gen_loader_fixture_fini(&f);
355 }
356 
357 static void signature_enforced(void)
358 {
359 	static const __u8 junk[64] = { 0x30, 0x42, 0x13, 0x37, };
360 	struct gen_loader_fixture f;
361 	int fd;
362 
363 	if (gen_loader_fixture_init(&f) == 0) {
364 		/*
365 		 * A present-but-invalid signature (the cert bytes are not a
366 		 * PKCS#7 signature) must be rejected at load: the signature
367 		 * path is honored, not ignored. (The valid path is covered by
368 		 * the signed lskels.) Pin -EBADMSG, the PKCS#7 parse failure:
369 		 * a looser fd < 0 check could also be satisfied by the sparse
370 		 * fd_array rejection (-EACCES) that the loader's map reference
371 		 * would trip even if the signature were silently ignored.
372 		 */
373 		fd = load_loader(f.gopts.insns, f.gopts.insns_sz, -1, junk,
374 				 sizeof(junk), KEY_SPEC_SESSION_KEYRING, 0);
375 		ASSERT_EQ(fd, -EBADMSG, "invalid signature rejected at load");
376 		if (fd >= 0)
377 			close(fd);
378 	}
379 	gen_loader_fixture_fini(&f);
380 }
381 
382 /*
383  * CO-RE relocations would have the kernel rewrite the insns after the
384  * signature was checked over them, with values the loader picks through the
385  * BTF it supplies. A signed load that carries any is rejected before the
386  * signature is examined, so junk serves as one.
387  */
388 static void signed_core_relo_rejected(void)
389 {
390 	static const __u8 junk[64] = { 0x30, 0x42, 0x13, 0x37, };
391 	struct bpf_insn insns[] = {
392 		BPF_MOV64_IMM(BPF_REG_0, 0),
393 		BPF_EXIT_INSN(),
394 	};
395 	struct bpf_core_relo relo = {
396 		.insn_off = 0,
397 		.type_id = 1,
398 		.kind = BPF_CORE_TYPE_ID_LOCAL,
399 	};
400 	char log_buf[1024] = {};
401 	union bpf_attr attr;
402 	int fd;
403 
404 	memset(&attr, 0, sizeof(attr));
405 	attr.prog_type = BPF_PROG_TYPE_SYSCALL;
406 	attr.insns = ptr_to_u64(insns);
407 	attr.insn_cnt = ARRAY_SIZE(insns);
408 	attr.license = ptr_to_u64("Dual BSD/GPL");
409 	attr.prog_flags = BPF_F_SLEEPABLE;
410 	attr.signature = ptr_to_u64(junk);
411 	attr.signature_size = sizeof(junk);
412 	attr.keyring_id = KEY_SPEC_SESSION_KEYRING;
413 	attr.core_relos = ptr_to_u64(&relo);
414 	attr.core_relo_cnt = 1;
415 	attr.core_relo_rec_size = sizeof(relo);
416 	attr.log_level = 1;
417 	attr.log_buf = ptr_to_u64(log_buf);
418 	attr.log_size = sizeof(log_buf);
419 	fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr, offsetofend(union bpf_attr, keyring_id));
420 	fd = fd < 0 ? -errno : fd;
421 	ASSERT_EQ(fd, -EACCES, "signed load with CO-RE relocations rejected");
422 	ASSERT_HAS_SUBSTR(log_buf, "signed program cannot carry CO-RE relocations", "log");
423 	if (fd >= 0)
424 		close(fd);
425 }
426 
427 static void signed_nonexcl_fd_array_rejected(void)
428 {
429 	static const __u8 junk[64] = { 0x30, 0x42, 0x13, 0x37, };
430 	struct gen_loader_fixture f;
431 	int map_fd, fd;
432 
433 	if (gen_loader_fixture_init(&f) == 0) {
434 		/*
435 		 * A signed program may only bind exclusive maps through fd_array
436 		 * (their contents are folded into the signature). Binding a
437 		 * non-exclusive map is rejected, before the signature is even
438 		 * examined.
439 		 */
440 		map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "nonexcl", 4,
441 					f.data_sz, 1, NULL);
442 		if (ASSERT_OK_FD(map_fd, "nonexcl_map")) {
443 			if (ASSERT_OK(bpf_map_freeze(map_fd), "freeze")) {
444 				fd = load_loader(f.gopts.insns, f.gopts.insns_sz,
445 						 map_fd, junk, sizeof(junk),
446 						 KEY_SPEC_SESSION_KEYRING, 1);
447 				ASSERT_EQ(fd, -EPERM,
448 					  "non-exclusive map in signed fd_array rejected");
449 				if (fd >= 0)
450 					close(fd);
451 			}
452 			close(map_fd);
453 		}
454 	}
455 	gen_loader_fixture_fini(&f);
456 }
457 
458 static void signed_unfrozen_fd_array_rejected(void)
459 {
460 	static const __u8 junk[64] = { 0x30, 0x42, 0x13, 0x37, };
461 	LIBBPF_OPTS(bpf_map_create_opts, mopts);
462 	struct gen_loader_fixture f;
463 	__u32 key = 0;
464 	int map_fd, fd;
465 
466 	if (gen_loader_fixture_init(&f) == 0) {
467 		/*
468 		 * The metadata map must be frozen before a signed load so the
469 		 * folded bytes cannot change afterwards. Bind an exclusive map
470 		 * with matching contents but skip the freeze: the load must be
471 		 * rejected by the frozen check with -EPERM. The exclusivity
472 		 * check right after it would pass, so the errno uniquely pins
473 		 * the freeze requirement.
474 		 */
475 		mopts.excl_prog_hash = f.excl;
476 		mopts.excl_prog_hash_size = sizeof(f.excl);
477 		map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "unfrozen", 4,
478 					f.data_sz, 1, &mopts);
479 		if (ASSERT_OK_FD(map_fd, "unfrozen_map")) {
480 			if (ASSERT_OK(bpf_map_update_elem(map_fd, &key, f.blob, 0),
481 				      "update")) {
482 				fd = load_loader(f.gopts.insns, f.gopts.insns_sz,
483 						 map_fd, junk, sizeof(junk),
484 						 KEY_SPEC_SESSION_KEYRING, 1);
485 				ASSERT_EQ(fd, -EPERM,
486 					  "unfrozen map in signed fd_array rejected");
487 				if (fd >= 0)
488 					close(fd);
489 			}
490 			close(map_fd);
491 		}
492 	}
493 	gen_loader_fixture_fini(&f);
494 }
495 
496 static void signed_nonarray_fd_array_rejected(void)
497 {
498 	static const __u8 junk[64] = { 0x30, 0x42, 0x13, 0x37, };
499 	LIBBPF_OPTS(bpf_map_create_opts, mopts);
500 	struct gen_loader_fixture f;
501 	int map_fd, fd;
502 
503 	if (gen_loader_fixture_init(&f) == 0) {
504 		/*
505 		 * Only a plain BPF_MAP_TYPE_ARRAY may be folded into the
506 		 * signature. An exclusive map of any other type is rejected
507 		 * (-EINVAL) rather than folded - this is the type gate that
508 		 * keeps arena maps (map_direct_value_addr() returns a user
509 		 * address) and insn-array maps (buffer smaller than value_size)
510 		 * out of the hashed region, where the old code would have
511 		 * memcpy()'d from them. A hash map stands in here: it is
512 		 * exclusive (bound to the loader digest) but not an array.
513 		 */
514 		mopts.excl_prog_hash = f.excl;
515 		mopts.excl_prog_hash_size = sizeof(f.excl);
516 		map_fd = bpf_map_create(BPF_MAP_TYPE_HASH, "excl_hash", 4, 4, 1,
517 					&mopts);
518 		if (ASSERT_OK_FD(map_fd, "excl_hash_map")) {
519 			fd = load_loader(f.gopts.insns, f.gopts.insns_sz, map_fd,
520 					 junk, sizeof(junk),
521 					 KEY_SPEC_SESSION_KEYRING, 1);
522 			ASSERT_EQ(fd, -EINVAL,
523 				  "non-array map in signed fd_array rejected");
524 			if (fd >= 0)
525 				close(fd);
526 			close(map_fd);
527 		}
528 	}
529 	gen_loader_fixture_fini(&f);
530 }
531 
532 static int setup_meta_map(const struct gen_loader_fixture *f);
533 
534 static void signed_btf_fd_array_rejected(void)
535 {
536 	char dir_tmpl[] = "/tmp/signed_loader_btfXXXXXX", *dir = NULL;
537 	__u32 sig_sz = 8192;
538 	int map_fd = -1, prog_fd = -1;
539 	unsigned char *buf = NULL;
540 	struct gen_loader_fixture f;
541 	bool have_fixture = false;
542 	struct btf *btf = NULL;
543 	union bpf_attr attr;
544 	int fds[2];
545 	__u8 sig[8192];
546 
547 	syscall(__NR_request_key, "keyring", "_uid.0", NULL,
548 		KEY_SPEC_SESSION_KEYRING);
549 	dir = mkdtemp(dir_tmpl);
550 	if (!ASSERT_OK_PTR(dir, "mkdtemp"))
551 		return;
552 	if (!ASSERT_OK(run_setup("setup-rsa", dir), "verify_sig_setup")) {
553 		rmdir(dir);
554 		return;
555 	}
556 	have_fixture = true;
557 	if (gen_loader_fixture_init(&f) != 0)
558 		goto out;
559 
560 	/*
561 	 * fd_array binds maps and BTFs alike, but only exclusive array maps are
562 	 * folded into the signature. Build an otherwise genuinely signed load -
563 	 * insns || metadata, exclusive frozen map at fd_array[0] - then smuggle
564 	 * an extra BTF into fd_array[1]. A signed program may not bind any BTF,
565 	 * so resolving the fd_array entries rejects the BTF with -EACCES (in
566 	 * __add_used_btf(), before the signature is even verified).
567 	 */
568 	buf = malloc((size_t)f.gopts.insns_sz + f.data_sz);
569 	if (!ASSERT_OK_PTR(buf, "signbuf"))
570 		goto out;
571 	memcpy(buf, f.gopts.insns, f.gopts.insns_sz);
572 	memcpy(buf + f.gopts.insns_sz, f.blob, f.data_sz);
573 	if (!ASSERT_OK(sign_buf(dir, buf, f.gopts.insns_sz + f.data_sz, sig,
574 			       &sig_sz), "sign insns||metadata"))
575 		goto out;
576 
577 	map_fd = setup_meta_map(&f);
578 	if (!ASSERT_OK_FD(map_fd, "meta_map"))
579 		goto out;
580 	btf = btf__new_empty();
581 	if (!ASSERT_OK_PTR(btf, "btf_new_empty"))
582 		goto out;
583 	btf__add_int(btf, "int", 4, BTF_INT_SIGNED);
584 	if (!ASSERT_OK(btf__load_into_kernel(btf), "btf_load"))
585 		goto out;
586 
587 	fds[0] = map_fd;
588 	fds[1] = btf__fd(btf);
589 	memset(&attr, 0, sizeof(attr));
590 	attr.prog_type = BPF_PROG_TYPE_SYSCALL;
591 	attr.insns = ptr_to_u64(f.gopts.insns);
592 	attr.insn_cnt = f.gopts.insns_sz / sizeof(struct bpf_insn);
593 	attr.license = ptr_to_u64("Dual BSD/GPL");
594 	attr.prog_flags = BPF_F_SLEEPABLE;
595 	attr.fd_array = ptr_to_u64(fds);
596 	attr.fd_array_cnt = 2;
597 	attr.signature = ptr_to_u64(sig);
598 	attr.signature_size = sig_sz;
599 	attr.keyring_id = KEY_SPEC_SESSION_KEYRING;
600 	memcpy(attr.prog_name, "__loader.prog", sizeof("__loader.prog"));
601 	prog_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr,
602 			  offsetofend(union bpf_attr, keyring_id));
603 	ASSERT_EQ(prog_fd < 0 ? -errno : prog_fd, -EACCES,
604 		  "BTF in signed fd_array rejected");
605 	if (prog_fd >= 0)
606 		close(prog_fd);
607 out:
608 	if (btf)
609 		btf__free(btf);
610 	if (map_fd >= 0)
611 		close(map_fd);
612 	if (have_fixture)
613 		gen_loader_fixture_fini(&f);
614 	if (dir)
615 		run_setup("cleanup", dir);
616 	free(buf);
617 }
618 
619 static void signature_failure_logs(void)
620 {
621 	static const __u8 junk[64] = { 0x30, 0x42, 0x13, 0x37, };
622 	char log_buf[1024] = {};
623 	struct gen_loader_fixture f;
624 	int fd;
625 
626 	if (gen_loader_fixture_init(&f) == 0) {
627 		/*
628 		 * Signature verification now runs inside bpf_check(), so a
629 		 * failure is reported through the verifier log. A present-but-
630 		 * invalid signature is rejected and the log says why.
631 		 */
632 		fd = load_loader_log(f.gopts.insns, f.gopts.insns_sz, -1, junk,
633 				     sizeof(junk), KEY_SPEC_SESSION_KEYRING, 0,
634 				     log_buf, sizeof(log_buf));
635 		ASSERT_LT(fd, 0, "invalid signature rejected at load");
636 		if (fd >= 0)
637 			close(fd);
638 		ASSERT_HAS_SUBSTR(log_buf, "signature verification failed",
639 				  "verifier logs signature failure");
640 	}
641 	gen_loader_fixture_fini(&f);
642 }
643 
644 static void signature_too_large(void)
645 {
646 	static const __u8 junk[64] = {};
647 	struct gen_loader_fixture f;
648 	int fd;
649 
650 	if (gen_loader_fixture_init(&f) == 0) {
651 		/*
652 		 * signature_size beyond the kernel's bound
653 		 * (BPF_PROG_MAX_SIGNATURE_SIZE) is rejected before the buffer
654 		 * is read.
655 		 */
656 		fd = load_loader(f.gopts.insns, f.gopts.insns_sz, -1, junk,
657 				 64 << 20, KEY_SPEC_SESSION_KEYRING, 0);
658 		ASSERT_EQ(fd, -EINVAL, "oversized signature rejected");
659 		if (fd >= 0)
660 			close(fd);
661 	}
662 	gen_loader_fixture_fini(&f);
663 }
664 
665 static void signature_zero_size(void)
666 {
667 	static const __u8 junk[64] = {};
668 	struct gen_loader_fixture f;
669 	int fd;
670 
671 	if (gen_loader_fixture_init(&f) == 0) {
672 		/*
673 		 * A present signature with signature_size == 0 is rejected
674 		 * up front, before the keyring is resolved or the signature
675 		 * buffer is read.
676 		 */
677 		fd = load_loader(f.gopts.insns, f.gopts.insns_sz, -1, junk,
678 				 0, KEY_SPEC_SESSION_KEYRING, 0);
679 		ASSERT_EQ(fd, -EINVAL, "zero-size signature rejected");
680 		if (fd >= 0)
681 			close(fd);
682 	}
683 	gen_loader_fixture_fini(&f);
684 }
685 
686 static void signature_bad_keyring(void)
687 {
688 	static const __u8 junk[64] = {};
689 	struct gen_loader_fixture f;
690 	int fd;
691 
692 	if (gen_loader_fixture_init(&f) == 0) {
693 		/*
694 		 * A present signature with a keyring_id that resolves to no key is
695 		 * rejected up front: bpf_prog_verify_signature() fails the keyring
696 		 * lookup (-EINVAL) before it ever looks at the signature bytes. A
697 		 * large positive serial takes the user-keyring path and won't exist.
698 		 */
699 		fd = load_loader(f.gopts.insns, f.gopts.insns_sz, -1, junk,
700 				 sizeof(junk), INT_MAX, 0);
701 		ASSERT_EQ(fd, -EINVAL, "signature with bad keyring_id rejected");
702 		if (fd >= 0)
703 			close(fd);
704 	}
705 	gen_loader_fixture_fini(&f);
706 }
707 
708 static bool keyring_unsealed_boot(void)
709 {
710 	char val = 0;
711 	int fd;
712 
713 	fd = open("/sys/module/bpf/parameters/keyring_unsealed", O_RDONLY);
714 	if (fd < 0)
715 		return false;
716 	if (read(fd, &val, 1) != 1)
717 		val = 0;
718 	close(fd);
719 	return val == 'Y' || val == '1';
720 }
721 
722 static int bpf_keyring_lookup(int *nr_keys)
723 {
724 	char line[512], type[32], desc[64];
725 	int serial = -ENOENT;
726 	FILE *f;
727 
728 	f = fopen("/proc/keys", "r");
729 	if (!f)
730 		return -errno;
731 
732 	while (fgets(line, sizeof(line), f)) {
733 		unsigned int hex;
734 		char *sum;
735 
736 		if (sscanf(line, "%x %*s %*s %*s %*s %*s %*s %31s %63s",
737 			   &hex, type, desc) != 3)
738 			continue;
739 		if (strcmp(type, "keyring") || strcmp(desc, ".bpf:"))
740 			continue;
741 
742 		serial = (int)hex;
743 		if (nr_keys) {
744 			sum = strstr(line, ".bpf: ");
745 			*nr_keys = !sum || !strncmp(sum + 6, "empty", 5) ?
746 				   0 : atoi(sum + 6);
747 		}
748 		break;
749 	}
750 	fclose(f);
751 	return serial;
752 }
753 
754 static long keyctl_ret(int cmd, unsigned long arg2, unsigned long arg3)
755 {
756 	long ret = syscall(__NR_keyctl, cmd, arg2, arg3);
757 
758 	return ret < 0 ? -errno : ret;
759 }
760 
761 /*
762  * What the bpf keyring still needs once it got provisioned: KEY_POS_SEARCH
763  * for the in-kernel search during verification, and the user view/read bits
764  * so it stays visible in /proc/keys, rest is dropped so the enrolled is
765  * therefore final.
766  */
767 #define BPF_KEYRING_PERM_LOCKED		0x08030000
768 /* What bpf_keyring_init() grants at boot. */
769 #define BPF_KEYRING_PERM_INITIAL	0x082f0000
770 
771 static void bpf_keyring_sealed(void)
772 {
773 	static const __u8 junk[64] = {};
774 	struct gen_loader_fixture f;
775 	int serial, key, fd;
776 
777 	if (keyring_unsealed_boot()) {
778 		printf("%s:SKIP:the bpf keyring was unsealed at boot\n", __func__);
779 		test__skip();
780 		return;
781 	}
782 	serial = bpf_keyring_lookup(NULL);
783 	if (serial >= 0) {
784 		ASSERT_EQ(keyctl_ret(KEYCTL_GET_KEYRING_ID,
785 				     KEY_SPEC_BPF_KEYRING, 0), serial,
786 			  "KEY_SPEC_BPF_KEYRING resolves to the bpf keyring");
787 		key = syscall(__NR_add_key, "user", "sealprobe", "x", 1,
788 			      KEY_SPEC_BPF_KEYRING);
789 		if (key >= 0)
790 			syscall(__NR_keyctl, KEYCTL_UNLINK, key,
791 				KEY_SPEC_BPF_KEYRING);
792 		ASSERT_EQ(key < 0 ? -errno : 0, -EPERM,
793 			  "nothing links into a sealed keyring");
794 	}
795 	if (gen_loader_fixture_init(&f) == 0) {
796 		fd = load_loader(f.gopts.insns, f.gopts.insns_sz, -1, junk,
797 				 sizeof(junk), KEY_SPEC_BPF_KEYRING, 0);
798 		ASSERT_EQ(fd, -ENOKEY, "sealed bpf keyring rejected");
799 		if (fd >= 0)
800 			close(fd);
801 	}
802 	gen_loader_fixture_fini(&f);
803 }
804 
805 static int try_load(const struct gen_loader_fixture *f, const void *sig,
806 		    __u32 sig_sz, __s32 keyring_id, char *log_buf, __u32 log_sz)
807 {
808 	int map_fd, prog_fd;
809 
810 	map_fd = setup_meta_map(f);
811 	if (!ASSERT_OK_FD(map_fd, "meta_map"))
812 		return map_fd;
813 	prog_fd = load_loader_log(f->gopts.insns, f->gopts.insns_sz, map_fd,
814 				  sig, sig_sz, keyring_id, 1, log_buf, log_sz);
815 	close(map_fd);
816 	if (prog_fd >= 0)
817 		close(prog_fd);
818 	return prog_fd;
819 }
820 
821 /*
822  * This needs bpf.keyring_unsealed=1 on the guest kernel command line, which
823  * vmtest.sh can pass via KERNEL_CMDLINE_EXTRA. There is no way to unseal the
824  * keyring from here, so without it the test skips. It also only works once
825  * per boot, as restricting a keyring cannot be undone.
826  */
827 static void bpf_keyring_provisioned(void)
828 {
829 	char dir_tmpl[] = "/tmp/bpfkeyringXXXXXX";
830 	char bad_tmpl[] = "/tmp/bpfkeyringbadXXXXXX";
831 	__u8 *sig = NULL, *bad = NULL, *buf = NULL;
832 	int serial, err;
833 	int nr_keys = 0, der_fd = -1;
834 	struct gen_loader_fixture f;
835 	__u32 sig_sz = 8192, bad_sz;
836 	bool have_fixture = false;
837 	char *dir, *bad_dir = NULL;
838 	char log_buf[1024] = {};
839 	char path[PATH_MAX];
840 	__u8 der[4096];
841 	ssize_t der_sz;
842 
843 	serial = bpf_keyring_lookup(&nr_keys);
844 	if (serial < 0) {
845 		printf("%s:SKIP:no bpf keyring (needs CONFIG_KEYS)\n", __func__);
846 		test__skip();
847 		return;
848 	}
849 	if (nr_keys != 0) {
850 		printf("%s:SKIP:the bpf keyring has already been provisioned\n",
851 		       __func__);
852 		test__skip();
853 		return;
854 	}
855 
856 	dir = mkdtemp(dir_tmpl);
857 	if (!ASSERT_OK_PTR(dir, "mkdtemp"))
858 		return;
859 	if (!ASSERT_OK(run_setup("genkey", dir), "verify_sig_setup genkey"))
860 		goto rmdir;
861 
862 	snprintf(path, sizeof(path), "%s/signing_key.der", dir);
863 	der_fd = open(path, O_RDONLY);
864 	if (!ASSERT_OK_FD(der_fd, "open signing_key.der"))
865 		goto rmdir;
866 	der_sz = read(der_fd, der, sizeof(der));
867 	close(der_fd);
868 	if (!ASSERT_GT(der_sz, 0, "read signing_key.der"))
869 		goto rmdir;
870 
871 	ASSERT_EQ(keyctl_ret(KEYCTL_GET_KEYRING_ID, KEY_SPEC_BPF_KEYRING, 0),
872 		  serial, "KEY_SPEC_BPF_KEYRING resolves to the bpf keyring");
873 
874 	err = syscall(__NR_add_key, "asymmetric", "", der, (size_t)der_sz,
875 		      KEY_SPEC_BPF_KEYRING);
876 	if (err < 0 && errno == EPERM) {
877 		printf("%s:SKIP:the bpf keyring is sealed, need bpf.keyring_unsealed=1\n",
878 		       __func__);
879 		test__skip();
880 		goto rmdir;
881 	}
882 	if (!ASSERT_GE(err, 0, "add the signing key to the bpf keyring"))
883 		goto rmdir;
884 
885 	sig = malloc(sig_sz);
886 	if (!ASSERT_OK_PTR(sig, "sig buf"))
887 		goto out;
888 	have_fixture = true;
889 	if (gen_loader_fixture_init(&f) != 0)
890 		goto out;
891 
892 	buf = malloc((size_t)f.gopts.insns_sz + f.data_sz);
893 	if (!ASSERT_OK_PTR(buf, "signbuf"))
894 		goto out;
895 	memcpy(buf, f.gopts.insns, f.gopts.insns_sz);
896 	memcpy(buf + f.gopts.insns_sz, f.blob, f.data_sz);
897 	if (!ASSERT_OK(sign_buf(dir, buf, f.gopts.insns_sz + f.data_sz, sig,
898 				&sig_sz), "sign insns||metadata"))
899 		goto out;
900 
901 	ASSERT_EQ(try_load(&f, sig, sig_sz, KEY_SPEC_BPF_KEYRING, NULL, 0),
902 		  -ENOKEY, "unrestricted keyring still not consulted");
903 
904 	ASSERT_EQ(try_load(&f, sig, sig_sz, KEY_SPEC_SESSION_KEYRING, NULL, 0),
905 		  -EPERM, "caller-supplied keyring refused before provisioning");
906 
907 	if (!ASSERT_OK(syscall(__NR_keyctl, KEYCTL_RESTRICT_KEYRING,
908 			       KEY_SPEC_BPF_KEYRING, NULL, NULL),
909 		       "restrict bpf keyring"))
910 		goto out;
911 
912 	if (!ASSERT_OK_FD(try_load(&f, sig, sig_sz, KEY_SPEC_BPF_KEYRING,
913 				   NULL, 0),
914 			  "load signed by a key in the .bpf keyring"))
915 		goto out;
916 
917 	bad_dir = mkdtemp(bad_tmpl);
918 	if (!ASSERT_OK_PTR(bad_dir, "mkdtemp unenrolled"))
919 		goto out;
920 	if (!ASSERT_OK(run_setup("genkey", bad_dir), "verify_sig_setup genkey unenrolled"))
921 		goto out;
922 	bad_sz = 8192;
923 	bad = malloc(bad_sz);
924 	if (!ASSERT_OK_PTR(bad, "bad sig buf"))
925 		goto out;
926 	if (!ASSERT_OK(sign_buf(bad_dir, buf, f.gopts.insns_sz + f.data_sz, bad,
927 				&bad_sz), "sign with an unenrolled key"))
928 		goto out;
929 
930 	ASSERT_EQ(try_load(&f, bad, bad_sz, KEY_SPEC_BPF_KEYRING, log_buf,
931 			   sizeof(log_buf)), -ENOKEY,
932 		  "key outside the bpf keyring refused");
933 	ASSERT_HAS_SUBSTR(log_buf, "signature verification failed",
934 			  "the bpf keyring was consulted");
935 
936 	f.blob[0] ^= 0xff;
937 	err = try_load(&f, sig, sig_sz, KEY_SPEC_BPF_KEYRING, NULL, 0);
938 	f.blob[0] ^= 0xff;
939 	ASSERT_EQ(err, -EKEYREJECTED, "tampered metadata refused");
940 
941 	ASSERT_EQ(try_load(&f, sig, sig_sz, KEY_SPEC_SESSION_KEYRING, NULL, 0),
942 		  -EPERM, "caller-supplied keyring refused once .bpf is in use");
943 
944 	err = keyctl_ret(KEYCTL_UNLINK, KEY_SPEC_SESSION_KEYRING, serial);
945 	ASSERT_EQ(err, -ENOENT, "keyring writable while the user bits are there");
946 
947 	err = keyctl_ret(KEYCTL_SETPERM, serial, BPF_KEYRING_PERM_LOCKED);
948 	if (!ASSERT_OK(err, "drop the user bits on the bpf keyring"))
949 		goto out;
950 
951 	ASSERT_OK_FD(try_load(&f, sig, sig_sz, KEY_SPEC_BPF_KEYRING, NULL, 0),
952 		     "load still verified against the locked keyring");
953 	ASSERT_EQ(keyctl_ret(KEYCTL_GET_KEYRING_ID, KEY_SPEC_BPF_KEYRING, 0),
954 		  -EACCES, "the special id grants no rights of its own");
955 
956 	err = keyctl_ret(KEYCTL_UNLINK, KEY_SPEC_SESSION_KEYRING, serial);
957 	ASSERT_EQ(err, -EACCES, "unlink refused");
958 	err = keyctl_ret(KEYCTL_CLEAR, serial, 0);
959 	ASSERT_EQ(err, -EACCES, "clear refused");
960 	err = keyctl_ret(KEYCTL_REVOKE, serial, 0);
961 	ASSERT_EQ(err, -EACCES, "revoke refused");
962 	err = keyctl_ret(KEYCTL_INVALIDATE, serial, 0);
963 	ASSERT_EQ(err, -EACCES, "invalidate refused");
964 	err = keyctl_ret(KEYCTL_SET_TIMEOUT, serial, 1);
965 	ASSERT_EQ(err, -EACCES, "timeout refused");
966 	err = keyctl_ret(KEYCTL_SETPERM, serial, BPF_KEYRING_PERM_INITIAL);
967 	ASSERT_EQ(err, -EACCES, "the bits cannot be granted back");
968 
969 	ASSERT_EQ(bpf_keyring_lookup(&nr_keys), serial, "keyring still there");
970 	ASSERT_EQ(nr_keys, 1, "the enrolled key survived");
971 out:
972 	if (have_fixture)
973 		gen_loader_fixture_fini(&f);
974 	genkey_dir_fini(bad_dir);
975 	free(buf);
976 	free(bad);
977 	free(sig);
978 rmdir:
979 	genkey_dir_fini(dir);
980 }
981 
982 /*
983  * A signed loader must ignore ctx-supplied map dimensions: the host cannot
984  * resize a signed program's maps via the loader ctx. Drive a one-map program
985  * through gen_loader, ask (via ctx) for every map to be resized to a bogus
986  * value, and confirm the created maps keep their attested size.
987  */
988 #define GATING_BOGUS_MAX 0x4000
989 
990 static void metadata_ctx_max_entries_ignored(void)
991 {
992 	LIBBPF_OPTS(gen_loader_opts, gopts, .gen_hash = true);
993 	struct test_signed_loader_map *skel;
994 	__u8 excl[SHA256_DIGEST_LENGTH];
995 	int nr_maps = 0, nr_progs = 0, i, checked = 0, r;
996 	struct bpf_program *p;
997 	struct bpf_map *m;
998 	struct bpf_map_desc *md;
999 	unsigned char *blob;
1000 	__u32 ctx_sz, data_sz;
1001 	void *ctx;
1002 	bool ran;
1003 
1004 	skel = test_signed_loader_map__open();
1005 	if (!ASSERT_OK_PTR(skel, "skel_open"))
1006 		return;
1007 	if (!ASSERT_OK(bpf_object__gen_loader(skel->obj, &gopts), "gen_loader"))
1008 		goto destroy;
1009 	if (!ASSERT_OK(bpf_object__load(skel->obj), "gen_load"))
1010 		goto destroy;
1011 
1012 	bpf_object__for_each_program(p, skel->obj)
1013 		nr_progs++;
1014 	bpf_object__for_each_map(m, skel->obj)
1015 		nr_maps++;
1016 	ctx_sz = sizeof(struct bpf_loader_ctx) +
1017 		 nr_maps * sizeof(struct bpf_map_desc) +
1018 		 nr_progs * sizeof(struct bpf_prog_desc);
1019 	ctx = calloc(1, ctx_sz);
1020 	if (!ASSERT_OK_PTR(ctx, "ctx_alloc"))
1021 		goto destroy;
1022 	((struct bpf_loader_ctx *)ctx)->sz = ctx_sz;
1023 
1024 	md = (struct bpf_map_desc *)((char *)ctx + sizeof(struct bpf_loader_ctx));
1025 	for (i = 0; i < nr_maps; i++)
1026 		md[i].max_entries = GATING_BOGUS_MAX;
1027 
1028 	libbpf_sha256(gopts.insns, gopts.insns_sz, excl);
1029 	data_sz = gopts.data_sz;
1030 	blob = malloc(data_sz);
1031 	if (!ASSERT_OK_PTR(blob, "blob_alloc"))
1032 		goto free_ctx;
1033 	memcpy(blob, gopts.data, data_sz);
1034 
1035 	r = run_gen_loader(gopts.insns, gopts.insns_sz, blob, data_sz,
1036 			   excl, sizeof(excl), NULL, 0, ctx, ctx_sz, &ran);
1037 	if (!ASSERT_TRUE(ran, "loader ran") ||
1038 	    !ASSERT_EQ(r, 0, "loader retval"))
1039 		goto free_blob;
1040 
1041 	for (i = 0; i < nr_maps; i++) {
1042 		struct bpf_map_info info;
1043 		__u32 ilen = sizeof(info);
1044 		int fd = md[i].map_fd;
1045 
1046 		if (fd <= 0)
1047 			continue;
1048 		memset(&info, 0, sizeof(info));
1049 		if (ASSERT_OK(bpf_map_get_info_by_fd(fd, &info, &ilen), "map_info")) {
1050 			ASSERT_NEQ(info.max_entries, GATING_BOGUS_MAX,
1051 				   "ctx max_entries ignored for signed loader");
1052 			checked++;
1053 		}
1054 	}
1055 	ASSERT_GT(checked, 0, "inspected a created map");
1056 
1057 free_blob:
1058 	free(blob);
1059 free_ctx:
1060 	close_loader_ctx_fds(ctx, nr_maps, nr_progs);
1061 	free(ctx);
1062 destroy:
1063 	test_signed_loader_map__destroy(skel);
1064 }
1065 
1066 /*
1067  * A signed loader must also ignore ctx-supplied initial_value: the host cannot
1068  * re-seed a signed program's map contents through the loader ctx. Drive a
1069  * program with one initialized global (a .data map) through gen_loader, point
1070  * every map's ctx initial_value at an adversarial buffer, and confirm the
1071  * created map still holds the attested value, never the ctx bytes.
1072  */
1073 #define DATA_MAGIC 0x5eed1234abad1deaULL
1074 
1075 static void metadata_ctx_initial_value_ignored(void)
1076 {
1077 	LIBBPF_OPTS(gen_loader_opts, gopts, .gen_hash = true);
1078 	struct test_signed_loader_data *skel;
1079 	__u8 excl[SHA256_DIGEST_LENGTH], evil[64];
1080 	int nr_maps = 0, nr_progs = 0, i, found = 0, r;
1081 	struct bpf_program *p;
1082 	struct bpf_map *m;
1083 	struct bpf_map_desc *md;
1084 	unsigned char *blob;
1085 	__u32 ctx_sz, data_sz;
1086 	void *ctx;
1087 	bool ran;
1088 
1089 	skel = test_signed_loader_data__open();
1090 	if (!ASSERT_OK_PTR(skel, "skel_open"))
1091 		return;
1092 	if (!ASSERT_OK(bpf_object__gen_loader(skel->obj, &gopts), "gen_loader"))
1093 		goto destroy;
1094 	if (!ASSERT_OK(bpf_object__load(skel->obj), "gen_load"))
1095 		goto destroy;
1096 
1097 	bpf_object__for_each_program(p, skel->obj)
1098 		nr_progs++;
1099 	bpf_object__for_each_map(m, skel->obj)
1100 		nr_maps++;
1101 	ctx_sz = sizeof(struct bpf_loader_ctx) +
1102 		 nr_maps * sizeof(struct bpf_map_desc) +
1103 		 nr_progs * sizeof(struct bpf_prog_desc);
1104 	ctx = calloc(1, ctx_sz);
1105 	if (!ASSERT_OK_PTR(ctx, "ctx_alloc"))
1106 		goto destroy;
1107 	((struct bpf_loader_ctx *)ctx)->sz = ctx_sz;
1108 
1109 	memset(evil, 0xAA, sizeof(evil));
1110 	md = (struct bpf_map_desc *)((char *)ctx + sizeof(struct bpf_loader_ctx));
1111 	for (i = 0; i < nr_maps; i++)
1112 		md[i].initial_value = ptr_to_u64(evil);
1113 
1114 	libbpf_sha256(gopts.insns, gopts.insns_sz, excl);
1115 	data_sz = gopts.data_sz;
1116 	blob = malloc(data_sz);
1117 	if (!ASSERT_OK_PTR(blob, "blob_alloc"))
1118 		goto free_ctx;
1119 	memcpy(blob, gopts.data, data_sz);
1120 
1121 	r = run_gen_loader(gopts.insns, gopts.insns_sz, blob, data_sz,
1122 			   excl, sizeof(excl), NULL, 0, ctx, ctx_sz, &ran);
1123 	if (!ASSERT_TRUE(ran, "loader ran") ||
1124 	    !ASSERT_EQ(r, 0, "loader retval"))
1125 		goto free_blob;
1126 
1127 	for (i = 0; i < nr_maps; i++) {
1128 		struct bpf_map_info info;
1129 		__u32 ilen = sizeof(info), key = 0;
1130 		__u8 value[64] = {};
1131 		__u64 got;
1132 		int fd = md[i].map_fd;
1133 
1134 		if (fd <= 0)
1135 			continue;
1136 		memset(&info, 0, sizeof(info));
1137 		if (!ASSERT_OK(bpf_map_get_info_by_fd(fd, &info, &ilen), "map_info"))
1138 			continue;
1139 		if (info.value_size <= sizeof(value) &&
1140 		    bpf_map_lookup_elem(fd, &key, value) == 0) {
1141 			memcpy(&got, value, sizeof(got));
1142 			/* attested .data survives; ctx bytes (0xAA..) ignored */
1143 			if (got == DATA_MAGIC)
1144 				found = 1;
1145 			ASSERT_NEQ(got, 0xAAAAAAAAAAAAAAAAULL,
1146 				   "ctx initial_value ignored for signed loader");
1147 		}
1148 	}
1149 	ASSERT_EQ(found, 1, "attested .data value preserved");
1150 
1151 free_blob:
1152 	free(blob);
1153 free_ctx:
1154 	close_loader_ctx_fds(ctx, nr_maps, nr_progs);
1155 	free(ctx);
1156 destroy:
1157 	test_signed_loader_data__destroy(skel);
1158 }
1159 
1160 /*
1161  * The load-time signature must authenticate the loader instructions: a valid
1162  * signature loads, and the very same signature over one-byte-tampered insns is
1163  * rejected. Uses ./verify_sig_setup.sh + ./sign-file at runtime, like
1164  * verify_pkcs7_sig, and verifies against the session keyring the key was added
1165  * to. (signature_enforced/_too_large only cover a malformed signature.)
1166  */
1167 static void signature_authenticates_insns(void)
1168 {
1169 	LIBBPF_OPTS(gen_loader_opts, gopts, .gen_hash = true);
1170 	char dir_tmpl[] = "/tmp/signed_loaderXXXXXX", *dir;
1171 	struct test_signed_loader *skel = NULL;
1172 	__u8 excl[SHA256_DIGEST_LENGTH], sig[8192];
1173 	__u32 sig_sz = sizeof(sig), insns_sz, data_sz, ctx_sz;
1174 	unsigned char *insns = NULL, *tampered = NULL, *blob = NULL;
1175 	unsigned char *signbuf = NULL;
1176 	int nr_maps = 0, nr_progs = 0, r;
1177 	struct bpf_program *p;
1178 	struct bpf_map *m;
1179 	void *ctx = NULL;
1180 	bool ran;
1181 
1182 	syscall(__NR_request_key, "keyring", "_uid.0", NULL,
1183 		KEY_SPEC_SESSION_KEYRING);
1184 	dir = mkdtemp(dir_tmpl);
1185 	if (!ASSERT_OK_PTR(dir, "mkdtemp"))
1186 		return;
1187 	if (!ASSERT_OK(run_setup("setup-rsa", dir), "verify_sig_setup")) {
1188 		rmdir(dir);
1189 		return;
1190 	}
1191 
1192 	skel = test_signed_loader__open();
1193 	if (!ASSERT_OK_PTR(skel, "skel_open"))
1194 		goto cleanup;
1195 	if (!ASSERT_OK(bpf_object__gen_loader(skel->obj, &gopts), "gen_loader"))
1196 		goto cleanup;
1197 	if (!ASSERT_OK(bpf_object__load(skel->obj), "gen_load"))
1198 		goto cleanup;
1199 
1200 	bpf_object__for_each_program(p, skel->obj)
1201 		nr_progs++;
1202 	bpf_object__for_each_map(m, skel->obj)
1203 		nr_maps++;
1204 	ctx_sz = sizeof(struct bpf_loader_ctx) +
1205 		 nr_maps * sizeof(struct bpf_map_desc) +
1206 		 nr_progs * sizeof(struct bpf_prog_desc);
1207 	insns_sz = gopts.insns_sz;
1208 	data_sz = gopts.data_sz;
1209 	ctx = calloc(1, ctx_sz);
1210 	insns = malloc(insns_sz);
1211 	tampered = malloc(insns_sz);
1212 	blob = malloc(data_sz);
1213 	if (!ASSERT_OK_PTR(ctx, "ctx") ||
1214 	    !ASSERT_OK_PTR(insns, "insns") ||
1215 	    !ASSERT_OK_PTR(tampered, "tampered") ||
1216 	    !ASSERT_OK_PTR(blob, "blob"))
1217 		goto cleanup;
1218 	memcpy(insns, gopts.insns, insns_sz);
1219 	memcpy(blob, gopts.data, data_sz);
1220 	libbpf_sha256(insns, insns_sz, excl);
1221 
1222 	signbuf = malloc((size_t)insns_sz + data_sz);
1223 	if (!ASSERT_OK_PTR(signbuf, "signbuf"))
1224 		goto cleanup;
1225 	memcpy(signbuf, insns, insns_sz);
1226 	memcpy(signbuf + insns_sz, blob, data_sz);
1227 	if (!ASSERT_OK(sign_buf(dir, signbuf, insns_sz + data_sz, sig, &sig_sz),
1228 		       "sign-file"))
1229 		goto cleanup;
1230 
1231 	memset(ctx, 0, ctx_sz);
1232 	((struct bpf_loader_ctx *)ctx)->sz = ctx_sz;
1233 	r = run_gen_loader(insns, insns_sz, blob, data_sz, excl, sizeof(excl),
1234 			   sig, sig_sz, ctx, ctx_sz, &ran);
1235 	ASSERT_TRUE(ran, "valid signature: loader loaded and ran");
1236 	ASSERT_EQ(r, 0, "valid signature accepted");
1237 	close_loader_ctx_fds(ctx, nr_maps, nr_progs);
1238 
1239 	memcpy(tampered, insns, insns_sz);
1240 	tampered[insns_sz / 2] ^= 0xff;
1241 	/*
1242 	 * Bind the metadata map to the tampered loader's own digest, so the
1243 	 * verifier's exclusive-map check (excl_prog_sha == prog->digest) passes
1244 	 * and the signature - verified after the maps are resolved - is what
1245 	 * rejects the load. This is the attacker's best case: even after
1246 	 * re-binding the exclusive map to their tampered loader, the signature
1247 	 * over the original insns || metadata still fails. (Leaving the map
1248 	 * bound to the original digest would instead trip the excl check first.)
1249 	 */
1250 	libbpf_sha256(tampered, insns_sz, excl);
1251 	memset(ctx, 0, ctx_sz);
1252 	((struct bpf_loader_ctx *)ctx)->sz = ctx_sz;
1253 	r = run_gen_loader(tampered, insns_sz, blob, data_sz, excl, sizeof(excl),
1254 			   sig, sig_sz, ctx, ctx_sz, &ran);
1255 	ASSERT_FALSE(ran, "tampered loader rejected before run");
1256 	ASSERT_EQ(r, -EKEYREJECTED, "signature is bound to the instructions");
1257 cleanup:
1258 	free(insns);
1259 	free(tampered);
1260 	free(blob);
1261 	free(signbuf);
1262 	free(ctx);
1263 	test_signed_loader__destroy(skel);
1264 	run_setup("cleanup", dir);
1265 }
1266 
1267 static void signature_authenticates_metadata(void)
1268 {
1269 	LIBBPF_OPTS(gen_loader_opts, gopts, .gen_hash = true);
1270 	char dir_tmpl[] = "/tmp/signed_loaderXXXXXX", *dir;
1271 	struct test_signed_loader *skel = NULL;
1272 	__u8 excl[SHA256_DIGEST_LENGTH], sig[8192];
1273 	__u32 sig_sz = sizeof(sig), insns_sz, data_sz, ctx_sz;
1274 	unsigned char *insns = NULL, *blob = NULL;
1275 	unsigned char *signbuf = NULL;
1276 	int nr_maps = 0, nr_progs = 0, r;
1277 	struct bpf_program *p;
1278 	struct bpf_map *m;
1279 	void *ctx = NULL;
1280 	bool ran;
1281 
1282 	syscall(__NR_request_key, "keyring", "_uid.0", NULL,
1283 		KEY_SPEC_SESSION_KEYRING);
1284 	dir = mkdtemp(dir_tmpl);
1285 	if (!ASSERT_OK_PTR(dir, "mkdtemp"))
1286 		return;
1287 	if (!ASSERT_OK(run_setup("setup-rsa", dir), "verify_sig_setup")) {
1288 		rmdir(dir);
1289 		return;
1290 	}
1291 
1292 	skel = test_signed_loader__open();
1293 	if (!ASSERT_OK_PTR(skel, "skel_open"))
1294 		goto cleanup;
1295 	if (!ASSERT_OK(bpf_object__gen_loader(skel->obj, &gopts), "gen_loader"))
1296 		goto cleanup;
1297 	if (!ASSERT_OK(bpf_object__load(skel->obj), "gen_load"))
1298 		goto cleanup;
1299 
1300 	bpf_object__for_each_program(p, skel->obj)
1301 		nr_progs++;
1302 	bpf_object__for_each_map(m, skel->obj)
1303 		nr_maps++;
1304 	ctx_sz = sizeof(struct bpf_loader_ctx) +
1305 		 nr_maps * sizeof(struct bpf_map_desc) +
1306 		 nr_progs * sizeof(struct bpf_prog_desc);
1307 	insns_sz = gopts.insns_sz;
1308 	data_sz = gopts.data_sz;
1309 	ctx = calloc(1, ctx_sz);
1310 	insns = malloc(insns_sz);
1311 	blob = malloc(data_sz);
1312 	if (!ASSERT_OK_PTR(ctx, "ctx") ||
1313 	    !ASSERT_OK_PTR(insns, "insns") ||
1314 	    !ASSERT_OK_PTR(blob, "blob"))
1315 		goto cleanup;
1316 	memcpy(insns, gopts.insns, insns_sz);
1317 	memcpy(blob, gopts.data, data_sz);
1318 	libbpf_sha256(insns, insns_sz, excl);
1319 
1320 	signbuf = malloc((size_t)insns_sz + data_sz);
1321 	if (!ASSERT_OK_PTR(signbuf, "signbuf"))
1322 		goto cleanup;
1323 	memcpy(signbuf, insns, insns_sz);
1324 	memcpy(signbuf + insns_sz, blob, data_sz);
1325 	if (!ASSERT_OK(sign_buf(dir, signbuf, insns_sz + data_sz, sig, &sig_sz),
1326 		       "sign-file"))
1327 		goto cleanup;
1328 
1329 	memset(ctx, 0, ctx_sz);
1330 	((struct bpf_loader_ctx *)ctx)->sz = ctx_sz;
1331 	r = run_gen_loader(insns, insns_sz, blob, data_sz, excl, sizeof(excl),
1332 			   sig, sig_sz, ctx, ctx_sz, &ran);
1333 	ASSERT_TRUE(ran, "valid signature: loader loaded and ran");
1334 	ASSERT_EQ(r, 0, "valid signature accepted");
1335 	close_loader_ctx_fds(ctx, nr_maps, nr_progs);
1336 
1337 	/*
1338 	 * Tamper the metadata after signing while leaving the instructions
1339 	 * and thus the exclusive hash binding untouched: the map freezes
1340 	 * fine and excl_prog_sha still matches the loader's digest, so the
1341 	 * load reaches signature verification, which folds the live frozen
1342 	 * map bytes into the checked payload and must reject the modified
1343 	 * blob. A kernel folding anything but the map contents themselves
1344 	 * would wrongly accept this load.
1345 	 */
1346 	blob[data_sz / 2] ^= 0xff;
1347 	memset(ctx, 0, ctx_sz);
1348 	((struct bpf_loader_ctx *)ctx)->sz = ctx_sz;
1349 	r = run_gen_loader(insns, insns_sz, blob, data_sz, excl, sizeof(excl),
1350 			   sig, sig_sz, ctx, ctx_sz, &ran);
1351 	ASSERT_FALSE(ran, "tampered metadata rejected before run");
1352 	ASSERT_EQ(r, -EKEYREJECTED, "signature is bound to the metadata");
1353 cleanup:
1354 	free(insns);
1355 	free(blob);
1356 	free(signbuf);
1357 	free(ctx);
1358 	test_signed_loader__destroy(skel);
1359 	run_setup("cleanup", dir);
1360 }
1361 
1362 static int make_excl_map(__u32 flags, __u32 value_size)
1363 {
1364 	LIBBPF_OPTS(bpf_map_create_opts, opts);
1365 	__u8 hash[SHA256_DIGEST_LENGTH] = { 1 };	/* any 32-byte value */
1366 
1367 	opts.excl_prog_hash = hash;
1368 	opts.excl_prog_hash_size = sizeof(hash);
1369 	opts.map_flags = flags;
1370 	return bpf_map_create(BPF_MAP_TYPE_ARRAY, "md", 4, value_size, 1, &opts);
1371 }
1372 
1373 static void hash_requires_frozen(void)
1374 {
1375 	__u8 hbuf[SHA256_DIGEST_LENGTH], val[64] = {};
1376 	struct bpf_map_info info;
1377 	__u32 ilen, key = 0;
1378 	int fd;
1379 
1380 	fd = make_excl_map(0, sizeof(val));
1381 	if (!ASSERT_OK_FD(fd, "excl_map"))
1382 		return;
1383 	ASSERT_OK(bpf_map_update_elem(fd, &key, val, 0), "update");
1384 
1385 	memset(&info, 0, sizeof(info));
1386 	info.hash = ptr_to_u64(hbuf);
1387 	info.hash_size = sizeof(hbuf);
1388 	ilen = sizeof(info);
1389 	ASSERT_EQ(bpf_map_get_info_by_fd(fd, &info, &ilen), -EPERM,
1390 		  "hash of unfrozen map rejected");
1391 	close(fd);
1392 }
1393 
1394 static void no_update_after_freeze(void)
1395 {
1396 	__u8 val[64] = {};
1397 	__u32 key = 0;
1398 	int fd;
1399 
1400 	fd = make_excl_map(0, sizeof(val));
1401 	if (!ASSERT_OK_FD(fd, "excl_map"))
1402 		return;
1403 	ASSERT_OK(bpf_map_update_elem(fd, &key, val, 0), "update");
1404 	ASSERT_OK(bpf_map_freeze(fd), "freeze");
1405 	ASSERT_EQ(bpf_map_update_elem(fd, &key, val, 0), -EPERM,
1406 		  "update after freeze rejected");
1407 	close(fd);
1408 }
1409 
1410 static void freeze_writable_mmap(void)
1411 {
1412 	void *w;
1413 	int fd;
1414 
1415 	fd = make_excl_map(BPF_F_MMAPABLE, 4096);
1416 	if (!ASSERT_OK_FD(fd, "excl_mmapable_map"))
1417 		return;
1418 	w = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1419 	if (ASSERT_OK_PTR(w, "writable_mmap")) {
1420 		ASSERT_EQ(bpf_map_freeze(fd), -EBUSY,
1421 			  "freeze rejected while writable mmap held");
1422 		munmap(w, 4096);
1423 	}
1424 	close(fd);
1425 }
1426 
1427 static void no_writable_mmap_frozen(void)
1428 {
1429 	void *w;
1430 	int fd;
1431 
1432 	fd = make_excl_map(BPF_F_MMAPABLE, 4096);
1433 	if (!ASSERT_OK_FD(fd, "excl_mmapable_map"))
1434 		return;
1435 	ASSERT_OK(bpf_map_freeze(fd), "freeze");
1436 	w = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1437 	ASSERT_EQ(w, MAP_FAILED, "writable mmap of frozen map rejected");
1438 	if (w != MAP_FAILED)
1439 		munmap(w, 4096);
1440 	close(fd);
1441 }
1442 
1443 static void map_hash_matches_libbpf(void)
1444 {
1445 	__u8 kbuf[SHA256_DIGEST_LENGTH], lbuf[SHA256_DIGEST_LENGTH], val[64] = {};
1446 	struct bpf_map_info info;
1447 	__u32 ilen, key = 0;
1448 	int fd, i;
1449 
1450 	/*
1451 	 * The signing scheme assumes the kernel's map hash equals what libbpf
1452 	 * computes over the same bytes (gen_loader bakes libbpf_sha256(blob);
1453 	 * the kernel recomputes via array_map_get_hash). Pin that they agree.
1454 	 */
1455 	for (i = 0; i < (int)sizeof(val); i++)
1456 		val[i] = i * 7 + 1;
1457 	fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "h", 4, sizeof(val), 1, NULL);
1458 	if (!ASSERT_OK_FD(fd, "array_map"))
1459 		return;
1460 	ASSERT_OK(bpf_map_update_elem(fd, &key, val, 0), "update");
1461 	ASSERT_OK(bpf_map_freeze(fd), "freeze");
1462 	memset(&info, 0, sizeof(info));
1463 	info.hash = ptr_to_u64(kbuf);
1464 	info.hash_size = sizeof(kbuf);
1465 	ilen = sizeof(info);
1466 	if (ASSERT_OK(bpf_map_get_info_by_fd(fd, &info, &ilen), "get_hash")) {
1467 		libbpf_sha256(val, sizeof(val), lbuf);
1468 		ASSERT_EQ(memcmp(kbuf, lbuf, sizeof(kbuf)), 0,
1469 			  "kernel map hash matches libbpf_sha256");
1470 	}
1471 	close(fd);
1472 }
1473 
1474 static void map_hash_multi_element(void)
1475 {
1476 	const __u32 nr = 8, value_size = 64;
1477 	__u8 kbuf[SHA256_DIGEST_LENGTH], lbuf[SHA256_DIGEST_LENGTH];
1478 	struct bpf_map_info info;
1479 	__u32 ilen, i, j;
1480 	__u8 *full;
1481 	int fd;
1482 
1483 	/*
1484 	 * array_map_get_hash() hashes elem_size * max_entries (the whole value
1485 	 * area), not just element 0. With an 8-aligned value_size elem_size has
1486 	 * no padding, so pin that a >1-entry array's kernel hash equals
1487 	 * libbpf_sha256() over the full, concatenated element contents.
1488 	 */
1489 	fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "h", 4, value_size, nr, NULL);
1490 	if (!ASSERT_OK_FD(fd, "array_map"))
1491 		return;
1492 	full = calloc(nr, value_size);
1493 	if (!ASSERT_OK_PTR(full, "buf"))
1494 		goto close_fd;
1495 	for (i = 0; i < nr; i++) {
1496 		__u8 *v = full + i * value_size;
1497 
1498 		for (j = 0; j < value_size; j++)
1499 			v[j] = i * 31 + j * 7 + 1;
1500 		ASSERT_OK(bpf_map_update_elem(fd, &i, v, 0), "update");
1501 	}
1502 	ASSERT_OK(bpf_map_freeze(fd), "freeze");
1503 	memset(&info, 0, sizeof(info));
1504 	info.hash = ptr_to_u64(kbuf);
1505 	info.hash_size = sizeof(kbuf);
1506 	ilen = sizeof(info);
1507 	if (ASSERT_OK(bpf_map_get_info_by_fd(fd, &info, &ilen), "get_hash")) {
1508 		libbpf_sha256(full, (size_t)nr * value_size, lbuf);
1509 		ASSERT_EQ(memcmp(kbuf, lbuf, sizeof(kbuf)), 0,
1510 			  "kernel hash covers full multi-element value area");
1511 	}
1512 	free(full);
1513 close_fd:
1514 	close(fd);
1515 }
1516 
1517 static void map_hash_bad_size(void)
1518 {
1519 	__u8 kbuf[SHA256_DIGEST_LENGTH], val[64] = {};
1520 	struct bpf_map_info info;
1521 	__u32 ilen, key = 0;
1522 	int fd;
1523 
1524 	fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "h", 4, sizeof(val), 1, NULL);
1525 	if (!ASSERT_OK_FD(fd, "array_map"))
1526 		return;
1527 	ASSERT_OK(bpf_map_update_elem(fd, &key, val, 0), "update");
1528 	ASSERT_OK(bpf_map_freeze(fd), "freeze");
1529 	memset(&info, 0, sizeof(info));
1530 	info.hash = ptr_to_u64(kbuf);
1531 	info.hash_size = sizeof(kbuf) / 2;
1532 	ilen = sizeof(info);
1533 	ASSERT_EQ(bpf_map_get_info_by_fd(fd, &info, &ilen), -EINVAL,
1534 		  "wrong hash_size rejected");
1535 	close(fd);
1536 }
1537 
1538 static void map_hash_unsupported_type(void)
1539 {
1540 	__u8 kbuf[SHA256_DIGEST_LENGTH];
1541 	struct bpf_map_info info;
1542 	__u32 ilen;
1543 	int fd;
1544 
1545 	/* Only arrays implement map_get_hash; a hash map must be refused. */
1546 	fd = bpf_map_create(BPF_MAP_TYPE_HASH, "h", 4, 8, 4, NULL);
1547 	if (!ASSERT_OK_FD(fd, "hash_map"))
1548 		return;
1549 	memset(&info, 0, sizeof(info));
1550 	info.hash = ptr_to_u64(kbuf);
1551 	info.hash_size = sizeof(kbuf);
1552 	ilen = sizeof(info);
1553 	ASSERT_EQ(bpf_map_get_info_by_fd(fd, &info, &ilen), -EINVAL,
1554 		  "hash unsupported for non-array map");
1555 	close(fd);
1556 }
1557 
1558 static int setup_meta_map(const struct gen_loader_fixture *f)
1559 {
1560 	LIBBPF_OPTS(bpf_map_create_opts, mopts,
1561 		    .excl_prog_hash = f->excl,
1562 		    .excl_prog_hash_size = sizeof(f->excl));
1563 	__u32 key = 0;
1564 	int fd;
1565 
1566 	fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "__loader.map", 4,
1567 			    f->data_sz, 1, &mopts);
1568 	if (fd < 0)
1569 		return -errno;
1570 	if (bpf_map_update_elem(fd, &key, f->blob, 0) || bpf_map_freeze(fd)) {
1571 		close(fd);
1572 		return -errno;
1573 	}
1574 	return fd;
1575 }
1576 
1577 static void lsm_signature_verdict(void)
1578 {
1579 	char dir_tmpl[] = "/tmp/signed_loader_lsmXXXXXX", *dir = NULL;
1580 	struct test_signed_loader_lsm *lsm = NULL;
1581 	__u32 sig_sz = 8192, msig_sz = 8192;
1582 	int map_fd = -1, prog_fd = -1;
1583 	bool have_fixture = false;
1584 	struct gen_loader_fixture f;
1585 	unsigned char *buf;
1586 	__s32 ses_serial;
1587 	__u8 sig[8192];
1588 
1589 	lsm = test_signed_loader_lsm__open_and_load();
1590 	if (!ASSERT_OK_PTR(lsm, "lsm_skel_load"))
1591 		return;
1592 	lsm->bss->monitored_tid = sys_gettid();
1593 	if (!ASSERT_OK(test_signed_loader_lsm__attach(lsm), "lsm_attach"))
1594 		goto out;
1595 
1596 	have_fixture = true;
1597 	if (gen_loader_fixture_init(&f) != 0)
1598 		goto out;
1599 
1600 	map_fd = setup_meta_map(&f);
1601 	if (!ASSERT_OK_FD(map_fd, "meta_map_unsigned"))
1602 		goto out;
1603 	lsm->bss->seen = 0;
1604 	prog_fd = load_loader(f.gopts.insns, f.gopts.insns_sz, map_fd, NULL, 0, 0, 0);
1605 	close(map_fd);
1606 	map_fd = -1;
1607 	if (!ASSERT_OK_FD(prog_fd, "unsigned loader load"))
1608 		goto out;
1609 	close(prog_fd);
1610 	prog_fd = -1;
1611 	if (!ASSERT_NEQ(lsm->bss->seen, 0, "bpf LSM in the active LSM set"))
1612 		goto out;
1613 	ASSERT_EQ(lsm->bss->seen, 1, "unsigned: one observed load");
1614 	ASSERT_EQ(lsm->bss->sig_verdict, BPF_SIG_UNSIGNED, "unsigned verdict");
1615 	ASSERT_EQ(lsm->bss->sig_keyring_type, BPF_SIG_KEYRING_NONE, "unsigned keyring type");
1616 	ASSERT_EQ(lsm->bss->sig_keyring_serial, 0, "unsigned: no keyring serial");
1617 
1618 	syscall(__NR_request_key, "keyring", "_uid.0", NULL,
1619 		KEY_SPEC_SESSION_KEYRING);
1620 	dir = mkdtemp(dir_tmpl);
1621 	if (!ASSERT_OK_PTR(dir, "mkdtemp"))
1622 		goto out;
1623 	if (!ASSERT_OK(run_setup("setup-rsa", dir), "verify_sig_setup")) {
1624 		rmdir(dir);
1625 		dir = NULL;
1626 		goto out;
1627 	}
1628 	if (!ASSERT_OK(sign_buf(dir, f.gopts.insns, f.gopts.insns_sz, sig,
1629 				&sig_sz), "sign-file"))
1630 		goto out;
1631 
1632 	map_fd = setup_meta_map(&f);
1633 	if (!ASSERT_OK_FD(map_fd, "meta_map_signed"))
1634 		goto out;
1635 	lsm->bss->seen = 0;
1636 	prog_fd = load_loader(f.gopts.insns, f.gopts.insns_sz, map_fd, sig,
1637 			      sig_sz, KEY_SPEC_SESSION_KEYRING, 0);
1638 	close(map_fd);
1639 	map_fd = -1;
1640 	ASSERT_EQ(prog_fd, -EACCES, "unfolded metadata rejected");
1641 	if (prog_fd >= 0)
1642 		close(prog_fd);
1643 	prog_fd = -1;
1644 
1645 	ses_serial = syscall(__NR_keyctl, KEYCTL_GET_KEYRING_ID,
1646 			     KEY_SPEC_SESSION_KEYRING, 0);
1647 	ASSERT_EQ(lsm->bss->seen, 1, "signed: one observed load");
1648 	ASSERT_EQ(lsm->bss->sig_verdict, BPF_SIG_VERIFIED,
1649 		  "admission saw a valid signature");
1650 	ASSERT_EQ(lsm->bss->sig_keyring_type, BPF_SIG_KEYRING_USER, "signed keyring type");
1651 	ASSERT_GT(ses_serial, 0, "session keyring serial resolved");
1652 	ASSERT_EQ(lsm->bss->sig_keyring_serial, ses_serial,
1653 		  "signed: validated against session keyring");
1654 
1655 	buf = malloc((size_t)f.gopts.insns_sz + f.data_sz);
1656 	if (!ASSERT_OK_PTR(buf, "meta_signbuf"))
1657 		goto out;
1658 	memcpy(buf, f.gopts.insns, f.gopts.insns_sz);
1659 	memcpy(buf + f.gopts.insns_sz, f.blob, f.data_sz);
1660 	if (!ASSERT_OK(sign_buf(dir, buf, f.gopts.insns_sz + f.data_sz,
1661 				sig, &msig_sz), "sign insns||metadata")) {
1662 		free(buf);
1663 		goto out;
1664 	}
1665 	free(buf);
1666 
1667 	map_fd = setup_meta_map(&f);
1668 	if (!ASSERT_OK_FD(map_fd, "meta_map_bound"))
1669 		goto out;
1670 	lsm->bss->seen = 0;
1671 	prog_fd = load_loader(f.gopts.insns, f.gopts.insns_sz, map_fd, sig,
1672 			      msig_sz, KEY_SPEC_SESSION_KEYRING, 1);
1673 	close(map_fd);
1674 	map_fd = -1;
1675 	if (!ASSERT_OK_FD(prog_fd, "metadata-bound loader load"))
1676 		goto out;
1677 	close(prog_fd);
1678 	prog_fd = -1;
1679 	ASSERT_EQ(lsm->bss->seen, 1, "metadata: one observed load");
1680 	ASSERT_EQ(lsm->bss->sig_verdict, BPF_SIG_VERIFIED,
1681 		  "metadata-bound verdict");
1682 out:
1683 	if (map_fd >= 0)
1684 		close(map_fd);
1685 	if (prog_fd >= 0)
1686 		close(prog_fd);
1687 	if (have_fixture)
1688 		gen_loader_fixture_fini(&f);
1689 	if (dir)
1690 		run_setup("cleanup", dir);
1691 	test_signed_loader_lsm__destroy(lsm);
1692 }
1693 
1694 /*
1695  * Load-time metadata verification: the kernel folds the frozen metadata map
1696  * into the signature (insns || metadata) and checks it at BPF_PROG_LOAD via
1697  * fd_array_cnt, rather than the loader checking from within BPF. Sign that
1698  * concatenation, hand the kernel the map, and confirm the signed loader loads,
1699  * runs, and installs its target.
1700  */
1701 static int loadtime_drive(const char *dir, const void *insns, __u32 insns_sz,
1702 			  const void *data, __u32 data_sz, const __u8 *excl,
1703 			  void *ctx, __u32 ctx_sz, int *load_ret, bool *ran)
1704 {
1705 	LIBBPF_OPTS(bpf_map_create_opts, mopts,
1706 		    .excl_prog_hash = excl,
1707 		    .excl_prog_hash_size = SHA256_DIGEST_LENGTH);
1708 	__u32 sig_sz = 8192, key = 0;
1709 	unsigned char *buf = NULL;
1710 	int map_fd, prog_fd, ret = 0;
1711 	union bpf_attr attr;
1712 	__u8 sig[8192];
1713 
1714 	*ran = false;
1715 	*load_ret = 0;
1716 
1717 	/*
1718 	 * Metadata map, bound to the loader digest and frozen, exactly as
1719 	 * skel_internal.h's bpf_load_and_run() sets it up.
1720 	 */
1721 	map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "__loader.map", 4,
1722 				data_sz, 1, &mopts);
1723 	if (map_fd < 0) {
1724 		ret = -errno;
1725 		goto out_load;
1726 	}
1727 	if (bpf_map_update_elem(map_fd, &key, data, 0) || bpf_map_freeze(map_fd)) {
1728 		ret = -errno;
1729 		goto out_load;
1730 	}
1731 
1732 	/* Sign insns || metadata, the same bytes the kernel reconstructs. */
1733 	buf = malloc((size_t)insns_sz + data_sz);
1734 	if (!buf) {
1735 		ret = -ENOMEM;
1736 		goto out_load;
1737 	}
1738 	memcpy(buf, insns, insns_sz);
1739 	memcpy(buf + insns_sz, data, data_sz);
1740 	ret = sign_buf(dir, buf, insns_sz + data_sz, sig, &sig_sz);
1741 	if (ret)
1742 		goto out_load;
1743 
1744 	memset(&attr, 0, sizeof(attr));
1745 	attr.prog_type = BPF_PROG_TYPE_SYSCALL;
1746 	attr.insns = ptr_to_u64(insns);
1747 	attr.insn_cnt = insns_sz / sizeof(struct bpf_insn);
1748 	attr.license = ptr_to_u64("Dual BSD/GPL");
1749 	attr.prog_flags = BPF_F_SLEEPABLE;
1750 	attr.fd_array = ptr_to_u64(&map_fd);
1751 	attr.signature = ptr_to_u64(sig);
1752 	attr.signature_size = sig_sz;
1753 	attr.keyring_id = KEY_SPEC_SESSION_KEYRING;
1754 	attr.fd_array_cnt = 1;
1755 	memcpy(attr.prog_name, "__loader.prog", sizeof("__loader.prog"));
1756 	prog_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr,
1757 			  offsetofend(union bpf_attr, keyring_id));
1758 	if (prog_fd < 0) {
1759 		ret = -errno;
1760 		goto out_load;
1761 	}
1762 
1763 	memset(&attr, 0, sizeof(attr));
1764 	attr.test.prog_fd = prog_fd;
1765 	attr.test.ctx_in = ptr_to_u64(ctx);
1766 	attr.test.ctx_size_in = ctx_sz;
1767 	if (syscall(__NR_bpf, BPF_PROG_RUN, &attr,
1768 		    offsetofend(union bpf_attr, test)) < 0) {
1769 		ret = -errno;
1770 		goto out_prog;
1771 	}
1772 	*ran = true;
1773 	ret = (int)attr.test.retval;
1774 out_prog:
1775 	close(prog_fd);
1776 	goto out_map;
1777 out_load:
1778 	*load_ret = ret;
1779 out_map:
1780 	free(buf);
1781 	if (map_fd >= 0)
1782 		close(map_fd);
1783 	return ret;
1784 }
1785 
1786 static void loadtime_verify(struct bpf_object *obj, int expect_maps)
1787 {
1788 	LIBBPF_OPTS(gen_loader_opts, gopts, .gen_hash = true);
1789 	char dir_tmpl[] = "/tmp/signed_loader_ltXXXXXX", *dir = NULL;
1790 	int nr_maps = 0, nr_progs = 0, load_ret = 0, r;
1791 	__u8 excl[SHA256_DIGEST_LENGTH];
1792 	struct bpf_prog_desc *pd;
1793 	struct bpf_map_desc *md;
1794 	unsigned char *blob = NULL;
1795 	struct bpf_program *p;
1796 	struct bpf_map *m;
1797 	__u32 ctx_sz, data_sz;
1798 	void *ctx = NULL;
1799 	bool ran = false;
1800 
1801 	syscall(__NR_request_key, "keyring", "_uid.0", NULL,
1802 		KEY_SPEC_SESSION_KEYRING);
1803 	dir = mkdtemp(dir_tmpl);
1804 	if (!ASSERT_OK_PTR(dir, "mkdtemp"))
1805 		return;
1806 	if (!ASSERT_OK(run_setup("setup-rsa", dir), "verify_sig_setup")) {
1807 		rmdir(dir);
1808 		return;
1809 	}
1810 
1811 	if (!ASSERT_OK(bpf_object__gen_loader(obj, &gopts), "gen_loader"))
1812 		goto out;
1813 	if (!ASSERT_OK(bpf_object__load(obj), "gen_load"))
1814 		goto out;
1815 
1816 	bpf_object__for_each_program(p, obj)
1817 		nr_progs++;
1818 	bpf_object__for_each_map(m, obj)
1819 		nr_maps++;
1820 	if (!ASSERT_EQ(nr_maps, expect_maps, "fixture map count"))
1821 		goto out;
1822 
1823 	ctx_sz = sizeof(struct bpf_loader_ctx) +
1824 		 nr_maps * sizeof(struct bpf_map_desc) +
1825 		 nr_progs * sizeof(struct bpf_prog_desc);
1826 	ctx = calloc(1, ctx_sz);
1827 	if (!ASSERT_OK_PTR(ctx, "ctx_alloc"))
1828 		goto out;
1829 	((struct bpf_loader_ctx *)ctx)->sz = ctx_sz;
1830 
1831 	data_sz = gopts.data_sz;
1832 	blob = malloc(data_sz);
1833 	if (!ASSERT_OK_PTR(blob, "blob_alloc"))
1834 		goto out;
1835 	memcpy(blob, gopts.data, data_sz);
1836 
1837 	/* excl_prog_hash = SHA256(loader insns) == the loader's prog->digest. */
1838 	libbpf_sha256(gopts.insns, gopts.insns_sz, excl);
1839 
1840 	r = loadtime_drive(dir, gopts.insns, gopts.insns_sz, blob, data_sz,
1841 			   excl, ctx, ctx_sz, &load_ret, &ran);
1842 	ASSERT_OK(load_ret, "signed loader loaded (insns || metadata)");
1843 	ASSERT_TRUE(ran, "loader ran");
1844 	ASSERT_EQ(r, 0, "loader installed its target");
1845 
1846 	md = (struct bpf_map_desc *)((char *)ctx + sizeof(struct bpf_loader_ctx));
1847 	pd = (struct bpf_prog_desc *)(md + nr_maps);
1848 	ASSERT_GT(pd[0].prog_fd, 0, "target program installed");
1849 	if (nr_maps)
1850 		ASSERT_GT(md[0].map_fd, 0, "target map installed");
1851 
1852 	close_loader_ctx_fds(ctx, nr_maps, nr_progs);
1853 out:
1854 	free(blob);
1855 	free(ctx);
1856 	if (dir)
1857 		run_setup("cleanup", dir);
1858 }
1859 
1860 static void loadtime_no_map(void)
1861 {
1862 	struct test_signed_loader *skel = test_signed_loader__open();
1863 
1864 	if (!ASSERT_OK_PTR(skel, "skel_open"))
1865 		return;
1866 	loadtime_verify(skel->obj, 0);
1867 	test_signed_loader__destroy(skel);
1868 }
1869 
1870 static void loadtime_with_map(void)
1871 {
1872 	struct test_signed_loader_map *skel = test_signed_loader_map__open();
1873 
1874 	if (!ASSERT_OK_PTR(skel, "skel_open"))
1875 		return;
1876 	loadtime_verify(skel->obj, 1);
1877 	test_signed_loader_map__destroy(skel);
1878 }
1879 
1880 /*
1881  * End-to-end signed load with a post-quantum key. ML-DSA (FIPS-204) is wired
1882  * through the X.509 and PKCS#7 parsers, and BPF reaches them via
1883  * verify_pkcs7_signature() without knowing the algorithm, so an ML-DSA key in
1884  * the keyring should verify an ML-DSA signed program with no BPF-side work.
1885  */
1886 static void mldsa_signed_load(void)
1887 {
1888 	char dir_tmpl[] = "/tmp/bpfmldsaXXXXXX";
1889 	int map_fd = -1, prog_fd = -1, err;
1890 	__u8 *sig = NULL, *buf = NULL;
1891 	struct gen_loader_fixture f;
1892 	bool have_fixture = false;
1893 	__u32 sig_sz = 16384;
1894 	char *dir;
1895 
1896 	syscall(__NR_request_key, "keyring", "_uid.0", NULL,
1897 		KEY_SPEC_SESSION_KEYRING);
1898 	dir = mkdtemp(dir_tmpl);
1899 	if (!ASSERT_OK_PTR(dir, "mkdtemp"))
1900 		return;
1901 
1902 	err = run_setup("setup-mldsa", dir);
1903 	if (err == SETUP_SKIP) {
1904 		printf("%s:SKIP:no working ML-DSA signing, set SELFTESTS_VERBOSE=1\n",
1905 		       __func__);
1906 		test__skip();
1907 		genkey_dir_fini(dir);
1908 		return;
1909 	}
1910 	if (!ASSERT_OK(err, "verify_sig_setup setup-mldsa")) {
1911 		genkey_dir_fini(dir);
1912 		return;
1913 	}
1914 
1915 	sig = malloc(sig_sz);
1916 	if (!ASSERT_OK_PTR(sig, "sig buf"))
1917 		goto out;
1918 	have_fixture = true;
1919 	if (gen_loader_fixture_init(&f) != 0)
1920 		goto out;
1921 
1922 	buf = malloc((size_t)f.gopts.insns_sz + f.data_sz);
1923 	if (!ASSERT_OK_PTR(buf, "signbuf"))
1924 		goto out;
1925 	memcpy(buf, f.gopts.insns, f.gopts.insns_sz);
1926 	memcpy(buf + f.gopts.insns_sz, f.blob, f.data_sz);
1927 
1928 	/*
1929 	 * ML-DSA hashes the message itself, but openssl before 4.0 cannot
1930 	 * produce a CMS message without signedAttrs for it, and with those in
1931 	 * play only SHA-512 is permitted for the messageDigest attribute.
1932 	 */
1933 	if (!ASSERT_OK(sign_buf_digest(dir, buf, f.gopts.insns_sz + f.data_sz,
1934 				       sig, &sig_sz, "sha512"),
1935 		       "sign insns||metadata with ML-DSA"))
1936 		goto out;
1937 
1938 	/*
1939 	 * Guard against the setup silently handing back some other key type:
1940 	 * an RSA or ECDSA signature is a few hundred bytes, where an ML-DSA-87
1941 	 * one cannot be smaller than the raw signature it carries.
1942 	 */
1943 	ASSERT_GT(sig_sz, MLDSA87_SIGNATURE_SIZE, "ML-DSA-87 signature size");
1944 
1945 	map_fd = setup_meta_map(&f);
1946 	if (!ASSERT_OK_FD(map_fd, "meta_map"))
1947 		goto out;
1948 	prog_fd = load_loader(f.gopts.insns, f.gopts.insns_sz, map_fd, sig,
1949 			      sig_sz, KEY_SPEC_SESSION_KEYRING, 1);
1950 	ASSERT_OK_FD(prog_fd, "ML-DSA signed loader load");
1951 out:
1952 	if (prog_fd >= 0)
1953 		close(prog_fd);
1954 	if (map_fd >= 0)
1955 		close(map_fd);
1956 	if (have_fixture)
1957 		gen_loader_fixture_fini(&f);
1958 	free(buf);
1959 	free(sig);
1960 	run_setup("cleanup", dir);
1961 }
1962 
1963 /*
1964  * A signed program need not bind any map. A plain BPF_PROG_TYPE_SYSCALL
1965  * program with no fd_array is signed over its instructions alone: the kernel
1966  * verifies the signature, folds no metadata, and the program loads. Exercise
1967  * the fd_array == NULL / fd_array_cnt == 0 path, and confirm the signature
1968  * still authenticates the instructions (a tampered copy is rejected).
1969  */
1970 static void signed_no_fd_array(void)
1971 {
1972 	struct bpf_insn insns[] = {
1973 		BPF_MOV64_IMM(BPF_REG_0, 0),
1974 		BPF_EXIT_INSN(),
1975 	};
1976 	char dir_tmpl[] = "/tmp/signed_loaderXXXXXX", *dir;
1977 	__u32 sig_sz = 8192;
1978 	union bpf_attr attr;
1979 	__u8 sig[8192];
1980 	int prog_fd, err;
1981 
1982 	syscall(__NR_request_key, "keyring", "_uid.0", NULL,
1983 		KEY_SPEC_SESSION_KEYRING);
1984 	dir = mkdtemp(dir_tmpl);
1985 	if (!ASSERT_OK_PTR(dir, "mkdtemp"))
1986 		return;
1987 	if (!ASSERT_OK(run_setup("setup-rsa", dir), "verify_sig_setup")) {
1988 		rmdir(dir);
1989 		return;
1990 	}
1991 
1992 	/* No metadata map: the signed payload is the instructions alone. */
1993 	if (!ASSERT_OK(sign_buf(dir, insns, sizeof(insns), sig, &sig_sz),
1994 		       "sign-file"))
1995 		goto cleanup;
1996 
1997 	memset(&attr, 0, sizeof(attr));
1998 	attr.prog_type = BPF_PROG_TYPE_SYSCALL;
1999 	attr.insns = ptr_to_u64(insns);
2000 	attr.insn_cnt = ARRAY_SIZE(insns);
2001 	attr.license = ptr_to_u64("Dual BSD/GPL");
2002 	attr.prog_flags = BPF_F_SLEEPABLE;
2003 	attr.signature = ptr_to_u64(sig);
2004 	attr.signature_size = sig_sz;
2005 	attr.keyring_id = KEY_SPEC_SESSION_KEYRING;
2006 	/* fd_array and fd_array_cnt deliberately left NULL/0. */
2007 	memcpy(attr.prog_name, "signed_nomap", sizeof("signed_nomap"));
2008 
2009 	prog_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr,
2010 			  offsetofend(union bpf_attr, keyring_id));
2011 	if (!ASSERT_GE(prog_fd, 0, "map-less signed program loaded")) {
2012 		if (prog_fd >= 0)
2013 			close(prog_fd);
2014 		goto cleanup;
2015 	}
2016 	close(prog_fd);
2017 
2018 	/* The signature covers the instructions, so tampering must be rejected. */
2019 	insns[0].imm = 1;
2020 	prog_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr,
2021 			  offsetofend(union bpf_attr, keyring_id));
2022 	err = prog_fd < 0 ? -errno : prog_fd;
2023 	ASSERT_EQ(err, -EKEYREJECTED, "tampered map-less program rejected");
2024 	if (prog_fd >= 0)
2025 		close(prog_fd);
2026 cleanup:
2027 	run_setup("cleanup", dir);
2028 }
2029 
2030 /*
2031  * A signed program may reach maps only through fd_array indices, so the kernel
2032  * folds (and thus attests) them. A direct BPF_PSEUDO_MAP_FD reference - a raw,
2033  * unfolded fd baked into the signed instructions - is rejected by the verifier.
2034  */
2035 static void signed_map_by_fd_rejected(void)
2036 {
2037 	struct bpf_insn insns[] = {
2038 		BPF_LD_MAP_FD(BPF_REG_1, 0),
2039 		BPF_MOV64_IMM(BPF_REG_0, 0),
2040 		BPF_EXIT_INSN(),
2041 	};
2042 	char dir_tmpl[] = "/tmp/signed_loaderXXXXXX", *dir;
2043 	__u32 sig_sz = 8192;
2044 	union bpf_attr attr;
2045 	__u8 sig[8192];
2046 	int map_fd, prog_fd, err;
2047 
2048 	map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "sig_mapfd", 4, 4, 1, NULL);
2049 	if (!ASSERT_GE(map_fd, 0, "map_create"))
2050 		return;
2051 	insns[0].imm = map_fd;	/* bake the raw map fd into the ld_imm64 */
2052 
2053 	syscall(__NR_request_key, "keyring", "_uid.0", NULL,
2054 		KEY_SPEC_SESSION_KEYRING);
2055 	dir = mkdtemp(dir_tmpl);
2056 	if (!ASSERT_OK_PTR(dir, "mkdtemp"))
2057 		goto out_map;
2058 	if (!ASSERT_OK(run_setup("setup-rsa", dir), "verify_sig_setup")) {
2059 		rmdir(dir);
2060 		goto out_map;
2061 	}
2062 
2063 	/* Sign the instructions, raw map fd and all. */
2064 	if (!ASSERT_OK(sign_buf(dir, insns, sizeof(insns), sig, &sig_sz),
2065 		       "sign-file"))
2066 		goto cleanup;
2067 
2068 	memset(&attr, 0, sizeof(attr));
2069 	attr.prog_type = BPF_PROG_TYPE_SYSCALL;
2070 	attr.insns = ptr_to_u64(insns);
2071 	attr.insn_cnt = ARRAY_SIZE(insns);
2072 	attr.license = ptr_to_u64("Dual BSD/GPL");
2073 	attr.prog_flags = BPF_F_SLEEPABLE;
2074 	attr.signature = ptr_to_u64(sig);
2075 	attr.signature_size = sig_sz;
2076 	attr.keyring_id = KEY_SPEC_SESSION_KEYRING;
2077 	/* No fd_array: the map is reached by a raw fd in the instructions. */
2078 	memcpy(attr.prog_name, "signed_mapfd", sizeof("signed_mapfd"));
2079 
2080 	prog_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr,
2081 			  offsetofend(union bpf_attr, keyring_id));
2082 	err = prog_fd < 0 ? -errno : prog_fd;
2083 	ASSERT_EQ(err, -EINVAL, "signed program referencing a map by fd rejected");
2084 	if (prog_fd >= 0)
2085 		close(prog_fd);
2086 cleanup:
2087 	run_setup("cleanup", dir);
2088 out_map:
2089 	close(map_fd);
2090 }
2091 
2092 /*
2093  * A signed program may reach maps only through the continuous fd_array, so the
2094  * kernel folds (and thus attests) them. Referencing a map by fd_array *index*
2095  * while leaving fd_array_cnt at 0 selects the sparse path, which resolves a map
2096  * the signature never covered; the verifier rejects it up front with -EACCES.
2097  */
2098 static void signed_sparse_fd_array_rejected(void)
2099 {
2100 	struct bpf_insn insns[] = {
2101 		BPF_LD_IMM64_RAW(BPF_REG_1, BPF_PSEUDO_MAP_IDX, 0),
2102 		BPF_MOV64_IMM(BPF_REG_0, 0),
2103 		BPF_EXIT_INSN(),
2104 	};
2105 	char dir_tmpl[] = "/tmp/signed_loader_spXXXXXX", *dir;
2106 	__u32 sig_sz = 8192;
2107 	union bpf_attr attr;
2108 	__u8 sig[8192];
2109 	int map_fd, prog_fd, err;
2110 
2111 	map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "sig_sparse", 4, 4, 1, NULL);
2112 	if (!ASSERT_GE(map_fd, 0, "map_create"))
2113 		return;
2114 
2115 	syscall(__NR_request_key, "keyring", "_uid.0", NULL,
2116 		KEY_SPEC_SESSION_KEYRING);
2117 	dir = mkdtemp(dir_tmpl);
2118 	if (!ASSERT_OK_PTR(dir, "mkdtemp"))
2119 		goto out_map;
2120 	if (!ASSERT_OK(run_setup("setup-rsa", dir), "verify_sig_setup")) {
2121 		rmdir(dir);
2122 		goto out_map;
2123 	}
2124 
2125 	/* Sign the instructions alone; the sparse map is not folded. */
2126 	if (!ASSERT_OK(sign_buf(dir, insns, sizeof(insns), sig, &sig_sz),
2127 		       "sign-file"))
2128 		goto cleanup;
2129 
2130 	memset(&attr, 0, sizeof(attr));
2131 	attr.prog_type = BPF_PROG_TYPE_SYSCALL;
2132 	attr.insns = ptr_to_u64(insns);
2133 	attr.insn_cnt = ARRAY_SIZE(insns);
2134 	attr.license = ptr_to_u64("Dual BSD/GPL");
2135 	attr.prog_flags = BPF_F_SLEEPABLE;
2136 	attr.fd_array = ptr_to_u64(&map_fd);
2137 	attr.fd_array_cnt = 0; /* sparse: force lazy map resolution */
2138 	attr.signature = ptr_to_u64(sig);
2139 	attr.signature_size = sig_sz;
2140 	attr.keyring_id = KEY_SPEC_SESSION_KEYRING;
2141 	memcpy(attr.prog_name, "signed_sparse", sizeof("signed_sparse"));
2142 
2143 	prog_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr,
2144 			  offsetofend(union bpf_attr, keyring_id));
2145 	err = prog_fd < 0 ? -errno : prog_fd;
2146 	ASSERT_EQ(err, -EACCES, "signed program binding a sparse fd_array map rejected");
2147 	if (prog_fd >= 0)
2148 		close(prog_fd);
2149 cleanup:
2150 	run_setup("cleanup", dir);
2151 out_map:
2152 	close(map_fd);
2153 }
2154 
2155 static void signed_module_kfunc_rejected(void)
2156 {
2157 	struct bpf_insn insns[] = {
2158 		BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, BPF_PSEUDO_KFUNC_CALL, 1, 1),
2159 		BPF_MOV64_IMM(BPF_REG_0, 0),
2160 		BPF_EXIT_INSN(),
2161 	};
2162 	char dir_tmpl[] = "/tmp/signed_loader_kfnXXXXXX", *dir;
2163 	int prog_fd, err, fds[2];
2164 	struct btf *btf = NULL;
2165 	__u32 sig_sz = 8192;
2166 	union bpf_attr attr;
2167 	__u8 sig[8192];
2168 
2169 	syscall(__NR_request_key, "keyring", "_uid.0", NULL,
2170 		KEY_SPEC_SESSION_KEYRING);
2171 	dir = mkdtemp(dir_tmpl);
2172 	if (!ASSERT_OK_PTR(dir, "mkdtemp"))
2173 		return;
2174 	if (!ASSERT_OK(run_setup("setup-rsa", dir), "verify_sig_setup")) {
2175 		rmdir(dir);
2176 		return;
2177 	}
2178 	if (!ASSERT_OK(sign_buf(dir, insns, sizeof(insns), sig, &sig_sz),
2179 		       "sign-file"))
2180 		goto cleanup;
2181 	btf = btf__new_empty();
2182 	if (!ASSERT_OK_PTR(btf, "btf_new_empty"))
2183 		goto cleanup;
2184 	btf__add_int(btf, "int", 4, BTF_INT_SIGNED);
2185 	if (!ASSERT_OK(btf__load_into_kernel(btf), "btf_load"))
2186 		goto cleanup;
2187 	fds[0] = -1;
2188 	fds[1] = btf__fd(btf);
2189 
2190 	memset(&attr, 0, sizeof(attr));
2191 	attr.prog_type = BPF_PROG_TYPE_SYSCALL;
2192 	attr.insns = ptr_to_u64(insns);
2193 	attr.insn_cnt = ARRAY_SIZE(insns);
2194 	attr.license = ptr_to_u64("Dual BSD/GPL");
2195 	attr.prog_flags = BPF_F_SLEEPABLE;
2196 	attr.fd_array = ptr_to_u64(fds);
2197 	attr.fd_array_cnt = 0; /* sparse: force lazy kfunc BTF resolution */
2198 	attr.signature = ptr_to_u64(sig);
2199 	attr.signature_size = sig_sz;
2200 	attr.keyring_id = KEY_SPEC_SESSION_KEYRING;
2201 	memcpy(attr.prog_name, "signed_kfunc", sizeof("signed_kfunc"));
2202 
2203 	prog_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr,
2204 			  offsetofend(union bpf_attr, keyring_id));
2205 	err = prog_fd < 0 ? -errno : prog_fd;
2206 	if (prog_fd >= 0)
2207 		close(prog_fd);
2208 
2209 	ASSERT_EQ(err, -EACCES, "module kfunc BTF in signed program rejected");
2210 cleanup:
2211 	if (btf)
2212 		btf__free(btf);
2213 	run_setup("cleanup", dir);
2214 }
2215 
2216 enum subtest_boot {
2217 	BOOT_ANY,
2218 	BOOT_SEALED,
2219 	BOOT_UNSEALED,
2220 };
2221 
2222 static const struct {
2223 	const char *name;
2224 	void (*fn)(void);
2225 	enum subtest_boot boot;
2226 } subtests[] = {
2227 	{ "loadtime_no_map", loadtime_no_map, BOOT_SEALED },
2228 	{ "loadtime_with_map", loadtime_with_map, BOOT_SEALED },
2229 	{ "metadata_match", metadata_match, BOOT_ANY },
2230 	{ "signature_enforced", signature_enforced, BOOT_SEALED },
2231 	{ "signed_nonexcl_fd_array_rejected", signed_nonexcl_fd_array_rejected, BOOT_SEALED },
2232 	{ "signed_unfrozen_fd_array_rejected", signed_unfrozen_fd_array_rejected, BOOT_SEALED },
2233 	{ "signed_nonarray_fd_array_rejected", signed_nonarray_fd_array_rejected, BOOT_SEALED },
2234 	{ "signed_btf_fd_array_rejected", signed_btf_fd_array_rejected, BOOT_ANY },
2235 	{ "signed_core_relo_rejected", signed_core_relo_rejected, BOOT_ANY },
2236 	{ "signed_module_kfunc_rejected", signed_module_kfunc_rejected, BOOT_SEALED },
2237 	{ "signature_failure_logs", signature_failure_logs, BOOT_SEALED },
2238 	{ "signature_too_large", signature_too_large, BOOT_ANY },
2239 	{ "signature_zero_size", signature_zero_size, BOOT_ANY },
2240 	{ "signature_bad_keyring", signature_bad_keyring, BOOT_SEALED },
2241 	{ "bpf_keyring_sealed", bpf_keyring_sealed, BOOT_ANY },
2242 	{ "mldsa_signed_load", mldsa_signed_load, BOOT_SEALED },
2243 	{ "metadata_ctx_max_entries_ignored", metadata_ctx_max_entries_ignored, BOOT_ANY },
2244 	{ "metadata_ctx_initial_value_ignored", metadata_ctx_initial_value_ignored, BOOT_ANY },
2245 	{ "signature_authenticates_insns", signature_authenticates_insns, BOOT_SEALED },
2246 	{ "signature_authenticates_metadata", signature_authenticates_metadata, BOOT_SEALED },
2247 	{ "hash_requires_frozen", hash_requires_frozen, BOOT_ANY },
2248 	{ "no_update_after_freeze", no_update_after_freeze, BOOT_ANY },
2249 	{ "freeze_writable_mmap", freeze_writable_mmap, BOOT_ANY },
2250 	{ "no_writable_mmap_frozen", no_writable_mmap_frozen, BOOT_ANY },
2251 	{ "map_hash_matches_libbpf", map_hash_matches_libbpf, BOOT_ANY },
2252 	{ "map_hash_multi_element", map_hash_multi_element, BOOT_ANY },
2253 	{ "map_hash_bad_size", map_hash_bad_size, BOOT_ANY },
2254 	{ "map_hash_unsupported_type", map_hash_unsupported_type, BOOT_ANY },
2255 	{ "lsm_signature_verdict", lsm_signature_verdict, BOOT_SEALED },
2256 	{ "signed_no_fd_array", signed_no_fd_array, BOOT_SEALED },
2257 	{ "signed_map_by_fd_rejected", signed_map_by_fd_rejected, BOOT_SEALED },
2258 	{ "signed_sparse_fd_array_rejected", signed_sparse_fd_array_rejected, BOOT_SEALED },
2259 	{ "bpf_keyring_provisioned", bpf_keyring_provisioned, BOOT_UNSEALED },
2260 };
2261 
2262 void test_signed_loader(void)
2263 {
2264 	bool unsealed = keyring_unsealed_boot();
2265 	unsigned int i;
2266 
2267 	for (i = 0; i < ARRAY_SIZE(subtests); i++) {
2268 		if (!test__start_subtest(subtests[i].name))
2269 			continue;
2270 		if (subtests[i].boot == BOOT_SEALED && unsealed) {
2271 			printf("%s:SKIP:needs a boot without bpf.keyring_unsealed=1\n",
2272 			       subtests[i].name);
2273 			test__skip();
2274 			continue;
2275 		}
2276 		if (subtests[i].boot == BOOT_UNSEALED && !unsealed) {
2277 			printf("%s:SKIP:needs bpf.keyring_unsealed=1\n",
2278 			       subtests[i].name);
2279 			test__skip();
2280 			continue;
2281 		}
2282 		subtests[i].fn();
2283 	}
2284 }
2285