summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorDaniel Borkmann <daniel@iogearbox.net>2026-06-02 09:40:12 +0200
committerChristian Brauner <brauner@kernel.org>2026-06-06 15:22:44 +0200
commit9722955b54307e9070994f2382ec06af3d7405e0 (patch)
treea599499f411dfa7cc47dcda733e04821a2a7fe86 /fs
parent6cccc49b027c7551ffc1d2532f2ef1922661f3da (diff)
bpf: Add simple xattr support to bpffs
Add support for extended attributes on bpffs inodes so that user space and BPF LSM programs can attach metadata, for example, a content hash or a security label - to a pinned object or directory. BPF LSM or user space tooling can then uniformly look at this (e.g. security.bpf.*) in similar way to other fs'es. The store is in-memory and non-persistent: it lives only for the lifetime of the mount, like everything else in bpffs. The modelling is similar to tmpfs. bpffs serves the trusted.* and security.* namespaces; user.* is left unsupported. As bpffs is FS_USERNS_MOUNT, security.* is reachable by the unprivileged mounter in a user namespace, and thus we are using the simple_xattr_set_limited infra there (trusted.* needs global CAP_SYS_ADMIN). bpf_fill_super() is open-coded instead of using simple_fill_super(), because the root inode must now be allocated through bpf_fs_alloc_inode() i.e. carry the bpf_fs_inode wrapper and come from the right cache - which requires s_op (and s_xattr) to be installed before the first inode is created. While at it, also harden s_iflags with SB_I_NOEXEC and SB_I_NODEV. bpf_fs_listxattr() is only reachable through the filesystem via i_op->listxattr, so the BPF token inode is left untouched. Name-based fsetxattr()/fgetxattr() on a token fd still work since the get/set handlers are installed at the superblock. For security.* namespace, we use simple_xattr_set_limited() but there was no simple_xattr_add_limited() API yet which was needed in bpf_fs_initxattrs() to avoid underflows in the accounting. The symlink target is freed in bpf_free_inode() rather than in bpf_destroy_inode() so that it is released only after an RCU grace period, as an RCU path walk following the symlink may still dereference inode->i_link in security_inode_follow_link(). Lastly, the bpf_symlink() allocated the symlink target is switched to GFP_KERNEL_ACCOUNT, so the string is charged to the caller's memcg. Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Link: https://patch.msgid.link/20260602074012.416289-1-daniel@iogearbox.net Cc: Christian Brauner <brauner@kernel.org> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/xattr.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/fs/xattr.c b/fs/xattr.c
index 89374cd9029a..ec2a4f3759d8 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -1679,6 +1679,39 @@ int simple_xattr_add(struct simple_xattr_cache *cache, struct list_head *xattrs,
}
/**
+ * simple_xattr_add_limited - add an xattr object, charging per-inode limits
+ * @cache: anchor for the hash table
+ * @xattrs: the header of the xattr object
+ * @limits: per-inode limit counters
+ * @new_xattr: the xattr object to add
+ *
+ * Like simple_xattr_add(), but also accounts @new_xattr against @limits so
+ * that a later removal or replacement of it through simple_xattr_set_limited()
+ * decrements counters that were actually incremented, rather than underflowing
+ * them. Use this instead of simple_xattr_add() when seeding initial xattrs
+ * that share a namespace with the limited set/remove path.
+ *
+ * Return: On success zero is returned. On failure a negative error code is
+ * returned.
+ */
+int simple_xattr_add_limited(struct simple_xattr_cache *cache,
+ struct list_head *xattrs,
+ struct simple_xattr_limits *limits,
+ struct simple_xattr *new_xattr)
+{
+ int err;
+
+ err = simple_xattr_limits_inc(limits, new_xattr->size);
+ if (err)
+ return err;
+
+ err = simple_xattr_add(cache, xattrs, new_xattr);
+ if (err)
+ simple_xattr_limits_dec(limits, new_xattr->size);
+ return err;
+}
+
+/**
* simple_xattrs_free - free xattrs
* @cache: anchor for the hash table
* @xattrs: xattr header whose xattrs to destroy