| // SPDX-License-Identifier: GPL-2.0 |
| /* Copyright (c) 2026 Christian Brauner <brauner@kernel.org> */ |
| |
| /* |
| * BPF LSM block device integrity tracker for dm-verity. |
| * |
| * Tracks block devices in a hashmap keyed by bd_dev. When dm-verity |
| * calls security_bdev_setintegrity() during verity_preresume(), the |
| * setintegrity hook records the roothash and signature-validity data. |
| * The free hook cleans up when the device goes away. The alloc hook |
| * counts allocations for test validation. |
| * |
| * The sleepable hooks exercise bpf_copy_from_user() to verify that |
| * the sleepable classification actually permits sleepable helpers. |
| */ |
| |
| #include "vmlinux.h" |
| #include <bpf/bpf_helpers.h> |
| #include <bpf/bpf_tracing.h> |
| |
| struct verity_info { |
| __u8 has_roothash; /* LSM_INT_DMVERITY_ROOTHASH seen */ |
| __u8 sig_valid; /* LSM_INT_DMVERITY_SIG_VALID value (non-NULL = valid) */ |
| __u32 setintegrity_cnt; /* total setintegrity calls for this dev */ |
| }; |
| |
| struct { |
| __uint(type, BPF_MAP_TYPE_HASH); |
| __uint(max_entries, 64); |
| __type(key, __u32); /* dev_t from bdev->bd_dev */ |
| __type(value, struct verity_info); |
| } verity_devices SEC(".maps"); |
| |
| /* Global counters exposed to userspace via skeleton bss. */ |
| int alloc_count; |
| |
| char _license[] SEC("license") = "GPL"; |
| |
| SEC("lsm.s/bdev_setintegrity") |
| int BPF_PROG(bdev_setintegrity, struct block_device *bdev, |
| enum lsm_integrity_type type, const void *value, size_t size) |
| { |
| struct verity_info zero = {}; |
| struct verity_info *info; |
| __u32 dev; |
| char buf; |
| |
| /* |
| * Exercise a sleepable helper to confirm the verifier |
| * allows it in this sleepable hook. |
| */ |
| (void)bpf_copy_from_user(&buf, sizeof(buf), NULL); |
| |
| dev = bdev->bd_dev; |
| |
| info = bpf_map_lookup_elem(&verity_devices, &dev); |
| if (!info) { |
| bpf_map_update_elem(&verity_devices, &dev, &zero, BPF_NOEXIST); |
| info = bpf_map_lookup_elem(&verity_devices, &dev); |
| if (!info) |
| return 0; |
| } |
| |
| if (type == LSM_INT_DMVERITY_ROOTHASH) |
| info->has_roothash = 1; |
| else if (type == LSM_INT_DMVERITY_SIG_VALID) |
| info->sig_valid = (value != NULL); |
| |
| __sync_fetch_and_add(&info->setintegrity_cnt, 1); |
| |
| return 0; |
| } |
| |
| SEC("lsm/bdev_free_security") |
| void BPF_PROG(bdev_free_security, struct block_device *bdev) |
| { |
| __u32 dev = bdev->bd_dev; |
| |
| bpf_map_delete_elem(&verity_devices, &dev); |
| } |
| |
| SEC("lsm.s/bdev_alloc_security") |
| int BPF_PROG(bdev_alloc_security, struct block_device *bdev) |
| { |
| char buf; |
| |
| /* |
| * Exercise a sleepable helper to confirm the verifier |
| * allows it in this sleepable hook. |
| */ |
| (void)bpf_copy_from_user(&buf, sizeof(buf), NULL); |
| |
| __sync_fetch_and_add(&alloc_count, 1); |
| |
| return 0; |
| } |