// SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ #include "vmlinux.h" #include #include #include "bpf_kfuncs.h" #include "bpf_misc.h" char _license[] SEC("license") = "GPL"; __u32 monitored_pid; const char xattr_foo[] = "security.bpf.foo"; const char xattr_bar[] = "security.bpf.bar"; static const char xattr_selinux[] = "security.selinux"; char value_bar[] = "world"; char read_value[32]; bool set_security_bpf_bar_success; bool remove_security_bpf_bar_success; bool set_security_selinux_fail; bool remove_security_selinux_fail; char name_buf[32]; static inline bool name_match_foo(const char *name) { bpf_probe_read_kernel(name_buf, sizeof(name_buf), name); return !bpf_strncmp(name_buf, sizeof(xattr_foo), xattr_foo); } /* Test bpf_set_dentry_xattr and bpf_remove_dentry_xattr */ SEC("lsm.s/inode_getxattr") int BPF_PROG(test_inode_getxattr, struct dentry *dentry, char *name) { struct bpf_dynptr value_ptr; __u32 pid; int ret; pid = bpf_get_current_pid_tgid() >> 32; if (pid != monitored_pid) return 0; /* Only do the following for security.bpf.foo */ if (!name_match_foo(name)) return 0; bpf_dynptr_from_mem(read_value, sizeof(read_value), 0, &value_ptr); /* read security.bpf.bar */ ret = bpf_get_dentry_xattr(dentry, xattr_bar, &value_ptr); if (ret < 0) { /* If security.bpf.bar doesn't exist, set it */ bpf_dynptr_from_mem(value_bar, sizeof(value_bar), 0, &value_ptr); ret = bpf_set_dentry_xattr(dentry, xattr_bar, &value_ptr, 0); if (!ret) set_security_bpf_bar_success = true; ret = bpf_set_dentry_xattr(dentry, xattr_selinux, &value_ptr, 0); if (ret) set_security_selinux_fail = true; } else { /* If security.bpf.bar exists, remove it */ ret = bpf_remove_dentry_xattr(dentry, xattr_bar); if (!ret) remove_security_bpf_bar_success = true; ret = bpf_remove_dentry_xattr(dentry, xattr_selinux); if (ret) remove_security_selinux_fail = true; } return 0; } bool locked_set_security_bpf_bar_success; bool locked_remove_security_bpf_bar_success; bool locked_set_security_selinux_fail; bool locked_remove_security_selinux_fail; /* Test bpf_set_dentry_xattr_locked and bpf_remove_dentry_xattr_locked. * It not necessary to differentiate the _locked version and the * not-_locked version in the BPF program. The verifier will fix them up * properly. */ SEC("lsm.s/inode_setxattr") int BPF_PROG(test_inode_setxattr, struct mnt_idmap *idmap, struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { struct bpf_dynptr value_ptr; __u32 pid; int ret; pid = bpf_get_current_pid_tgid() >> 32; if (pid != monitored_pid) return 0; /* Only do the following for security.bpf.foo */ if (!name_match_foo(name)) return 0; bpf_dynptr_from_mem(read_value, sizeof(read_value), 0, &value_ptr); /* read security.bpf.bar */ ret = bpf_get_dentry_xattr(dentry, xattr_bar, &value_ptr); if (ret < 0) { /* If security.bpf.bar doesn't exist, set it */ bpf_dynptr_from_mem(value_bar, sizeof(value_bar), 0, &value_ptr); ret = bpf_set_dentry_xattr(dentry, xattr_bar, &value_ptr, 0); if (!ret) locked_set_security_bpf_bar_success = true; ret = bpf_set_dentry_xattr(dentry, xattr_selinux, &value_ptr, 0); if (ret) locked_set_security_selinux_fail = true; } else { /* If security.bpf.bar exists, remove it */ ret = bpf_remove_dentry_xattr(dentry, xattr_bar); if (!ret) locked_remove_security_bpf_bar_success = true; ret = bpf_remove_dentry_xattr(dentry, xattr_selinux); if (ret) locked_remove_security_selinux_fail = true; } return 0; }