linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH RFC 0/7] pidfs: support extended attributes
@ 2025-06-17 15:45 Christian Brauner
  2025-06-17 15:45 ` [PATCH RFC 1/7] libfs: prepare to allow for non-immutable pidfd inodes Christian Brauner
                   ` (6 more replies)
  0 siblings, 7 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

With the incoming support for permanent pidfs dentries we can start
supporting extended attributes on pidfds. This will allow to attach meta
information to tasks. This currently adds support for trusted extended
attributes which is a first natural target.

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 slap tags
onto pidfds which is useful for e.g., service managers such as systemd.

Signed-off-by: Christian Brauner <brauner@kernel.org>
---
Christian Brauner (7):
      libfs: prepare to allow for non-immutable pidfd inodes
      pidfs: make inodes mutable
      pidfs: raise SB_I_NODEV and SB_I_NOEXEC
      pidfs: support xattrs on pidfds
      selftests/pidfd: test extended attribute support
      selftests/pidfd: test extended attribute support
      selftests/pidfd: test setattr support

 fs/libfs.c                                         |   1 -
 fs/pidfs.c                                         |  98 ++++++++++++++-
 tools/testing/selftests/pidfd/.gitignore           |   2 +
 tools/testing/selftests/pidfd/Makefile             |   3 +-
 tools/testing/selftests/pidfd/pidfd_setattr_test.c |  69 +++++++++++
 tools/testing/selftests/pidfd/pidfd_xattr_test.c   | 132 +++++++++++++++++++++
 6 files changed, 301 insertions(+), 4 deletions(-)
---
base-commit: ac79f1c5b96d8d2f39b3eed1084588160198f6d3
change-id: 20250617-work-pidfs-xattr-1111246fe9b2


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [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

* [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

* [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

* [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

* [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

* 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

* 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

* 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

* 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

end of thread, other threads:[~2025-06-18 19:54 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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-18 19:44   ` Alexander Mikhalitsyn
2025-06-17 15:45 ` [PATCH RFC 2/7] pidfs: make inodes mutable 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
2025-06-18 19:46   ` Alexander Mikhalitsyn
2025-06-17 15:45 ` [PATCH RFC 4/7] pidfs: support xattrs on pidfds 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
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).