lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250507-work-coredump-socket-v4-9-af0ef317b2d0@kernel.org>
Date: Wed, 07 May 2025 18:13:42 +0200
From: Christian Brauner <brauner@...nel.org>
To: Kuniyuki Iwashima <kuniyu@...zon.com>, linux-fsdevel@...r.kernel.org, 
 Jann Horn <jannh@...gle.com>
Cc: Eric Dumazet <edumazet@...gle.com>, Oleg Nesterov <oleg@...hat.com>, 
 "David S. Miller" <davem@...emloft.net>, 
 Alexander Viro <viro@...iv.linux.org.uk>, 
 Daan De Meyer <daan.j.demeyer@...il.com>, 
 David Rheinsberg <david@...dahead.eu>, Jakub Kicinski <kuba@...nel.org>, 
 Jan Kara <jack@...e.cz>, Lennart Poettering <lennart@...ttering.net>, 
 Luca Boccassi <bluca@...ian.org>, Mike Yuan <me@...dnzj.com>, 
 Paolo Abeni <pabeni@...hat.com>, Simon Horman <horms@...nel.org>, 
 Zbigniew Jędrzejewski-Szmek <zbyszek@...waw.pl>, 
 linux-kernel@...r.kernel.org, netdev@...r.kernel.org, 
 Christian Brauner <brauner@...nel.org>, 
 Alexander Mikhalitsyn <alexander@...alicyn.com>
Subject: [PATCH v4 09/11] pidfs, coredump: allow to verify coredump
 connection

When a coredump connection is initiated use the socket cookie as the
coredump cookie and store it in the pidfd. The receiver can now easily
authenticate that the connection is coming from the kernel.

Unless the coredump server expects to handle connection from
non-crashing task it can validate that the connection has been made from
a crashing task:

   fd_coredump = accept4(fd_socket, NULL, NULL, SOCK_CLOEXEC);
   getsockopt(fd_coredump, SOL_SOCKET, SO_PEERPIDFD, &fd_peer_pidfd, &fd_peer_pidfd_len);

   struct pidfd_info info = {
           info.mask = PIDFD_INFO_EXIT | PIDFD_INFO_COREDUMP,
   };

   ioctl(pidfd, PIDFD_GET_INFO, &info);
   /* Refuse connections that aren't from a crashing task. */
   if (!(info.mask & PIDFD_INFO_COREDUMP) || !(info.coredump_mask & PIDFD_COREDUMPED) )
           close(fd_coredump);

   /*
    * Make sure that the coredump cookie matches the connection cookie.
    * If they don't it's not the coredump connection from the kernel.
    * We'll get another connection request in a bit.
    */
   getsocketop(fd_coredump, SOL_SOCKET, SO_COOKIE, &peer_cookie, &peer_cookie_len);
   if (!info.coredump_cookie || (info.coredump_cookie != peer_cookie))
           close(fd_coredump);

The kernel guarantees that by the time the connection is made the
coredump info is available.

Signed-off-by: Christian Brauner <brauner@...nel.org>
---
 fs/coredump.c              |  3 ++-
 fs/pidfs.c                 | 20 +++++++++++++++++++-
 include/linux/net.h        |  1 +
 include/linux/pidfs.h      |  1 +
 include/uapi/linux/pidfd.h |  1 +
 net/unix/af_unix.c         |  7 +++++++
 6 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/fs/coredump.c b/fs/coredump.c
index ddff1854988f..cfb7a3459785 100644
--- a/fs/coredump.c
+++ b/fs/coredump.c
@@ -907,7 +907,8 @@ void do_coredump(const kernel_siginfo_t *siginfo)
 		 */
 		retval = kernel_connect(socket,
 					(struct sockaddr *)(&coredump_unix_socket),
-					COREDUMP_UNIX_SOCKET_ADDR_SIZE, O_NONBLOCK);
+					COREDUMP_UNIX_SOCKET_ADDR_SIZE, O_NONBLOCK |
+					SOCK_COREDUMP);
 
 		/*
 		 * ... So we can safely put our pidfs reference now...
diff --git a/fs/pidfs.c b/fs/pidfs.c
index 8c4d83fb115b..7ff1e7923f19 100644
--- a/fs/pidfs.c
+++ b/fs/pidfs.c
@@ -35,6 +35,7 @@ struct pidfs_exit_info {
 	__u64 cgroupid;
 	__s32 exit_code;
 	__u32 coredump_mask;
+	__u64 coredump_cookie;
 };
 
 struct pidfs_inode {
@@ -300,6 +301,7 @@ static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg)
 
 	if (mask & PIDFD_INFO_COREDUMP) {
 		kinfo.mask |= PIDFD_INFO_COREDUMP;
+		kinfo.coredump_cookie = READ_ONCE(pidfs_i(inode)->__pei.coredump_cookie);
 		kinfo.coredump_mask = READ_ONCE(pidfs_i(inode)->__pei.coredump_mask);
 	}
 
@@ -321,8 +323,10 @@ static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg)
 
 	if (!(kinfo.mask & PIDFD_INFO_COREDUMP)) {
 		task_lock(task);
-		if (task->mm)
+		if (task->mm) {
+			kinfo.coredump_cookie = READ_ONCE(pidfs_i(inode)->__pei.coredump_cookie);
 			kinfo.coredump_mask = pidfs_coredump_mask(task->mm->flags);
+		}
 		task_unlock(task);
 	}
 
@@ -589,6 +593,20 @@ void pidfs_exit(struct task_struct *tsk)
 	}
 }
 
+void pidfs_coredump_cookie(struct pid *pid, u64 coredump_cookie)
+{
+	struct pidfs_exit_info *exit_info;
+	struct dentry *dentry = pid->stashed;
+	struct inode *inode;
+
+	if (WARN_ON_ONCE(!dentry))
+		return;
+
+	inode = d_inode(dentry);
+	exit_info = &pidfs_i(inode)->__pei;
+	smp_store_release(&exit_info->coredump_cookie, coredump_cookie);
+}
+
 void pidfs_coredump(const struct coredump_params *cprm)
 {
 	struct pid *pid = cprm->pid;
diff --git a/include/linux/net.h b/include/linux/net.h
index 0ff950eecc6b..005f1e52e7f1 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -81,6 +81,7 @@ enum sock_type {
 #ifndef SOCK_NONBLOCK
 #define SOCK_NONBLOCK	O_NONBLOCK
 #endif
+#define SOCK_COREDUMP	O_TRUNC
 
 #endif /* ARCH_HAS_SOCKET_TYPES */
 
diff --git a/include/linux/pidfs.h b/include/linux/pidfs.h
index f7729b9371bc..5875037be272 100644
--- a/include/linux/pidfs.h
+++ b/include/linux/pidfs.h
@@ -10,6 +10,7 @@ void pidfs_add_pid(struct pid *pid);
 void pidfs_remove_pid(struct pid *pid);
 void pidfs_exit(struct task_struct *tsk);
 void pidfs_coredump(const struct coredump_params *cprm);
+void pidfs_coredump_cookie(struct pid *pid, u64 coredump_cookie);
 extern const struct dentry_operations pidfs_dentry_operations;
 int pidfs_register_pid(struct pid *pid);
 void pidfs_get_pid(struct pid *pid);
diff --git a/include/uapi/linux/pidfd.h b/include/uapi/linux/pidfd.h
index 84ac709f560c..f46819a02d23 100644
--- a/include/uapi/linux/pidfd.h
+++ b/include/uapi/linux/pidfd.h
@@ -108,6 +108,7 @@ struct pidfd_info {
 	__s32 exit_code;
 	__u32 coredump_mask;
 	__u32 __spare1;
+	__u64 coredump_cookie;
 };
 
 #define PIDFS_IOCTL_MAGIC 0xFF
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 148d008862e7..45e7a6363939 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -101,6 +101,7 @@
 #include <linux/string.h>
 #include <linux/uaccess.h>
 #include <linux/pidfs.h>
+#include <linux/sock_diag.h>
 #include <net/af_unix.h>
 #include <net/net_namespace.h>
 #include <net/scm.h>
@@ -771,6 +772,7 @@ static void unix_release_sock(struct sock *sk, int embrion)
 
 struct unix_peercred {
 	struct pid *peer_pid;
+	u64 cookie;
 	const struct cred *peer_cred;
 };
 
@@ -806,6 +808,8 @@ static void drop_peercred(struct unix_peercred *peercred)
 static inline void init_peercred(struct sock *sk,
 				 const struct unix_peercred *peercred)
 {
+	if (peercred->cookie)
+		pidfs_coredump_cookie(peercred->peer_pid, peercred->cookie);
 	sk->sk_peer_pid = peercred->peer_pid;
 	sk->sk_peer_cred = peercred->peer_cred;
 }
@@ -1717,6 +1721,9 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
 	unix_peer(newsk)	= sk;
 	newsk->sk_state		= TCP_ESTABLISHED;
 	newsk->sk_type		= sk->sk_type;
+	/* Prepare a new socket cookie for the receiver. */
+	if (flags & SOCK_COREDUMP)
+		peercred.cookie = sock_gen_cookie(newsk);
 	init_peercred(newsk, &peercred);
 	newu = unix_sk(newsk);
 	newu->listener = other;

-- 
2.47.2


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ