mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-08-09 06:14:34 +02:00
Add selftests to test block device tracking for bpf lsm programs. Signed-off-by: Christian Brauner <brauner@kernel.org> Link: https://lore.kernel.org/r/20260326-work-bpf-bdev-v2-2-5e3c58963987@kernel.org Signed-off-by: Alexei Starovoitov <ast@kernel.org>
97 lines
2.5 KiB
C
97 lines
2.5 KiB
C
// 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;
|
|
}
|