* [PATCH RFC 1/7] libfs: prepare to allow for non-immutable pidfd inodes
2025-06-17 15:45 [PATCH RFC 0/7] pidfs: support extended attributes Christian Brauner
@ 2025-06-17 15:45 ` Christian Brauner
2025-06-18 19:44 ` Alexander Mikhalitsyn
2025-06-17 15:45 ` [PATCH RFC 2/7] pidfs: make inodes mutable Christian Brauner
` (5 subsequent siblings)
6 siblings, 1 reply; 12+ messages in thread
From: Christian Brauner @ 2025-06-17 15:45 UTC (permalink / raw)
To: linux-fsdevel
Cc: Jann Horn, Josef Bacik, Jeff Layton, Daan De Meyer,
Lennart Poettering, Mike Yuan, Zbigniew Jędrzejewski-Szmek,
Christian Brauner, Alexander Mikhalitsyn
Allow for S_IMMUTABLE to be stripped so that we can support xattrs on
pidfds.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/libfs.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/fs/libfs.c b/fs/libfs.c
index f496373869fb..9098dc6b26f9 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -2162,7 +2162,6 @@ static struct dentry *prepare_anon_dentry(struct dentry **stashed,
/* Notice when this is changed. */
WARN_ON_ONCE(!S_ISREG(inode->i_mode));
- WARN_ON_ONCE(!IS_IMMUTABLE(inode));
dentry = d_alloc_anon(sb);
if (!dentry) {
--
2.47.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH RFC 1/7] libfs: prepare to allow for non-immutable pidfd inodes
2025-06-17 15:45 ` [PATCH RFC 1/7] libfs: prepare to allow for non-immutable pidfd inodes Christian Brauner
@ 2025-06-18 19:44 ` Alexander Mikhalitsyn
0 siblings, 0 replies; 12+ messages in thread
From: Alexander Mikhalitsyn @ 2025-06-18 19:44 UTC (permalink / raw)
To: Christian Brauner
Cc: linux-fsdevel, Jann Horn, Josef Bacik, Jeff Layton, Daan De Meyer,
Lennart Poettering, Mike Yuan, Zbigniew Jędrzejewski-Szmek
Am Di., 17. Juni 2025 um 17:45 Uhr schrieb Christian Brauner
<brauner@kernel.org>:
>
> Allow for S_IMMUTABLE to be stripped so that we can support xattrs on
> pidfds.
>
> Signed-off-by: Christian Brauner <brauner@kernel.org>
Reviewed-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
> ---
> fs/libfs.c | 1 -
> 1 file changed, 1 deletion(-)
>
> diff --git a/fs/libfs.c b/fs/libfs.c
> index f496373869fb..9098dc6b26f9 100644
> --- a/fs/libfs.c
> +++ b/fs/libfs.c
> @@ -2162,7 +2162,6 @@ static struct dentry *prepare_anon_dentry(struct dentry **stashed,
>
> /* Notice when this is changed. */
> WARN_ON_ONCE(!S_ISREG(inode->i_mode));
> - WARN_ON_ONCE(!IS_IMMUTABLE(inode));
>
> dentry = d_alloc_anon(sb);
> if (!dentry) {
>
> --
> 2.47.2
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH RFC 2/7] pidfs: make inodes mutable
2025-06-17 15:45 [PATCH RFC 0/7] pidfs: support extended attributes Christian Brauner
2025-06-17 15:45 ` [PATCH RFC 1/7] libfs: prepare to allow for non-immutable pidfd inodes Christian Brauner
@ 2025-06-17 15:45 ` Christian Brauner
2025-06-18 19:43 ` Alexander Mikhalitsyn
2025-06-17 15:45 ` [PATCH RFC 3/7] pidfs: raise SB_I_NODEV and SB_I_NOEXEC Christian Brauner
` (4 subsequent siblings)
6 siblings, 1 reply; 12+ messages in thread
From: Christian Brauner @ 2025-06-17 15:45 UTC (permalink / raw)
To: linux-fsdevel
Cc: Jann Horn, Josef Bacik, Jeff Layton, Daan De Meyer,
Lennart Poettering, Mike Yuan, Zbigniew Jędrzejewski-Szmek,
Christian Brauner, Alexander Mikhalitsyn
Prepare for allowing extended attributes to be set on pidfd inodes by
allowing them to be mutable.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/pidfs.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/fs/pidfs.c b/fs/pidfs.c
index 9373d03fd263..ca217bfe6e40 100644
--- a/fs/pidfs.c
+++ b/fs/pidfs.c
@@ -892,6 +892,8 @@ static int pidfs_init_inode(struct inode *inode, void *data)
inode->i_private = data;
inode->i_flags |= S_PRIVATE | S_ANON_INODE;
+ /* We allow to set xattrs. */
+ inode->i_flags &= ~S_IMMUTABLE;
inode->i_mode |= S_IRWXU;
inode->i_op = &pidfs_inode_operations;
inode->i_fop = &pidfs_file_operations;
--
2.47.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH RFC 2/7] pidfs: make inodes mutable
2025-06-17 15:45 ` [PATCH RFC 2/7] pidfs: make inodes mutable Christian Brauner
@ 2025-06-18 19:43 ` Alexander Mikhalitsyn
0 siblings, 0 replies; 12+ messages in thread
From: Alexander Mikhalitsyn @ 2025-06-18 19:43 UTC (permalink / raw)
To: Christian Brauner
Cc: linux-fsdevel, Jann Horn, Josef Bacik, Jeff Layton, Daan De Meyer,
Lennart Poettering, Mike Yuan, Zbigniew Jędrzejewski-Szmek
Am Di., 17. Juni 2025 um 17:45 Uhr schrieb Christian Brauner
<brauner@kernel.org>:
>
> Prepare for allowing extended attributes to be set on pidfd inodes by
> allowing them to be mutable.
>
> Signed-off-by: Christian Brauner <brauner@kernel.org>
Reviewed-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
> ---
> fs/pidfs.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/fs/pidfs.c b/fs/pidfs.c
> index 9373d03fd263..ca217bfe6e40 100644
> --- a/fs/pidfs.c
> +++ b/fs/pidfs.c
> @@ -892,6 +892,8 @@ static int pidfs_init_inode(struct inode *inode, void *data)
>
> inode->i_private = data;
> inode->i_flags |= S_PRIVATE | S_ANON_INODE;
> + /* We allow to set xattrs. */
> + inode->i_flags &= ~S_IMMUTABLE;
> inode->i_mode |= S_IRWXU;
> inode->i_op = &pidfs_inode_operations;
> inode->i_fop = &pidfs_file_operations;
>
> --
> 2.47.2
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH RFC 3/7] pidfs: raise SB_I_NODEV and SB_I_NOEXEC
2025-06-17 15:45 [PATCH RFC 0/7] pidfs: support extended attributes Christian Brauner
2025-06-17 15:45 ` [PATCH RFC 1/7] libfs: prepare to allow for non-immutable pidfd inodes Christian Brauner
2025-06-17 15:45 ` [PATCH RFC 2/7] pidfs: make inodes mutable Christian Brauner
@ 2025-06-17 15:45 ` Christian Brauner
2025-06-18 19:46 ` Alexander Mikhalitsyn
2025-06-17 15:45 ` [PATCH RFC 4/7] pidfs: support xattrs on pidfds Christian Brauner
` (3 subsequent siblings)
6 siblings, 1 reply; 12+ messages in thread
From: Christian Brauner @ 2025-06-17 15:45 UTC (permalink / raw)
To: linux-fsdevel
Cc: Jann Horn, Josef Bacik, Jeff Layton, Daan De Meyer,
Lennart Poettering, Mike Yuan, Zbigniew Jędrzejewski-Szmek,
Christian Brauner, Alexander Mikhalitsyn
Similar to commit 1ed95281c0c7 ("anon_inode: raise SB_I_NODEV and SB_I_NOEXEC"):
it shouldn't be possible to execute pidfds via
execveat(fd_anon_inode, "", NULL, NULL, AT_EMPTY_PATH)
so raise SB_I_NOEXEC so that no one gets any creative ideas.
Also raise SB_I_NODEV as we don't expect or support any devices on pidfs.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/pidfs.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/fs/pidfs.c b/fs/pidfs.c
index ca217bfe6e40..1343bfc60e3f 100644
--- a/fs/pidfs.c
+++ b/fs/pidfs.c
@@ -959,6 +959,8 @@ static int pidfs_init_fs_context(struct fs_context *fc)
if (!ctx)
return -ENOMEM;
+ fc->s_iflags |= SB_I_NOEXEC;
+ fc->s_iflags |= SB_I_NODEV;
ctx->ops = &pidfs_sops;
ctx->eops = &pidfs_export_operations;
ctx->dops = &pidfs_dentry_operations;
--
2.47.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH RFC 3/7] pidfs: raise SB_I_NODEV and SB_I_NOEXEC
2025-06-17 15:45 ` [PATCH RFC 3/7] pidfs: raise SB_I_NODEV and SB_I_NOEXEC Christian Brauner
@ 2025-06-18 19:46 ` Alexander Mikhalitsyn
0 siblings, 0 replies; 12+ messages in thread
From: Alexander Mikhalitsyn @ 2025-06-18 19:46 UTC (permalink / raw)
To: Christian Brauner
Cc: linux-fsdevel, Jann Horn, Josef Bacik, Jeff Layton, Daan De Meyer,
Lennart Poettering, Mike Yuan, Zbigniew Jędrzejewski-Szmek
Am Di., 17. Juni 2025 um 17:45 Uhr schrieb Christian Brauner
<brauner@kernel.org>:
>
> Similar to commit 1ed95281c0c7 ("anon_inode: raise SB_I_NODEV and SB_I_NOEXEC"):
> it shouldn't be possible to execute pidfds via
> execveat(fd_anon_inode, "", NULL, NULL, AT_EMPTY_PATH)
> so raise SB_I_NOEXEC so that no one gets any creative ideas.
>
> Also raise SB_I_NODEV as we don't expect or support any devices on pidfs.
>
> Signed-off-by: Christian Brauner <brauner@kernel.org>
Reviewed-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
> ---
> fs/pidfs.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/fs/pidfs.c b/fs/pidfs.c
> index ca217bfe6e40..1343bfc60e3f 100644
> --- a/fs/pidfs.c
> +++ b/fs/pidfs.c
> @@ -959,6 +959,8 @@ static int pidfs_init_fs_context(struct fs_context *fc)
> if (!ctx)
> return -ENOMEM;
>
> + fc->s_iflags |= SB_I_NOEXEC;
> + fc->s_iflags |= SB_I_NODEV;
> ctx->ops = &pidfs_sops;
> ctx->eops = &pidfs_export_operations;
> ctx->dops = &pidfs_dentry_operations;
>
> --
> 2.47.2
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH RFC 4/7] pidfs: support xattrs on pidfds
2025-06-17 15:45 [PATCH RFC 0/7] pidfs: support extended attributes Christian Brauner
` (2 preceding siblings ...)
2025-06-17 15:45 ` [PATCH RFC 3/7] pidfs: raise SB_I_NODEV and SB_I_NOEXEC Christian Brauner
@ 2025-06-17 15:45 ` Christian Brauner
2025-06-18 19:54 ` Alexander Mikhalitsyn
2025-06-17 15:45 ` [PATCH RFC 5/7] selftests/pidfd: test extended attribute support Christian Brauner
` (2 subsequent siblings)
6 siblings, 1 reply; 12+ messages in thread
From: Christian Brauner @ 2025-06-17 15:45 UTC (permalink / raw)
To: linux-fsdevel
Cc: Jann Horn, Josef Bacik, Jeff Layton, Daan De Meyer,
Lennart Poettering, Mike Yuan, Zbigniew Jędrzejewski-Szmek,
Christian Brauner, Alexander Mikhalitsyn
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/pidfs.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 92 insertions(+), 2 deletions(-)
diff --git a/fs/pidfs.c b/fs/pidfs.c
index 1343bfc60e3f..b1968f628417 100644
--- a/fs/pidfs.c
+++ b/fs/pidfs.c
@@ -21,6 +21,7 @@
#include <linux/utsname.h>
#include <net/net_namespace.h>
#include <linux/coredump.h>
+#include <linux/xattr.h>
#include "internal.h"
#include "mount.h"
@@ -40,6 +41,7 @@
#define PIDFS_PID_DEAD ERR_PTR(-ESRCH)
static struct kmem_cache *pidfs_cachep __ro_after_init;
+static struct kmem_cache *pidfs_attrs_cachep __ro_after_init;
/*
* Stashes information that userspace needs to access even after the
@@ -51,9 +53,14 @@ struct pidfs_exit_info {
__u32 coredump_mask;
};
+struct pidfs_attrs {
+ struct simple_xattrs xattrs;
+};
+
struct pidfs_inode {
struct pidfs_exit_info __pei;
struct pidfs_exit_info *exit_info;
+ struct pidfs_attrs *attrs;
struct inode vfs_inode;
};
@@ -672,15 +679,34 @@ static int pidfs_getattr(struct mnt_idmap *idmap, const struct path *path,
return anon_inode_getattr(idmap, path, stat, request_mask, query_flags);
}
+static ssize_t pidfs_listxattr(struct dentry *dentry, char *buf, size_t size)
+{
+ struct inode *inode = d_inode(dentry);
+ struct pidfs_attrs *attrs;
+
+ attrs = READ_ONCE(pidfs_i(inode)->attrs);
+ if (!attrs)
+ return -ENODATA;
+
+ return simple_xattr_list(inode, &attrs->xattrs, buf, size);
+}
+
static const struct inode_operations pidfs_inode_operations = {
- .getattr = pidfs_getattr,
- .setattr = pidfs_setattr,
+ .getattr = pidfs_getattr,
+ .setattr = pidfs_setattr,
+ .listxattr = pidfs_listxattr,
};
static void pidfs_evict_inode(struct inode *inode)
{
struct pid *pid = inode->i_private;
+ struct pidfs_attrs *attrs;
+ attrs = READ_ONCE(pidfs_i(inode)->attrs);
+ if (attrs) {
+ simple_xattrs_free(&attrs->xattrs, NULL);
+ kmem_cache_free(pidfs_attrs_cachep, attrs);
+ }
clear_inode(inode);
put_pid(pid);
}
@@ -695,6 +721,7 @@ static struct inode *pidfs_alloc_inode(struct super_block *sb)
memset(&pi->__pei, 0, sizeof(pi->__pei));
pi->exit_info = NULL;
+ pi->attrs = NULL;
return &pi->vfs_inode;
}
@@ -951,6 +978,63 @@ static const struct stashed_operations pidfs_stashed_ops = {
.put_data = pidfs_put_data,
};
+static int pidfs_xattr_get(const struct xattr_handler *handler,
+ struct dentry *unused, struct inode *inode,
+ const char *suffix, void *value, size_t size)
+{
+ const char *name;
+ struct pidfs_attrs *attrs;
+
+ attrs = READ_ONCE(pidfs_i(inode)->attrs);
+ if (!attrs)
+ return -ENODATA;
+
+ name = xattr_full_name(handler, suffix);
+ return simple_xattr_get(&attrs->xattrs, name, value, size);
+}
+
+static int pidfs_xattr_set(const struct xattr_handler *handler,
+ struct mnt_idmap *idmap, struct dentry *unused,
+ struct inode *inode, const char *suffix,
+ const void *value, size_t size, int flags)
+{
+ const char *name;
+ struct pidfs_attrs *attrs;
+ struct simple_xattr *old_xattr;
+
+ /* Make sure we're the only one here. */
+ WARN_ON_ONCE(!inode_is_locked(inode));
+
+ attrs = READ_ONCE(pidfs_i(inode)->attrs);
+ if (!attrs) {
+ attrs = kmem_cache_zalloc(pidfs_attrs_cachep, GFP_KERNEL);
+ if (!attrs)
+ return -ENOMEM;
+
+ simple_xattrs_init(&attrs->xattrs);
+ smp_store_release(&pidfs_i(inode)->attrs, attrs);
+ }
+
+ name = xattr_full_name(handler, suffix);
+ old_xattr = simple_xattr_set(&attrs->xattrs, name, value, size, flags);
+ if (IS_ERR(old_xattr))
+ return PTR_ERR(old_xattr);
+
+ simple_xattr_free(old_xattr);
+ return 0;
+}
+
+static const struct xattr_handler pidfs_trusted_xattr_handler = {
+ .prefix = XATTR_TRUSTED_PREFIX,
+ .get = pidfs_xattr_get,
+ .set = pidfs_xattr_set,
+};
+
+static const struct xattr_handler *const pidfs_xattr_handlers[] = {
+ &pidfs_trusted_xattr_handler,
+ NULL
+};
+
static int pidfs_init_fs_context(struct fs_context *fc)
{
struct pseudo_fs_context *ctx;
@@ -964,6 +1048,7 @@ static int pidfs_init_fs_context(struct fs_context *fc)
ctx->ops = &pidfs_sops;
ctx->eops = &pidfs_export_operations;
ctx->dops = &pidfs_dentry_operations;
+ ctx->xattr = pidfs_xattr_handlers;
fc->s_fs_info = (void *)&pidfs_stashed_ops;
return 0;
}
@@ -1073,6 +1158,11 @@ void __init pidfs_init(void)
(SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT |
SLAB_ACCOUNT | SLAB_PANIC),
pidfs_inode_init_once);
+
+ pidfs_attrs_cachep = kmem_cache_create("pidfs_attrs_cache",
+ sizeof(struct pidfs_attrs), 0,
+ SLAB_PANIC, NULL);
+
pidfs_mnt = kern_mount(&pidfs_type);
if (IS_ERR(pidfs_mnt))
panic("Failed to mount pidfs pseudo filesystem");
--
2.47.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH RFC 4/7] pidfs: support xattrs on pidfds
2025-06-17 15:45 ` [PATCH RFC 4/7] pidfs: support xattrs on pidfds Christian Brauner
@ 2025-06-18 19:54 ` Alexander Mikhalitsyn
0 siblings, 0 replies; 12+ messages in thread
From: Alexander Mikhalitsyn @ 2025-06-18 19:54 UTC (permalink / raw)
To: Christian Brauner
Cc: linux-fsdevel, Jann Horn, Josef Bacik, Jeff Layton, Daan De Meyer,
Lennart Poettering, Mike Yuan, Zbigniew Jędrzejewski-Szmek
Am Di., 17. Juni 2025 um 17:45 Uhr schrieb Christian Brauner
<brauner@kernel.org>:
>
> Signed-off-by: Christian Brauner <brauner@kernel.org>
Reviewed-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
> ---
> fs/pidfs.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 92 insertions(+), 2 deletions(-)
>
> diff --git a/fs/pidfs.c b/fs/pidfs.c
> index 1343bfc60e3f..b1968f628417 100644
> --- a/fs/pidfs.c
> +++ b/fs/pidfs.c
> @@ -21,6 +21,7 @@
> #include <linux/utsname.h>
> #include <net/net_namespace.h>
> #include <linux/coredump.h>
> +#include <linux/xattr.h>
>
> #include "internal.h"
> #include "mount.h"
> @@ -40,6 +41,7 @@
> #define PIDFS_PID_DEAD ERR_PTR(-ESRCH)
>
> static struct kmem_cache *pidfs_cachep __ro_after_init;
> +static struct kmem_cache *pidfs_attrs_cachep __ro_after_init;
>
> /*
> * Stashes information that userspace needs to access even after the
> @@ -51,9 +53,14 @@ struct pidfs_exit_info {
> __u32 coredump_mask;
> };
>
> +struct pidfs_attrs {
> + struct simple_xattrs xattrs;
> +};
> +
> struct pidfs_inode {
> struct pidfs_exit_info __pei;
> struct pidfs_exit_info *exit_info;
> + struct pidfs_attrs *attrs;
> struct inode vfs_inode;
> };
>
> @@ -672,15 +679,34 @@ static int pidfs_getattr(struct mnt_idmap *idmap, const struct path *path,
> return anon_inode_getattr(idmap, path, stat, request_mask, query_flags);
> }
>
> +static ssize_t pidfs_listxattr(struct dentry *dentry, char *buf, size_t size)
> +{
> + struct inode *inode = d_inode(dentry);
> + struct pidfs_attrs *attrs;
> +
> + attrs = READ_ONCE(pidfs_i(inode)->attrs);
> + if (!attrs)
> + return -ENODATA;
> +
> + return simple_xattr_list(inode, &attrs->xattrs, buf, size);
> +}
> +
> static const struct inode_operations pidfs_inode_operations = {
> - .getattr = pidfs_getattr,
> - .setattr = pidfs_setattr,
> + .getattr = pidfs_getattr,
> + .setattr = pidfs_setattr,
> + .listxattr = pidfs_listxattr,
> };
>
> static void pidfs_evict_inode(struct inode *inode)
> {
> struct pid *pid = inode->i_private;
> + struct pidfs_attrs *attrs;
>
> + attrs = READ_ONCE(pidfs_i(inode)->attrs);
> + if (attrs) {
> + simple_xattrs_free(&attrs->xattrs, NULL);
> + kmem_cache_free(pidfs_attrs_cachep, attrs);
> + }
> clear_inode(inode);
> put_pid(pid);
> }
> @@ -695,6 +721,7 @@ static struct inode *pidfs_alloc_inode(struct super_block *sb)
>
> memset(&pi->__pei, 0, sizeof(pi->__pei));
> pi->exit_info = NULL;
> + pi->attrs = NULL;
>
> return &pi->vfs_inode;
> }
> @@ -951,6 +978,63 @@ static const struct stashed_operations pidfs_stashed_ops = {
> .put_data = pidfs_put_data,
> };
>
> +static int pidfs_xattr_get(const struct xattr_handler *handler,
> + struct dentry *unused, struct inode *inode,
> + const char *suffix, void *value, size_t size)
> +{
> + const char *name;
> + struct pidfs_attrs *attrs;
> +
> + attrs = READ_ONCE(pidfs_i(inode)->attrs);
> + if (!attrs)
> + return -ENODATA;
> +
> + name = xattr_full_name(handler, suffix);
> + return simple_xattr_get(&attrs->xattrs, name, value, size);
> +}
> +
> +static int pidfs_xattr_set(const struct xattr_handler *handler,
> + struct mnt_idmap *idmap, struct dentry *unused,
> + struct inode *inode, const char *suffix,
> + const void *value, size_t size, int flags)
> +{
> + const char *name;
> + struct pidfs_attrs *attrs;
> + struct simple_xattr *old_xattr;
> +
> + /* Make sure we're the only one here. */
> + WARN_ON_ONCE(!inode_is_locked(inode));
> +
> + attrs = READ_ONCE(pidfs_i(inode)->attrs);
> + if (!attrs) {
> + attrs = kmem_cache_zalloc(pidfs_attrs_cachep, GFP_KERNEL);
> + if (!attrs)
> + return -ENOMEM;
> +
> + simple_xattrs_init(&attrs->xattrs);
> + smp_store_release(&pidfs_i(inode)->attrs, attrs);
> + }
> +
> + name = xattr_full_name(handler, suffix);
> + old_xattr = simple_xattr_set(&attrs->xattrs, name, value, size, flags);
> + if (IS_ERR(old_xattr))
> + return PTR_ERR(old_xattr);
> +
> + simple_xattr_free(old_xattr);
> + return 0;
> +}
> +
> +static const struct xattr_handler pidfs_trusted_xattr_handler = {
> + .prefix = XATTR_TRUSTED_PREFIX,
> + .get = pidfs_xattr_get,
> + .set = pidfs_xattr_set,
> +};
> +
> +static const struct xattr_handler *const pidfs_xattr_handlers[] = {
> + &pidfs_trusted_xattr_handler,
> + NULL
> +};
> +
> static int pidfs_init_fs_context(struct fs_context *fc)
> {
> struct pseudo_fs_context *ctx;
> @@ -964,6 +1048,7 @@ static int pidfs_init_fs_context(struct fs_context *fc)
> ctx->ops = &pidfs_sops;
> ctx->eops = &pidfs_export_operations;
> ctx->dops = &pidfs_dentry_operations;
> + ctx->xattr = pidfs_xattr_handlers;
> fc->s_fs_info = (void *)&pidfs_stashed_ops;
> return 0;
> }
> @@ -1073,6 +1158,11 @@ void __init pidfs_init(void)
> (SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT |
> SLAB_ACCOUNT | SLAB_PANIC),
> pidfs_inode_init_once);
> +
> + pidfs_attrs_cachep = kmem_cache_create("pidfs_attrs_cache",
> + sizeof(struct pidfs_attrs), 0,
> + SLAB_PANIC, NULL);
nit: WDYT about adding SLAB_ACCOUNT too?
> +
> pidfs_mnt = kern_mount(&pidfs_type);
> if (IS_ERR(pidfs_mnt))
> panic("Failed to mount pidfs pseudo filesystem");
>
> --
> 2.47.2
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH RFC 5/7] selftests/pidfd: test extended attribute support
2025-06-17 15:45 [PATCH RFC 0/7] pidfs: support extended attributes Christian Brauner
` (3 preceding siblings ...)
2025-06-17 15:45 ` [PATCH RFC 4/7] pidfs: support xattrs on pidfds Christian Brauner
@ 2025-06-17 15:45 ` Christian Brauner
2025-06-17 15:45 ` [PATCH RFC 6/7] " Christian Brauner
2025-06-17 15:45 ` [PATCH RFC 7/7] selftests/pidfd: test setattr support Christian Brauner
6 siblings, 0 replies; 12+ messages in thread
From: Christian Brauner @ 2025-06-17 15:45 UTC (permalink / raw)
To: linux-fsdevel
Cc: Jann Horn, Josef Bacik, Jeff Layton, Daan De Meyer,
Lennart Poettering, Mike Yuan, Zbigniew Jędrzejewski-Szmek,
Christian Brauner, Alexander Mikhalitsyn
Add tests for extended attribute support on pidfds.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
tools/testing/selftests/pidfd/.gitignore | 1 +
tools/testing/selftests/pidfd/Makefile | 3 +-
tools/testing/selftests/pidfd/pidfd_xattr_test.c | 97 ++++++++++++++++++++++++
3 files changed, 100 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/pidfd/.gitignore b/tools/testing/selftests/pidfd/.gitignore
index 0406a065deb4..bc4130506eda 100644
--- a/tools/testing/selftests/pidfd/.gitignore
+++ b/tools/testing/selftests/pidfd/.gitignore
@@ -10,3 +10,4 @@ pidfd_file_handle_test
pidfd_bind_mount
pidfd_info_test
pidfd_exec_helper
+pidfd_xattr_test
diff --git a/tools/testing/selftests/pidfd/Makefile b/tools/testing/selftests/pidfd/Makefile
index fcbefc0d77f6..c9fd5023ef15 100644
--- a/tools/testing/selftests/pidfd/Makefile
+++ b/tools/testing/selftests/pidfd/Makefile
@@ -3,7 +3,8 @@ CFLAGS += -g $(KHDR_INCLUDES) -pthread -Wall
TEST_GEN_PROGS := pidfd_test pidfd_fdinfo_test pidfd_open_test \
pidfd_poll_test pidfd_wait pidfd_getfd_test pidfd_setns_test \
- pidfd_file_handle_test pidfd_bind_mount pidfd_info_test
+ pidfd_file_handle_test pidfd_bind_mount pidfd_info_test \
+ pidfd_xattr_test
TEST_GEN_PROGS_EXTENDED := pidfd_exec_helper
diff --git a/tools/testing/selftests/pidfd/pidfd_xattr_test.c b/tools/testing/selftests/pidfd/pidfd_xattr_test.c
new file mode 100644
index 000000000000..00d400ac515b
--- /dev/null
+++ b/tools/testing/selftests/pidfd/pidfd_xattr_test.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <linux/types.h>
+#include <poll.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syscall.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <linux/kcmp.h>
+#include <sys/stat.h>
+#include <sys/xattr.h>
+
+#include "pidfd.h"
+#include "../kselftest_harness.h"
+
+FIXTURE(pidfs_xattr)
+{
+ pid_t child_pid;
+ int child_pidfd;
+};
+
+FIXTURE_SETUP(pidfs_xattr)
+{
+ self->child_pid = create_child(&self->child_pidfd, CLONE_NEWUSER | CLONE_NEWPID);
+ EXPECT_GE(self->child_pid, 0);
+
+ if (self->child_pid == 0)
+ _exit(EXIT_SUCCESS);
+}
+
+FIXTURE_TEARDOWN(pidfs_xattr)
+{
+ sys_waitid(P_PID, self->child_pid, NULL, WEXITED);
+}
+
+TEST_F(pidfs_xattr, set_get_list_xattr_multiple)
+{
+ int ret, i;
+ char xattr_name[32];
+ char xattr_value[32];
+ char buf[32];
+ const int num_xattrs = 10;
+ char list[PATH_MAX] = {};
+
+ for (i = 0; i < num_xattrs; i++) {
+ snprintf(xattr_name, sizeof(xattr_name), "trusted.testattr%d", i);
+ snprintf(xattr_value, sizeof(xattr_value), "testvalue%d", i);
+ ret = fsetxattr(self->child_pidfd, xattr_name, xattr_value, strlen(xattr_value), 0);
+ ASSERT_EQ(ret, 0);
+ }
+
+ for (i = 0; i < num_xattrs; i++) {
+ snprintf(xattr_name, sizeof(xattr_name), "trusted.testattr%d", i);
+ snprintf(xattr_value, sizeof(xattr_value), "testvalue%d", i);
+ memset(buf, 0, sizeof(buf));
+ ret = fgetxattr(self->child_pidfd, xattr_name, buf, sizeof(buf));
+ ASSERT_EQ(ret, strlen(xattr_value));
+ ASSERT_EQ(strcmp(buf, xattr_value), 0);
+ }
+
+ ret = flistxattr(self->child_pidfd, list, sizeof(list));
+ ASSERT_GT(ret, 0);
+ for (i = 0; i < num_xattrs; i++) {
+ snprintf(xattr_name, sizeof(xattr_name), "trusted.testattr%d", i);
+ bool found = false;
+ for (char *it = list; it < list + ret; it += strlen(it) + 1) {
+ if (strcmp(it, xattr_name))
+ continue;
+ found = true;
+ break;
+ }
+ ASSERT_TRUE(found);
+ }
+
+ for (i = 0; i < num_xattrs; i++) {
+ snprintf(xattr_name, sizeof(xattr_name), "trusted.testattr%d", i);
+ ret = fremovexattr(self->child_pidfd, xattr_name);
+ ASSERT_EQ(ret, 0);
+
+ ret = fgetxattr(self->child_pidfd, xattr_name, buf, sizeof(buf));
+ ASSERT_EQ(ret, -1);
+ ASSERT_EQ(errno, ENODATA);
+ }
+}
+
+TEST_HARNESS_MAIN
--
2.47.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH RFC 6/7] selftests/pidfd: test extended attribute support
2025-06-17 15:45 [PATCH RFC 0/7] pidfs: support extended attributes Christian Brauner
` (4 preceding siblings ...)
2025-06-17 15:45 ` [PATCH RFC 5/7] selftests/pidfd: test extended attribute support Christian Brauner
@ 2025-06-17 15:45 ` Christian Brauner
2025-06-17 15:45 ` [PATCH RFC 7/7] selftests/pidfd: test setattr support Christian Brauner
6 siblings, 0 replies; 12+ messages in thread
From: Christian Brauner @ 2025-06-17 15:45 UTC (permalink / raw)
To: linux-fsdevel
Cc: Jann Horn, Josef Bacik, Jeff Layton, Daan De Meyer,
Lennart Poettering, Mike Yuan, Zbigniew Jędrzejewski-Szmek,
Christian Brauner, Alexander Mikhalitsyn
Test that extended attributes are permanent.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
tools/testing/selftests/pidfd/pidfd_xattr_test.c | 35 ++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/tools/testing/selftests/pidfd/pidfd_xattr_test.c b/tools/testing/selftests/pidfd/pidfd_xattr_test.c
index 00d400ac515b..5cf7bb0e4bf2 100644
--- a/tools/testing/selftests/pidfd/pidfd_xattr_test.c
+++ b/tools/testing/selftests/pidfd/pidfd_xattr_test.c
@@ -94,4 +94,39 @@ TEST_F(pidfs_xattr, set_get_list_xattr_multiple)
}
}
+TEST_F(pidfs_xattr, set_get_list_xattr_persistent)
+{
+ int ret;
+ char buf[32];
+ char list[PATH_MAX] = {};
+
+ ret = fsetxattr(self->child_pidfd, "trusted.persistent", "persistent value", strlen("persistent value"), 0);
+ ASSERT_EQ(ret, 0);
+
+ memset(buf, 0, sizeof(buf));
+ ret = fgetxattr(self->child_pidfd, "trusted.persistent", buf, sizeof(buf));
+ ASSERT_EQ(ret, strlen("persistent value"));
+ ASSERT_EQ(strcmp(buf, "persistent value"), 0);
+
+ ret = flistxattr(self->child_pidfd, list, sizeof(list));
+ ASSERT_GT(ret, 0);
+ ASSERT_EQ(strcmp(list, "trusted.persistent"), 0)
+
+ ASSERT_EQ(close(self->child_pidfd), 0);
+ self->child_pidfd = -EBADF;
+ sleep(2);
+
+ self->child_pidfd = sys_pidfd_open(self->child_pid, 0);
+ ASSERT_GE(self->child_pidfd, 0);
+
+ memset(buf, 0, sizeof(buf));
+ ret = fgetxattr(self->child_pidfd, "trusted.persistent", buf, sizeof(buf));
+ ASSERT_EQ(ret, strlen("persistent value"));
+ ASSERT_EQ(strcmp(buf, "persistent value"), 0);
+
+ ret = flistxattr(self->child_pidfd, list, sizeof(list));
+ ASSERT_GT(ret, 0);
+ ASSERT_EQ(strcmp(list, "trusted.persistent"), 0);
+}
+
TEST_HARNESS_MAIN
--
2.47.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH RFC 7/7] selftests/pidfd: test setattr support
2025-06-17 15:45 [PATCH RFC 0/7] pidfs: support extended attributes Christian Brauner
` (5 preceding siblings ...)
2025-06-17 15:45 ` [PATCH RFC 6/7] " Christian Brauner
@ 2025-06-17 15:45 ` Christian Brauner
6 siblings, 0 replies; 12+ messages in thread
From: Christian Brauner @ 2025-06-17 15:45 UTC (permalink / raw)
To: linux-fsdevel
Cc: Jann Horn, Josef Bacik, Jeff Layton, Daan De Meyer,
Lennart Poettering, Mike Yuan, Zbigniew Jędrzejewski-Szmek,
Christian Brauner, Alexander Mikhalitsyn
Verify that ->setattr() on a pidfd doens't work.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
tools/testing/selftests/pidfd/.gitignore | 1 +
tools/testing/selftests/pidfd/Makefile | 2 +-
tools/testing/selftests/pidfd/pidfd_setattr_test.c | 69 ++++++++++++++++++++++
3 files changed, 71 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/pidfd/.gitignore b/tools/testing/selftests/pidfd/.gitignore
index bc4130506eda..144e7ff65d6a 100644
--- a/tools/testing/selftests/pidfd/.gitignore
+++ b/tools/testing/selftests/pidfd/.gitignore
@@ -11,3 +11,4 @@ pidfd_bind_mount
pidfd_info_test
pidfd_exec_helper
pidfd_xattr_test
+pidfd_setattr_test
diff --git a/tools/testing/selftests/pidfd/Makefile b/tools/testing/selftests/pidfd/Makefile
index c9fd5023ef15..03a6eede9c9e 100644
--- a/tools/testing/selftests/pidfd/Makefile
+++ b/tools/testing/selftests/pidfd/Makefile
@@ -4,7 +4,7 @@ CFLAGS += -g $(KHDR_INCLUDES) -pthread -Wall
TEST_GEN_PROGS := pidfd_test pidfd_fdinfo_test pidfd_open_test \
pidfd_poll_test pidfd_wait pidfd_getfd_test pidfd_setns_test \
pidfd_file_handle_test pidfd_bind_mount pidfd_info_test \
- pidfd_xattr_test
+ pidfd_xattr_test pidfd_setattr_test
TEST_GEN_PROGS_EXTENDED := pidfd_exec_helper
diff --git a/tools/testing/selftests/pidfd/pidfd_setattr_test.c b/tools/testing/selftests/pidfd/pidfd_setattr_test.c
new file mode 100644
index 000000000000..d7de05edc4b3
--- /dev/null
+++ b/tools/testing/selftests/pidfd/pidfd_setattr_test.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <linux/types.h>
+#include <poll.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syscall.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <linux/kcmp.h>
+#include <sys/stat.h>
+#include <sys/xattr.h>
+
+#include "pidfd.h"
+#include "../kselftest_harness.h"
+
+FIXTURE(pidfs_setattr)
+{
+ pid_t child_pid;
+ int child_pidfd;
+};
+
+FIXTURE_SETUP(pidfs_setattr)
+{
+ self->child_pid = create_child(&self->child_pidfd, CLONE_NEWUSER | CLONE_NEWPID);
+ EXPECT_GE(self->child_pid, 0);
+
+ if (self->child_pid == 0)
+ _exit(EXIT_SUCCESS);
+}
+
+FIXTURE_TEARDOWN(pidfs_setattr)
+{
+ sys_waitid(P_PID, self->child_pid, NULL, WEXITED);
+ EXPECT_EQ(close(self->child_pidfd), 0);
+}
+
+TEST_F(pidfs_setattr, no_chown)
+{
+ ASSERT_LT(fchown(self->child_pidfd, 1234, 5678), 0);
+ ASSERT_EQ(errno, EOPNOTSUPP);
+}
+
+TEST_F(pidfs_setattr, no_chmod)
+{
+ ASSERT_LT(fchmod(self->child_pidfd, 0777), 0);
+ ASSERT_EQ(errno, EOPNOTSUPP);
+}
+
+TEST_F(pidfs_setattr, no_exec)
+{
+ char *const argv[] = { NULL };
+ char *const envp[] = { NULL };
+
+ ASSERT_LT(execveat(self->child_pidfd, "", argv, envp, AT_EMPTY_PATH), 0);
+ ASSERT_EQ(errno, EACCES);
+}
+
+TEST_HARNESS_MAIN
--
2.47.2
^ permalink raw reply related [flat|nested] 12+ messages in thread