Re: [PATCH bpf-next 0/3] bpf: Add bpf_path_getattr()
From: Alexei Starovoitov
Date: Sat Oct 31 2026 - 20:57:12 EST
On Thu, Oct 29, 2026 at 02:59 AM Anastasios Papagiannis <tasos.papagiannnis@xxxxxxxxx> wrote:
> The kfunc returns a 64-byte bpf_file_stat. We avoid using struct kstat
> directly as this is an internal structure and this can lead to changing
> the user API. Inode and device identity follow the filesystem's getattr
kfuncs are not uapi. See "kfunc lifecycle expectations" in
Documentation/bpf/kfuncs.rst.
The prog reads struct kstat with CO-RE like any other kernel struct.
No need for bpf_file_stat.
> operation, and the device number uses stat(2) encoding. Mount IDs,
> mount-root attributes and ownership translation follow statx(), including
> mount idmapping and translation into the current task's user namespace.
bpf_path_d_path(), bpf_real_data_inode(), bpf_get_task_exe_file() are
thin wrappers of vfs functions.
Lets do the same with vfs_getattr_nosec().
like:
diff --git a/fs/bpf_fs_kfuncs.c b/fs/bpf_fs_kfuncs.c
--- a/fs/bpf_fs_kfuncs.c
+++ b/fs/bpf_fs_kfuncs.c
@@ -96,6 +96,37 @@ __bpf_kfunc int bpf_path_d_path(const struct path *path, char *buf, size_t buf__
return len;
}
+/**
+ * bpf_path_getattr - get the attributes of the supplied path
+ * @path: path to get the attributes of
+ * @request_mask: STATX_* flags of the attributes that the caller wants
+ * @query_flags: AT_STATX_SYNC_AS_STAT, AT_STATX_FORCE_SYNC or AT_STATX_DONT_SYNC
+ * @stat__uninit: buffer to return the attributes in
+ * @stat__sz: size of the supplied buffer
+ *
+ * Ask the filesystem for the attributes of *path*. This is vfs_getattr()
+ * without the call into security_inode_getattr().
+ *
+ * This BPF kfunc may only be called from sleepable BPF LSM programs.
+ *
+ * Return: 0 on success, a negative value on error.
+ */
+__bpf_kfunc int bpf_path_getattr(const struct path *path, u32 request_mask,
+ u32 query_flags, struct kstat *stat__uninit,
+ size_t stat__sz)
+{
+ struct kstat stat;
+ int ret;
+
+ ret = vfs_getattr_nosec(path, &stat, request_mask, query_flags);
+ if (ret)
+ return ret;
+
+ /* struct kstat in the prog's vmlinux.h can be smaller or larger */
+ memcpy(stat__uninit, &stat, min(stat__sz, sizeof(stat)));
+ return 0;
+}
+
static bool match_security_bpf_prefix(const char *name__str)
{
return !strncmp(name__str, XATTR_NAME_BPF_LSM, XATTR_NAME_BPF_LSM_LEN);
@@ -504,6 +535,7 @@ BTF_KFUNCS_START(bpf_fs_kfunc_set_ids)
BTF_ID_FLAGS(func, bpf_get_task_exe_file, KF_ACQUIRE | KF_RET_NULL)
BTF_ID_FLAGS(func, bpf_put_file, KF_RELEASE)
BTF_ID_FLAGS(func, bpf_path_d_path)
+BTF_ID_FLAGS(func, bpf_path_getattr, KF_SLEEPABLE)
BTF_ID_FLAGS(func, bpf_get_dentry_xattr, KF_SLEEPABLE)
BTF_ID_FLAGS(func, bpf_get_file_xattr, KF_SLEEPABLE)
BTF_ID_FLAGS(func, bpf_set_dentry_xattr, KF_SLEEPABLE)
@@ -515,8 +547,9 @@ BTF_ID_FLAGS(func, bpf_sock_read_xattr, KF_RCU)
#endif
BTF_KFUNCS_END(bpf_fs_kfunc_set_ids)
-/* Side-effecting kfuncs that stay exclusive to LSM programs. */
+/* Kfuncs that stay exclusive to LSM programs. */
BTF_SET_START(bpf_fs_kfunc_lsm_only_ids)
+BTF_ID(func, bpf_path_getattr)
BTF_ID(func, bpf_set_dentry_xattr)
BTF_ID(func, bpf_remove_dentry_xattr)
BTF_SET_END(bpf_fs_kfunc_lsm_only_ids)
pw-bot: cr