Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf: Add kfunc bpf_get_dentry_xattr() to read xattr from dentry

This kfunc can be used in LSM hooks with dentry, such as:

security_inode_listxattr
security_inode_permission

and many more.

Acked-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Song Liu <song@kernel.org>
Link: https://lore.kernel.org/r/20240806230904.71194-3-song@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Song Liu and committed by
Alexei Starovoitov
ac13a426 fa4e5afa

+40 -16
+40 -16
fs/bpf_fs_kfuncs.c
··· 94 94 } 95 95 96 96 /** 97 + * bpf_get_dentry_xattr - get xattr of a dentry 98 + * @dentry: dentry to get xattr from 99 + * @name__str: name of the xattr 100 + * @value_p: output buffer of the xattr value 101 + * 102 + * Get xattr *name__str* of *dentry* and store the output in *value_ptr*. 103 + * 104 + * For security reasons, only *name__str* with prefix "user." is allowed. 105 + * 106 + * Return: 0 on success, a negative value on error. 107 + */ 108 + __bpf_kfunc int bpf_get_dentry_xattr(struct dentry *dentry, const char *name__str, 109 + struct bpf_dynptr *value_p) 110 + { 111 + struct bpf_dynptr_kern *value_ptr = (struct bpf_dynptr_kern *)value_p; 112 + struct inode *inode = d_inode(dentry); 113 + u32 value_len; 114 + void *value; 115 + int ret; 116 + 117 + if (WARN_ON(!inode)) 118 + return -EINVAL; 119 + 120 + if (strncmp(name__str, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) 121 + return -EPERM; 122 + 123 + value_len = __bpf_dynptr_size(value_ptr); 124 + value = __bpf_dynptr_data_rw(value_ptr, value_len); 125 + if (!value) 126 + return -EINVAL; 127 + 128 + ret = inode_permission(&nop_mnt_idmap, inode, MAY_READ); 129 + if (ret) 130 + return ret; 131 + return __vfs_getxattr(dentry, inode, name__str, value, value_len); 132 + } 133 + 134 + /** 97 135 * bpf_get_file_xattr - get xattr of a file 98 136 * @file: file to get xattr from 99 137 * @name__str: name of the xattr ··· 146 108 __bpf_kfunc int bpf_get_file_xattr(struct file *file, const char *name__str, 147 109 struct bpf_dynptr *value_p) 148 110 { 149 - struct bpf_dynptr_kern *value_ptr = (struct bpf_dynptr_kern *)value_p; 150 111 struct dentry *dentry; 151 - u32 value_len; 152 - void *value; 153 - int ret; 154 - 155 - if (strncmp(name__str, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) 156 - return -EPERM; 157 - 158 - value_len = __bpf_dynptr_size(value_ptr); 159 - value = __bpf_dynptr_data_rw(value_ptr, value_len); 160 - if (!value) 161 - return -EINVAL; 162 112 163 113 dentry = file_dentry(file); 164 - ret = inode_permission(&nop_mnt_idmap, dentry->d_inode, MAY_READ); 165 - if (ret) 166 - return ret; 167 - return __vfs_getxattr(dentry, dentry->d_inode, name__str, value, value_len); 114 + return bpf_get_dentry_xattr(dentry, name__str, value_p); 168 115 } 169 116 170 117 __bpf_kfunc_end_defs(); ··· 159 136 KF_ACQUIRE | KF_TRUSTED_ARGS | KF_RET_NULL) 160 137 BTF_ID_FLAGS(func, bpf_put_file, KF_RELEASE) 161 138 BTF_ID_FLAGS(func, bpf_path_d_path, KF_TRUSTED_ARGS) 139 + BTF_ID_FLAGS(func, bpf_get_dentry_xattr, KF_SLEEPABLE | KF_TRUSTED_ARGS) 162 140 BTF_ID_FLAGS(func, bpf_get_file_xattr, KF_SLEEPABLE | KF_TRUSTED_ARGS) 163 141 BTF_KFUNCS_END(bpf_fs_kfunc_set_ids) 164 142