blob: eb5ed3e7fec1bd269d115e85d238345de61e3720 [file] [log] [blame]
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/* The SPDX header above is actually correct in claiming this was
* LGPL-2.1-or-later, because it is. Since the kernel doesn't consider that
* compatible with GPL we will claim this to be GPL however, which should be
* fine given that LGPL-2.1-or-later downgrades to GPL if needed.
*/
#include <linux/types.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
#include <errno.h>
#include <stddef.h>
#include <stdint.h>
struct super_block {
unsigned long int s_magic;
} __attribute__((preserve_access_index));
struct inode {
struct super_block *i_sb;
} __attribute__((preserve_access_index));
struct file {
struct inode *f_inode;
} __attribute__((preserve_access_index));
/*
* max_entries is set from user space with the bpf_map__set_max_entries helper.
* */
struct {
__uint(type, BPF_MAP_TYPE_HASH_OF_MAPS);
__type(key, uint64_t); /* cgroup ID */
__type(value, uint32_t); /* fs magic set */
} cgroup_hash SEC(".maps");
SEC("lsm/file_open")
int BPF_PROG(restrict_filesystems, struct file *file, int ret)
{
unsigned long raw_magic_number;
uint64_t cgroup_id;
uint32_t *value, *magic_map, magic_number, zero = 0, *is_allow;
/* ret is the return value from the previous BPF program or 0 if it's
* the first hook */
if (ret != 0)
return ret;
BPF_CORE_READ_INTO(&raw_magic_number, file, f_inode, i_sb, s_magic);
/* super_block.s_magic is unsigned long, but magic_map keys are
* uint32_t. Using s_magic as-is would fail on big-endian systems,
* which have 64-bit unsigned long. So cast it. */
magic_number = (uint32_t)raw_magic_number;
cgroup_id = bpf_get_current_cgroup_id();
magic_map = bpf_map_lookup_elem(&cgroup_hash, &cgroup_id);
if (!magic_map)
return 0;
is_allow = bpf_map_lookup_elem(magic_map, &zero);
if (!is_allow)
/* Malformed map, it doesn't include whether it's an allow list
* or a deny list. Allow. */
return 0;
if (*is_allow) {
/* Allow-list: Allow access only if magic_number present in inner map */
if (!bpf_map_lookup_elem(magic_map, &magic_number))
return -EPERM;
} else {
/* Deny-list: Allow access only if magic_number is not present in inner map */
if (bpf_map_lookup_elem(magic_map, &magic_number))
return -EPERM;
}
return 0;
}
static const char _license[] SEC("license") = "GPL";