Skip to content

Commit 91d837c

Browse files
committed
pidfs: support xattrs on pidfds
Now that we have a way to persist information for pidfs dentries we can start supporting extended attributes on pidfds. This will allow userspace to attach meta information to tasks. One natural extension would be to introduce a custom pidfs.* extended attribute space and allow for the inheritance of extended attributes across fork() and exec(). The first simple scheme will allow privileged userspace to set trusted extended attributes on pidfs inodes. Link: https://lore.kernel.org/20250618-work-pidfs-persistent-v2-12-98f3456fd552@kernel.org Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent f769b3d commit 91d837c

1 file changed

Lines changed: 103 additions & 4 deletions

File tree

fs/pidfs.c

Lines changed: 103 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@
2121
#include <linux/utsname.h>
2222
#include <net/net_namespace.h>
2323
#include <linux/coredump.h>
24+
#include <linux/xattr.h>
2425

2526
#include "internal.h"
2627
#include "mount.h"
2728

2829
#define PIDFS_PID_DEAD ERR_PTR(-ESRCH)
2930

3031
static struct kmem_cache *pidfs_attr_cachep __ro_after_init;
32+
static struct kmem_cache *pidfs_xattr_cachep __ro_after_init;
3133

3234
/*
3335
* Stashes information that userspace needs to access even after the
@@ -40,6 +42,7 @@ struct pidfs_exit_info {
4042
};
4143

4244
struct pidfs_attr {
45+
struct simple_xattrs *xattrs;
4346
struct pidfs_exit_info __pei;
4447
struct pidfs_exit_info *exit_info;
4548
};
@@ -138,14 +141,27 @@ void pidfs_remove_pid(struct pid *pid)
138141

139142
void pidfs_free_pid(struct pid *pid)
140143
{
144+
struct pidfs_attr *attr __free(kfree) = no_free_ptr(pid->attr);
145+
struct simple_xattrs *xattrs __free(kfree) = NULL;
146+
141147
/*
142148
* Any dentry must've been wiped from the pid by now.
143149
* Otherwise there's a reference count bug.
144150
*/
145151
VFS_WARN_ON_ONCE(pid->stashed);
146152

147-
if (!IS_ERR(pid->attr))
148-
kfree(pid->attr);
153+
if (IS_ERR(attr))
154+
return;
155+
156+
/*
157+
* Any dentry must've been wiped from the pid by now. Otherwise
158+
* there's a reference count bug.
159+
*/
160+
VFS_WARN_ON_ONCE(pid->stashed);
161+
162+
xattrs = attr->xattrs;
163+
if (xattrs)
164+
simple_xattrs_free(attr->xattrs, NULL);
149165
}
150166

151167
#ifdef CONFIG_PROC_FS
@@ -663,9 +679,24 @@ static int pidfs_getattr(struct mnt_idmap *idmap, const struct path *path,
663679
return anon_inode_getattr(idmap, path, stat, request_mask, query_flags);
664680
}
665681

682+
static ssize_t pidfs_listxattr(struct dentry *dentry, char *buf, size_t size)
683+
{
684+
struct inode *inode = d_inode(dentry);
685+
struct pid *pid = inode->i_private;
686+
struct pidfs_attr *attr = pid->attr;
687+
struct simple_xattrs *xattrs;
688+
689+
xattrs = READ_ONCE(attr->xattrs);
690+
if (!xattrs)
691+
return 0;
692+
693+
return simple_xattr_list(inode, xattrs, buf, size);
694+
}
695+
666696
static const struct inode_operations pidfs_inode_operations = {
667-
.getattr = pidfs_getattr,
668-
.setattr = pidfs_setattr,
697+
.getattr = pidfs_getattr,
698+
.setattr = pidfs_setattr,
699+
.listxattr = pidfs_listxattr,
669700
};
670701

671702
static void pidfs_evict_inode(struct inode *inode)
@@ -905,6 +936,67 @@ static const struct stashed_operations pidfs_stashed_ops = {
905936
.put_data = pidfs_put_data,
906937
};
907938

939+
static int pidfs_xattr_get(const struct xattr_handler *handler,
940+
struct dentry *unused, struct inode *inode,
941+
const char *suffix, void *value, size_t size)
942+
{
943+
struct pid *pid = inode->i_private;
944+
struct pidfs_attr *attr = pid->attr;
945+
const char *name;
946+
struct simple_xattrs *xattrs;
947+
948+
xattrs = READ_ONCE(attr->xattrs);
949+
if (!xattrs)
950+
return 0;
951+
952+
name = xattr_full_name(handler, suffix);
953+
return simple_xattr_get(xattrs, name, value, size);
954+
}
955+
956+
static int pidfs_xattr_set(const struct xattr_handler *handler,
957+
struct mnt_idmap *idmap, struct dentry *unused,
958+
struct inode *inode, const char *suffix,
959+
const void *value, size_t size, int flags)
960+
{
961+
struct pid *pid = inode->i_private;
962+
struct pidfs_attr *attr = pid->attr;
963+
const char *name;
964+
struct simple_xattrs *xattrs;
965+
struct simple_xattr *old_xattr;
966+
967+
/* Ensure we're the only one to set @attr->xattrs. */
968+
WARN_ON_ONCE(!inode_is_locked(inode));
969+
970+
xattrs = READ_ONCE(attr->xattrs);
971+
if (!xattrs) {
972+
xattrs = kmem_cache_zalloc(pidfs_xattr_cachep, GFP_KERNEL);
973+
if (!xattrs)
974+
return -ENOMEM;
975+
976+
simple_xattrs_init(xattrs);
977+
smp_store_release(&pid->attr->xattrs, xattrs);
978+
}
979+
980+
name = xattr_full_name(handler, suffix);
981+
old_xattr = simple_xattr_set(xattrs, name, value, size, flags);
982+
if (IS_ERR(old_xattr))
983+
return PTR_ERR(old_xattr);
984+
985+
simple_xattr_free(old_xattr);
986+
return 0;
987+
}
988+
989+
static const struct xattr_handler pidfs_trusted_xattr_handler = {
990+
.prefix = XATTR_TRUSTED_PREFIX,
991+
.get = pidfs_xattr_get,
992+
.set = pidfs_xattr_set,
993+
};
994+
995+
static const struct xattr_handler *const pidfs_xattr_handlers[] = {
996+
&pidfs_trusted_xattr_handler,
997+
NULL
998+
};
999+
9081000
static int pidfs_init_fs_context(struct fs_context *fc)
9091001
{
9101002
struct pseudo_fs_context *ctx;
@@ -918,6 +1010,7 @@ static int pidfs_init_fs_context(struct fs_context *fc)
9181010
ctx->ops = &pidfs_sops;
9191011
ctx->eops = &pidfs_export_operations;
9201012
ctx->dops = &pidfs_dentry_operations;
1013+
ctx->xattr = pidfs_xattr_handlers;
9211014
fc->s_fs_info = (void *)&pidfs_stashed_ops;
9221015
return 0;
9231016
}
@@ -960,6 +1053,12 @@ void __init pidfs_init(void)
9601053
pidfs_attr_cachep = kmem_cache_create("pidfs_attr_cache", sizeof(struct pidfs_attr), 0,
9611054
(SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT |
9621055
SLAB_ACCOUNT | SLAB_PANIC), NULL);
1056+
1057+
pidfs_xattr_cachep = kmem_cache_create("pidfs_xattr_cache",
1058+
sizeof(struct simple_xattrs), 0,
1059+
(SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT |
1060+
SLAB_ACCOUNT | SLAB_PANIC), NULL);
1061+
9631062
pidfs_mnt = kern_mount(&pidfs_type);
9641063
if (IS_ERR(pidfs_mnt))
9651064
panic("Failed to mount pidfs pseudo filesystem");

0 commit comments

Comments
 (0)