xref: /linux/tools/testing/selftests/bpf/progs/lsm_bdev.c (revision 5ea5880764cbb164afb17a62e76ca75dc371409d)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2026 Christian Brauner <brauner@kernel.org> */
3 
4 /*
5  * BPF LSM block device integrity tracker for dm-verity.
6  *
7  * Tracks block devices in a hashmap keyed by bd_dev.  When dm-verity
8  * calls security_bdev_setintegrity() during verity_preresume(), the
9  * setintegrity hook records the roothash and signature-validity data.
10  * The free hook cleans up when the device goes away.  The alloc hook
11  * counts allocations for test validation.
12  *
13  * The sleepable hooks exercise bpf_copy_from_user() to verify that
14  * the sleepable classification actually permits sleepable helpers.
15  */
16 
17 #include "vmlinux.h"
18 #include <bpf/bpf_helpers.h>
19 #include <bpf/bpf_tracing.h>
20 
21 struct verity_info {
22 	__u8  has_roothash;	/* LSM_INT_DMVERITY_ROOTHASH seen */
23 	__u8  sig_valid;	/* LSM_INT_DMVERITY_SIG_VALID value (non-NULL = valid) */
24 	__u32 setintegrity_cnt;	/* total setintegrity calls for this dev */
25 };
26 
27 struct {
28 	__uint(type, BPF_MAP_TYPE_HASH);
29 	__uint(max_entries, 64);
30 	__type(key, __u32);		/* dev_t from bdev->bd_dev */
31 	__type(value, struct verity_info);
32 } verity_devices SEC(".maps");
33 
34 /* Global counters exposed to userspace via skeleton bss. */
35 int alloc_count;
36 
37 char _license[] SEC("license") = "GPL";
38 
39 SEC("lsm.s/bdev_setintegrity")
40 int BPF_PROG(bdev_setintegrity, struct block_device *bdev,
41 	     enum lsm_integrity_type type, const void *value, size_t size)
42 {
43 	struct verity_info zero = {};
44 	struct verity_info *info;
45 	__u32 dev;
46 	char buf;
47 
48 	/*
49 	 * Exercise a sleepable helper to confirm the verifier
50 	 * allows it in this sleepable hook.
51 	 */
52 	(void)bpf_copy_from_user(&buf, sizeof(buf), NULL);
53 
54 	dev = bdev->bd_dev;
55 
56 	info = bpf_map_lookup_elem(&verity_devices, &dev);
57 	if (!info) {
58 		bpf_map_update_elem(&verity_devices, &dev, &zero, BPF_NOEXIST);
59 		info = bpf_map_lookup_elem(&verity_devices, &dev);
60 		if (!info)
61 			return 0;
62 	}
63 
64 	if (type == LSM_INT_DMVERITY_ROOTHASH)
65 		info->has_roothash = 1;
66 	else if (type == LSM_INT_DMVERITY_SIG_VALID)
67 		info->sig_valid = (value != NULL);
68 
69 	__sync_fetch_and_add(&info->setintegrity_cnt, 1);
70 
71 	return 0;
72 }
73 
74 SEC("lsm/bdev_free_security")
75 void BPF_PROG(bdev_free_security, struct block_device *bdev)
76 {
77 	__u32 dev = bdev->bd_dev;
78 
79 	bpf_map_delete_elem(&verity_devices, &dev);
80 }
81 
82 SEC("lsm.s/bdev_alloc_security")
83 int BPF_PROG(bdev_alloc_security, struct block_device *bdev)
84 {
85 	char buf;
86 
87 	/*
88 	 * Exercise a sleepable helper to confirm the verifier
89 	 * allows it in this sleepable hook.
90 	 */
91 	(void)bpf_copy_from_user(&buf, sizeof(buf), NULL);
92 
93 	__sync_fetch_and_add(&alloc_count, 1);
94 
95 	return 0;
96 }
97