> From: Casey Schaufler [mailto:casey@xxxxxxxxxxxxxxxx] > Sent: Wednesday, April 6, 2022 12:48 AM > On 4/5/2022 6:11 AM, Roberto Sassu wrote: > > Introduce a new LSM to protect pinned objects in a bpf filesystem > > This is *not an LSM*. Do not call it an LSM. It is a set of > eBPF programs. We have all the opportunities for confusion > that we need. I suggested that you call this a BPF security > module (BSM) earlier today. You have any number of things > you can call this that won't be objectionable. > > > instance. This is useful for example to ensure that an LSM will always > > enforce its policy, even despite root tries to unload the corresponding > > eBPF program. > > How is this going to ensure that SELinux enforces its policy? I should have said above: that an LSM implemented with eBPF. Built-in LSMs are not affected by this change. Ok, next time I call it BSM. Thanks Roberto HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063 Managing Director: Li Peng, Zhong Ronghua > AppArmor has no eBPF program that corresponds to its policy, > neither does any other existing LSM, save BPF. Your claim is > nonsensical in the face of LSM behavior. > > > Achieve the protection by denying inode unlink and unmount of the > > protected bpf filesystem instance. Since protected inodes hold a > > reference of the link of loaded programs (e.g. LSM hooks), denying > > operations on them will prevent the ref count of the links from reaching > > zero, ensuring that the programs remain always active. > > > > Enable the protection only for the instance created by the user space > > counterpart of the LSM, and don't interfere with other instances, so > > that their behavior remains unchanged. > > > > Suggested-by: Djalal Harouni <tixxdz@xxxxxxxxx> > > Signed-off-by: Roberto Sassu <roberto.sassu@xxxxxxxxxx> > > --- > > .gitignore | 4 +++ > > Makefile | 18 ++++++++++++++ > > bpffs_lsm_kern.c | 63 > ++++++++++++++++++++++++++++++++++++++++++++++++ > > bpffs_lsm_user.c | 60 > +++++++++++++++++++++++++++++++++++++++++++++ > > 4 files changed, 145 insertions(+) > > create mode 100644 .gitignore > > create mode 100644 Makefile > > create mode 100644 bpffs_lsm_kern.c > > create mode 100644 bpffs_lsm_user.c > > > > diff --git a/.gitignore b/.gitignore > > new file mode 100644 > > index 000000000000..7fa02964f1dc > > --- /dev/null > > +++ b/.gitignore > > @@ -0,0 +1,4 @@ > > +*.o > > +vmlinux.h > > +bpffs_lsm_kern.skel.h > > +bpffs_lsm_user > > diff --git a/Makefile b/Makefile > > new file mode 100644 > > index 000000000000..c3d805759db3 > > --- /dev/null > > +++ b/Makefile > > @@ -0,0 +1,18 @@ > > +# SPDX-License-Identifier: GPL-2.0 > > +all: bpffs_lsm_user > > + > > +clean: > > + rm -rf bpffs_lsm.skel.h vmlinux.h bpffs_lsm_kern.o bpffs_lsm_user > > + > > +vmlinux.h: > > + /usr/sbin/bpftool btf dump file /sys/kernel/btf/vmlinux format c > \ > > + vmlinux.h > > + > > +bpffs_lsm_kern.skel.h: bpffs_lsm_kern.o > > + bpftool gen skeleton $< > $@ > > + > > +bpffs_lsm_kern.o: bpffs_lsm_kern.c vmlinux.h > > + clang -Wall -Werror -g -O2 -target bpf -c $< -o $@ > > + > > +bpffs_lsm_user: bpffs_lsm_user.c bpffs_lsm_kern.skel.h > bpffs_lsm_kern.o > > + cc -Wall -Werror -g -o $@ $< -lbpf > > diff --git a/bpffs_lsm_kern.c b/bpffs_lsm_kern.c > > new file mode 100644 > > index 000000000000..b3ccb2a75c95 > > --- /dev/null > > +++ b/bpffs_lsm_kern.c > > @@ -0,0 +1,63 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH > > + * > > + * Authors: > > + * Roberto Sassu <roberto.sassu@xxxxxxxxxx> > > + * > > + * Implement an LSM to protect a bpf filesystem instance. > > + */ > > + > > +#include "vmlinux.h" > > +#include <errno.h> > > +#include <bpf/bpf_helpers.h> > > +#include <bpf/bpf_tracing.h> > > +#include <bpf/bpf_core_read.h> > > + > > +char _license[] SEC("license") = "GPL"; > > + > > +uint32_t monitored_pid = 0; > > + > > +struct { > > + __uint(type, BPF_MAP_TYPE_INODE_STORAGE); > > + __uint(map_flags, BPF_F_NO_PREALLOC); > > + __type(key, int); > > + __type(value, sizeof(uint8_t)); > > +} inode_storage_map SEC(".maps"); > > + > > +SEC("lsm/sb_set_mnt_opts") > > +int BPF_PROG(sb_set_mnt_opts, struct super_block *sb, void > *mnt_opts, > > + unsigned long kern_flags, unsigned long *set_kern_flags) > > +{ > > + u32 pid; > > + > > + pid = bpf_get_current_pid_tgid() >> 32; > > + if (pid != monitored_pid) > > + return 0; > > + > > + if (!bpf_inode_storage_get(&inode_storage_map, sb->s_root- > >d_inode, 0, > > + BPF_LOCAL_STORAGE_GET_F_CREATE)) > > + return -EPERM; > > + > > + return 0; > > +} > > + > > +SEC("lsm/inode_unlink") > > +int BPF_PROG(inode_unlink, struct inode *dir, struct dentry *dentry) > > +{ > > + if (bpf_inode_storage_get(&inode_storage_map, > > + dir->i_sb->s_root->d_inode, 0, 0)) > > + return -EPERM; > > + > > + return 0; > > +} > > + > > +SEC("lsm/sb_umount") > > +int BPF_PROG(sb_umount, struct vfsmount *mnt, int flags) > > +{ > > + if (bpf_inode_storage_get(&inode_storage_map, > > + mnt->mnt_sb->s_root->d_inode, 0, 0)) > > + return -EPERM; > > + > > + return 0; > > +} > > diff --git a/bpffs_lsm_user.c b/bpffs_lsm_user.c > > new file mode 100644 > > index 000000000000..e20180cc5db9 > > --- /dev/null > > +++ b/bpffs_lsm_user.c > > @@ -0,0 +1,60 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH > > + * > > + * Author: Roberto Sassu <roberto.sassu@xxxxxxxxxx> > > + * > > + * Implement the user space side of the LSM for bpffs. > > + */ > > + > > +#include <fcntl.h> > > +#include <unistd.h> > > +#include <stdio.h> > > +#include <errno.h> > > +#include <stdlib.h> > > +#include <unistd.h> > > +#include <limits.h> > > +#include <sys/mount.h> > > +#include <sys/stat.h> > > + > > +#include "bpffs_lsm_kern.skel.h" > > + > > +#define MOUNT_FLAGS (MS_NOSUID | MS_NODEV | MS_NOEXEC | > MS_RELATIME) > > + > > +int main(int argc, char *argv[]) > > +{ > > + char mntpoint[] = "/tmp/bpf_private_mountXXXXXX"; > > + char path[PATH_MAX]; > > + struct bpffs_lsm_kern *skel; > > + int ret, i; > > + > > + skel = bpffs_lsm_kern__open_and_load(); > > + if (!skel) > > + return -EINVAL; > > + > > + ret = bpffs_lsm_kern__attach(skel); > > + if (ret < 0) > > + goto out_destroy; > > + > > + mkdtemp(mntpoint); > > + > > + skel->bss->monitored_pid = getpid(); > > + ret = mount(mntpoint, mntpoint, "bpf", MOUNT_FLAGS, NULL); > > + skel->bss->monitored_pid = 0; > > + > > + if (ret < 0) > > + goto out_destroy; > > + > > + for (i = 0; i < skel->skeleton->prog_cnt; i++) { > > + snprintf(path, sizeof(path), "%s/%s", mntpoint, > > + skel->skeleton->progs[i].name); > > + ret = bpf_link__pin(*skel->skeleton->progs[i].link, path); > > + if (ret < 0) > > + goto out_destroy; > > + } > > + > > + ret = 0; > > +out_destroy: > > + bpffs_lsm_kern__destroy(skel); > > + return ret; > > +}