// SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2026 Christian Brauner */ /* * 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 #include 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; }