1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
/* 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";
|