/* 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 #include #include #include #include #include #include #include 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";