1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ 3 4 #include "vmlinux.h" 5 #include <errno.h> 6 #include <bpf/bpf_tracing.h> 7 #include "bpf_kfuncs.h" 8 #include "bpf_misc.h" 9 10 char _license[] SEC("license") = "GPL"; 11 12 __u32 monitored_pid; 13 14 const char xattr_foo[] = "security.bpf.foo"; 15 const char xattr_bar[] = "security.bpf.bar"; 16 static const char xattr_selinux[] = "security.selinux"; 17 char value_bar[] = "world"; 18 char read_value[32]; 19 20 bool set_security_bpf_bar_success; 21 bool remove_security_bpf_bar_success; 22 bool set_security_selinux_fail; 23 bool remove_security_selinux_fail; 24 25 char name_buf[32]; 26 27 static inline bool name_match_foo(const char *name) 28 { 29 bpf_probe_read_kernel(name_buf, sizeof(name_buf), name); 30 31 return !bpf_strncmp(name_buf, sizeof(xattr_foo), xattr_foo); 32 } 33 34 /* Test bpf_set_dentry_xattr and bpf_remove_dentry_xattr */ 35 SEC("lsm.s/inode_getxattr") 36 int BPF_PROG(test_inode_getxattr, struct dentry *dentry, char *name) 37 { 38 struct bpf_dynptr value_ptr; 39 __u32 pid; 40 int ret; 41 42 pid = bpf_get_current_pid_tgid() >> 32; 43 if (pid != monitored_pid) 44 return 0; 45 46 /* Only do the following for security.bpf.foo */ 47 if (!name_match_foo(name)) 48 return 0; 49 50 bpf_dynptr_from_mem(read_value, sizeof(read_value), 0, &value_ptr); 51 52 /* read security.bpf.bar */ 53 ret = bpf_get_dentry_xattr(dentry, xattr_bar, &value_ptr); 54 55 if (ret < 0) { 56 /* If security.bpf.bar doesn't exist, set it */ 57 bpf_dynptr_from_mem(value_bar, sizeof(value_bar), 0, &value_ptr); 58 59 ret = bpf_set_dentry_xattr(dentry, xattr_bar, &value_ptr, 0); 60 if (!ret) 61 set_security_bpf_bar_success = true; 62 ret = bpf_set_dentry_xattr(dentry, xattr_selinux, &value_ptr, 0); 63 if (ret) 64 set_security_selinux_fail = true; 65 } else { 66 /* If security.bpf.bar exists, remove it */ 67 ret = bpf_remove_dentry_xattr(dentry, xattr_bar); 68 if (!ret) 69 remove_security_bpf_bar_success = true; 70 71 ret = bpf_remove_dentry_xattr(dentry, xattr_selinux); 72 if (ret) 73 remove_security_selinux_fail = true; 74 } 75 76 return 0; 77 } 78 79 bool locked_set_security_bpf_bar_success; 80 bool locked_remove_security_bpf_bar_success; 81 bool locked_set_security_selinux_fail; 82 bool locked_remove_security_selinux_fail; 83 84 /* Test bpf_set_dentry_xattr_locked and bpf_remove_dentry_xattr_locked. 85 * It not necessary to differentiate the _locked version and the 86 * not-_locked version in the BPF program. The verifier will fix them up 87 * properly. 88 */ 89 SEC("lsm.s/inode_setxattr") 90 int BPF_PROG(test_inode_setxattr, struct mnt_idmap *idmap, 91 struct dentry *dentry, const char *name, 92 const void *value, size_t size, int flags) 93 { 94 struct bpf_dynptr value_ptr; 95 __u32 pid; 96 int ret; 97 98 pid = bpf_get_current_pid_tgid() >> 32; 99 if (pid != monitored_pid) 100 return 0; 101 102 /* Only do the following for security.bpf.foo */ 103 if (!name_match_foo(name)) 104 return 0; 105 106 bpf_dynptr_from_mem(read_value, sizeof(read_value), 0, &value_ptr); 107 108 /* read security.bpf.bar */ 109 ret = bpf_get_dentry_xattr(dentry, xattr_bar, &value_ptr); 110 111 if (ret < 0) { 112 /* If security.bpf.bar doesn't exist, set it */ 113 bpf_dynptr_from_mem(value_bar, sizeof(value_bar), 0, &value_ptr); 114 115 ret = bpf_set_dentry_xattr(dentry, xattr_bar, &value_ptr, 0); 116 if (!ret) 117 locked_set_security_bpf_bar_success = true; 118 ret = bpf_set_dentry_xattr(dentry, xattr_selinux, &value_ptr, 0); 119 if (ret) 120 locked_set_security_selinux_fail = true; 121 } else { 122 /* If security.bpf.bar exists, remove it */ 123 ret = bpf_remove_dentry_xattr(dentry, xattr_bar); 124 if (!ret) 125 locked_remove_security_bpf_bar_success = true; 126 127 ret = bpf_remove_dentry_xattr(dentry, xattr_selinux); 128 if (ret) 129 locked_remove_security_selinux_fail = true; 130 } 131 132 return 0; 133 } 134