diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 15:35:18 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 15:35:18 +0000 |
commit | b750101eb236130cf056c675997decbac904cc49 (patch) | |
tree | a5df1a06754bdd014cb975c051c83b01c9a97532 /src/core/bpf/restrict_fs | |
parent | Initial commit. (diff) | |
download | systemd-b750101eb236130cf056c675997decbac904cc49.tar.xz systemd-b750101eb236130cf056c675997decbac904cc49.zip |
Adding upstream version 252.22.upstream/252.22upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/core/bpf/restrict_fs')
-rw-r--r-- | src/core/bpf/restrict_fs/meson.build | 24 | ||||
-rw-r--r-- | src/core/bpf/restrict_fs/restrict-fs-skel.h | 14 | ||||
-rw-r--r-- | src/core/bpf/restrict_fs/restrict-fs.bpf.c | 82 |
3 files changed, 120 insertions, 0 deletions
diff --git a/src/core/bpf/restrict_fs/meson.build b/src/core/bpf/restrict_fs/meson.build new file mode 100644 index 0000000..69cde02 --- /dev/null +++ b/src/core/bpf/restrict_fs/meson.build @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +if conf.get('BPF_FRAMEWORK') != 1 + subdir_done() +endif + +restrict_fs_bpf_o_unstripped = custom_target( + 'restrict-fs.bpf.unstripped.o', + input : 'restrict-fs.bpf.c', + output : 'restrict-fs.bpf.unstripped.o', + command : bpf_o_unstripped_cmd) + +restrict_fs_bpf_o = custom_target( + 'restrict-fs.bpf.o', + input : restrict_fs_bpf_o_unstripped, + output : 'restrict-fs.bpf.o', + command : bpf_o_cmd) + +restrict_fs_skel_h = custom_target( + 'restrict-fs.skel.h', + input : restrict_fs_bpf_o, + output : 'restrict-fs.skel.h', + command : skel_h_cmd, + capture : true) diff --git a/src/core/bpf/restrict_fs/restrict-fs-skel.h b/src/core/bpf/restrict_fs/restrict-fs-skel.h new file mode 100644 index 0000000..412cf62 --- /dev/null +++ b/src/core/bpf/restrict_fs/restrict-fs-skel.h @@ -0,0 +1,14 @@ +/* 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. + */ + +/* libbpf is used via dlopen(), so rename symbols */ +#define bpf_object__open_skeleton sym_bpf_object__open_skeleton +#define bpf_object__load_skeleton sym_bpf_object__load_skeleton +#define bpf_object__destroy_skeleton sym_bpf_object__destroy_skeleton + +#include "bpf/restrict_fs/restrict-fs.skel.h" diff --git a/src/core/bpf/restrict_fs/restrict-fs.bpf.c b/src/core/bpf/restrict_fs/restrict-fs.bpf.c new file mode 100644 index 0000000..eb5ed3e --- /dev/null +++ b/src/core/bpf/restrict_fs/restrict-fs.bpf.c @@ -0,0 +1,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"; |