[net-next,v6,1/3] scm: add SO_PASSPIDFD and SCM_PIDFD

Message ID 20230522132439.634031-2-aleksandr.mikhalitsyn@canonical.com
State New
Headers
Series Add SCM_PIDFD and SO_PEERPIDFD |

Commit Message

Aleksandr Mikhalitsyn May 22, 2023, 1:24 p.m. UTC
  Implement SCM_PIDFD, a new type of CMSG type analogical to SCM_CREDENTIALS,
but it contains pidfd instead of plain pid, which allows programmers not
to care about PID reuse problem.

We mask SO_PASSPIDFD feature if CONFIG_UNIX is not builtin because
it depends on a pidfd_prepare() API which is not exported to the kernel
modules.

Idea comes from UAPI kernel group:
https://uapi-group.org/kernel-features/

Big thanks to Christian Brauner and Lennart Poettering for productive
discussions about this.

Cc: "David S. Miller" <davem@davemloft.net>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: Paolo Abeni <pabeni@redhat.com>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: David Ahern <dsahern@kernel.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Kees Cook <keescook@chromium.org>
Cc: Christian Brauner <brauner@kernel.org>
Cc: Kuniyuki Iwashima <kuniyu@amazon.com>
Cc: Lennart Poettering <mzxreary@0pointer.de>
Cc: Luca Boccassi <bluca@debian.org>
Cc: linux-kernel@vger.kernel.org
Cc: netdev@vger.kernel.org
Cc: linux-arch@vger.kernel.org
Tested-by: Luca Boccassi <bluca@debian.org>
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
---
v6:
	- disable feature when CONFIG_UNIX=n/m (pidfd_prepare API is not exported to modules)
v5:
	- no changes
v4:
	- fixed silent fd_install if writting of CMSG to the userspace fails (pointed by Christian)
v2:
	According to review comments from Kuniyuki Iwashima and Christian Brauner:
	- use pidfd_create(..) retval as a result
	- whitespace change
---
 arch/alpha/include/uapi/asm/socket.h    |  2 ++
 arch/mips/include/uapi/asm/socket.h     |  2 ++
 arch/parisc/include/uapi/asm/socket.h   |  2 ++
 arch/sparc/include/uapi/asm/socket.h    |  2 ++
 include/linux/net.h                     |  1 +
 include/linux/socket.h                  |  1 +
 include/net/scm.h                       | 43 +++++++++++++++++++++++--
 include/uapi/asm-generic/socket.h       |  2 ++
 net/core/sock.c                         | 15 +++++++++
 net/mptcp/sockopt.c                     |  3 ++
 net/unix/af_unix.c                      | 18 ++++++++---
 tools/include/uapi/asm-generic/socket.h |  2 ++
 12 files changed, 86 insertions(+), 7 deletions(-)
  

Comments

Jakub Kicinski May 22, 2023, 8:34 p.m. UTC | #1
On Mon, 22 May 2023 15:24:37 +0200 Alexander Mikhalitsyn wrote:
> v6:
> 	- disable feature when CONFIG_UNIX=n/m (pidfd_prepare API is not exported to modules)

IMHO hiding the code under #if IS_BUILTIN(CONFIG_UNRELATED) is
surprising to the user and.. ugly?

Can we move scm_pidfd_recv() into a C source and export that?
That should be less controversial than exporting pidfd_prepare()
directly?
  
Christian Brauner May 23, 2023, 9:49 a.m. UTC | #2
On Mon, May 22, 2023 at 01:34:09PM -0700, Jakub Kicinski wrote:
> On Mon, 22 May 2023 15:24:37 +0200 Alexander Mikhalitsyn wrote:
> > v6:
> > 	- disable feature when CONFIG_UNIX=n/m (pidfd_prepare API is not exported to modules)
> 
> IMHO hiding the code under #if IS_BUILTIN(CONFIG_UNRELATED) is
> surprising to the user and.. ugly?
> 
> Can we move scm_pidfd_recv() into a C source and export that?
> That should be less controversial than exporting pidfd_prepare()
> directly?

I really would like to avoid that because it will just mean that someone
else will abuse that function and then make an argument why we should
export the other function.

I think it would be ok if we required that unix support is built in
because it's not unprecedented either and we're not breaking anything.
Bpf has the same requirement:

  #if IS_BUILTIN(CONFIG_UNIX) && defined(CONFIG_BPF_SYSCALL)
  struct bpf_unix_iter_state {
          struct seq_net_private p;
          unsigned int cur_sk;
          unsigned int end_sk;
          unsigned int max_sk;
          struct sock **batch;
          bool st_bucket_done;
  };

and

  #if IS_BUILTIN(CONFIG_UNIX) && defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
  DEFINE_BPF_ITER_FUNC(unix, struct bpf_iter_meta *meta,
                       struct unix_sock *unix_sk, uid_t uid)
  
Luca Boccassi May 23, 2023, 10:44 a.m. UTC | #3
On Tue, 23 May 2023 at 10:49, Christian Brauner <brauner@kernel.org> wrote:
>
> On Mon, May 22, 2023 at 01:34:09PM -0700, Jakub Kicinski wrote:
> > On Mon, 22 May 2023 15:24:37 +0200 Alexander Mikhalitsyn wrote:
> > > v6:
> > >     - disable feature when CONFIG_UNIX=n/m (pidfd_prepare API is not exported to modules)
> >
> > IMHO hiding the code under #if IS_BUILTIN(CONFIG_UNRELATED) is
> > surprising to the user and.. ugly?
> >
> > Can we move scm_pidfd_recv() into a C source and export that?
> > That should be less controversial than exporting pidfd_prepare()
> > directly?
>
> I really would like to avoid that because it will just mean that someone
> else will abuse that function and then make an argument why we should
> export the other function.
>
> I think it would be ok if we required that unix support is built in
> because it's not unprecedented either and we're not breaking anything.
> Bpf has the same requirement:
>
>   #if IS_BUILTIN(CONFIG_UNIX) && defined(CONFIG_BPF_SYSCALL)
>   struct bpf_unix_iter_state {
>           struct seq_net_private p;
>           unsigned int cur_sk;
>           unsigned int end_sk;
>           unsigned int max_sk;
>           struct sock **batch;
>           bool st_bucket_done;
>   };
>
> and
>
>   #if IS_BUILTIN(CONFIG_UNIX) && defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
>   DEFINE_BPF_ITER_FUNC(unix, struct bpf_iter_meta *meta,
>                        struct unix_sock *unix_sk, uid_t uid)

Some data points: Debian, Ubuntu, Fedora, RHEL, CentOS, Archlinux all
ship with CONFIG_UNIX=y, so a missing SCM_PIDFD in unlikely to have a
widespread impact, and if it does, it might encourage someone to
review their kconfig.

As mentioned on the v5 thread, we are waiting for this API to get the
userspace side sorted (systemd/dbus/dbus-broker/polkit), so I'd be
really grateful if we could start with the simplest and most
conservative approach (which seems to be the current one in v6 to me),
and then eventually later decide whether to export more functions, or
to deprecate CONFIG_UNIX=m, or something else entirely, as that
doesn't really affect the shape of the UAPI, just the details of its
availability. Thank you.

Kind regards,
Luca Boccassi
  
Jakub Kicinski May 23, 2023, 9:08 p.m. UTC | #4
On Tue, 23 May 2023 11:44:01 +0100 Luca Boccassi wrote:
> > I really would like to avoid that because it will just mean that someone
> > else will abuse that function and then make an argument why we should
> > export the other function.
> >
> > I think it would be ok if we required that unix support is built in
> > because it's not unprecedented either and we're not breaking anything.
> > Bpf has the same requirement:
> >
> >   #if IS_BUILTIN(CONFIG_UNIX) && defined(CONFIG_BPF_SYSCALL)
> >   struct bpf_unix_iter_state {
> >           struct seq_net_private p;
> >           unsigned int cur_sk;
> >           unsigned int end_sk;
> >           unsigned int max_sk;
> >           struct sock **batch;
> >           bool st_bucket_done;
> >   };
> >
> > and
> >
> >   #if IS_BUILTIN(CONFIG_UNIX) && defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
> >   DEFINE_BPF_ITER_FUNC(unix, struct bpf_iter_meta *meta,
> >                        struct unix_sock *unix_sk, uid_t uid)  

Don't think we should bring BPF into arguments about uAPI consistency :S

> Some data points: Debian, Ubuntu, Fedora, RHEL, CentOS, Archlinux all
> ship with CONFIG_UNIX=y, so a missing SCM_PIDFD in unlikely to have a
> widespread impact, and if it does, it might encourage someone to
> review their kconfig.

IDK how you can argue that everyone sets UNIX to =y so hiding SCM_PIDFD
is fine and at the same time not be okay with making UNIX a bool :S

> As mentioned on the v5 thread, we are waiting for this API to get the
> userspace side sorted (systemd/dbus/dbus-broker/polkit), so I'd be
> really grateful if we could start with the simplest and most
> conservative approach (which seems to be the current one in v6 to me),
> and then eventually later decide whether to export more functions, or
> to deprecate CONFIG_UNIX=m, or something else entirely, as that
> doesn't really affect the shape of the UAPI, just the details of its
> availability. Thank you.

Just throw in a patch to make UNIX a bool and stop arguing then.
  
Aleksandr Mikhalitsyn May 24, 2023, 10:43 a.m. UTC | #5
On Tue, May 23, 2023 at 11:08 PM Jakub Kicinski <kuba@kernel.org> wrote:
>
> On Tue, 23 May 2023 11:44:01 +0100 Luca Boccassi wrote:
> > > I really would like to avoid that because it will just mean that someone
> > > else will abuse that function and then make an argument why we should
> > > export the other function.
> > >
> > > I think it would be ok if we required that unix support is built in
> > > because it's not unprecedented either and we're not breaking anything.
> > > Bpf has the same requirement:
> > >
> > >   #if IS_BUILTIN(CONFIG_UNIX) && defined(CONFIG_BPF_SYSCALL)
> > >   struct bpf_unix_iter_state {
> > >           struct seq_net_private p;
> > >           unsigned int cur_sk;
> > >           unsigned int end_sk;
> > >           unsigned int max_sk;
> > >           struct sock **batch;
> > >           bool st_bucket_done;
> > >   };
> > >
> > > and
> > >
> > >   #if IS_BUILTIN(CONFIG_UNIX) && defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
> > >   DEFINE_BPF_ITER_FUNC(unix, struct bpf_iter_meta *meta,
> > >                        struct unix_sock *unix_sk, uid_t uid)
>
> Don't think we should bring BPF into arguments about uAPI consistency :S
>
> > Some data points: Debian, Ubuntu, Fedora, RHEL, CentOS, Archlinux all
> > ship with CONFIG_UNIX=y, so a missing SCM_PIDFD in unlikely to have a
> > widespread impact, and if it does, it might encourage someone to
> > review their kconfig.
>
> IDK how you can argue that everyone sets UNIX to =y so hiding SCM_PIDFD
> is fine and at the same time not be okay with making UNIX a bool :S
>
> > As mentioned on the v5 thread, we are waiting for this API to get the
> > userspace side sorted (systemd/dbus/dbus-broker/polkit), so I'd be
> > really grateful if we could start with the simplest and most
> > conservative approach (which seems to be the current one in v6 to me),
> > and then eventually later decide whether to export more functions, or
> > to deprecate CONFIG_UNIX=m, or something else entirely, as that
> > doesn't really affect the shape of the UAPI, just the details of its
> > availability. Thank you.
>
> Just throw in a patch to make UNIX a bool and stop arguing then.

Dear Jakub,

Thanks for your attention to these patch series!

I'm ready to prepare/send a patch to make CONFIG_UNIX bool.

I will send SO_PEERPIDFD as an independent patch too, because it
doesn't require this change with CONFIG_UNIX
and we can avoid waiting until CONFIG_UNIX change will be merged.
I've a feeling that the discussion around making CONFIG_UNIX  to be a
boolean won't be easy and fast ;-)

Kind regards,
Alex
  
Luca Boccassi May 24, 2023, 10:47 a.m. UTC | #6
On Wed, 24 May 2023 at 11:43, Aleksandr Mikhalitsyn
<aleksandr.mikhalitsyn@canonical.com> wrote:
>
> On Tue, May 23, 2023 at 11:08 PM Jakub Kicinski <kuba@kernel.org> wrote:
> >
> > On Tue, 23 May 2023 11:44:01 +0100 Luca Boccassi wrote:
> > > > I really would like to avoid that because it will just mean that someone
> > > > else will abuse that function and then make an argument why we should
> > > > export the other function.
> > > >
> > > > I think it would be ok if we required that unix support is built in
> > > > because it's not unprecedented either and we're not breaking anything.
> > > > Bpf has the same requirement:
> > > >
> > > >   #if IS_BUILTIN(CONFIG_UNIX) && defined(CONFIG_BPF_SYSCALL)
> > > >   struct bpf_unix_iter_state {
> > > >           struct seq_net_private p;
> > > >           unsigned int cur_sk;
> > > >           unsigned int end_sk;
> > > >           unsigned int max_sk;
> > > >           struct sock **batch;
> > > >           bool st_bucket_done;
> > > >   };
> > > >
> > > > and
> > > >
> > > >   #if IS_BUILTIN(CONFIG_UNIX) && defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
> > > >   DEFINE_BPF_ITER_FUNC(unix, struct bpf_iter_meta *meta,
> > > >                        struct unix_sock *unix_sk, uid_t uid)
> >
> > Don't think we should bring BPF into arguments about uAPI consistency :S
> >
> > > Some data points: Debian, Ubuntu, Fedora, RHEL, CentOS, Archlinux all
> > > ship with CONFIG_UNIX=y, so a missing SCM_PIDFD in unlikely to have a
> > > widespread impact, and if it does, it might encourage someone to
> > > review their kconfig.
> >
> > IDK how you can argue that everyone sets UNIX to =y so hiding SCM_PIDFD
> > is fine and at the same time not be okay with making UNIX a bool :S
> >
> > > As mentioned on the v5 thread, we are waiting for this API to get the
> > > userspace side sorted (systemd/dbus/dbus-broker/polkit), so I'd be
> > > really grateful if we could start with the simplest and most
> > > conservative approach (which seems to be the current one in v6 to me),
> > > and then eventually later decide whether to export more functions, or
> > > to deprecate CONFIG_UNIX=m, or something else entirely, as that
> > > doesn't really affect the shape of the UAPI, just the details of its
> > > availability. Thank you.
> >
> > Just throw in a patch to make UNIX a bool and stop arguing then.
>
> Dear Jakub,
>
> Thanks for your attention to these patch series!
>
> I'm ready to prepare/send a patch to make CONFIG_UNIX bool.
>
> I will send SO_PEERPIDFD as an independent patch too, because it
> doesn't require this change with CONFIG_UNIX
> and we can avoid waiting until CONFIG_UNIX change will be merged.
> I've a feeling that the discussion around making CONFIG_UNIX  to be a
> boolean won't be easy and fast ;-)

Thank you, that sounds great to me, I can start using SO_PEERPIDFD
independently of SCM_PIDFD, there's no hard dependency between the
two.

Kind regards,
Luca Boccassi
  
Jakub Kicinski May 24, 2023, 3:19 p.m. UTC | #7
On Wed, 24 May 2023 11:47:50 +0100 Luca Boccassi wrote:
> > I will send SO_PEERPIDFD as an independent patch too, because it
> > doesn't require this change with CONFIG_UNIX
> > and we can avoid waiting until CONFIG_UNIX change will be merged.
> > I've a feeling that the discussion around making CONFIG_UNIX  to be a
> > boolean won't be easy and fast ;-)  
> 
> Thank you, that sounds great to me, I can start using SO_PEERPIDFD
> independently of SCM_PIDFD, there's no hard dependency between the
> two.

How about you put the UNIX -> bool patch at the end of the series,
(making it a 4 patch series) and if there's a discussion about it 
I'll just skip it and apply the first 3 patches?

In the (IMHO more likely) case that there isn't a discussion it saves
me from remembering to chase you to send that patch ;)
  
Aleksandr Mikhalitsyn May 24, 2023, 3:45 p.m. UTC | #8
On Wed, May 24, 2023 at 5:19 PM Jakub Kicinski <kuba@kernel.org> wrote:
>
> On Wed, 24 May 2023 11:47:50 +0100 Luca Boccassi wrote:
> > > I will send SO_PEERPIDFD as an independent patch too, because it
> > > doesn't require this change with CONFIG_UNIX
> > > and we can avoid waiting until CONFIG_UNIX change will be merged.
> > > I've a feeling that the discussion around making CONFIG_UNIX  to be a
> > > boolean won't be easy and fast ;-)
> >
> > Thank you, that sounds great to me, I can start using SO_PEERPIDFD
> > independently of SCM_PIDFD, there's no hard dependency between the
> > two.
>
> How about you put the UNIX -> bool patch at the end of the series,
> (making it a 4 patch series) and if there's a discussion about it
> I'll just skip it and apply the first 3 patches?

Sure, I will do that!

>
> In the (IMHO more likely) case that there isn't a discussion it saves
> me from remembering to chase you to send that patch ;)

Thanks a lot, Jakub!

Kind regards,
Alex
  
Jakub Kicinski June 4, 2023, 6:02 p.m. UTC | #9
On Wed, 24 May 2023 17:45:25 +0200 Aleksandr Mikhalitsyn wrote:
> > How about you put the UNIX -> bool patch at the end of the series,
> > (making it a 4 patch series) and if there's a discussion about it
> > I'll just skip it and apply the first 3 patches?  
> 
> Sure, I will do that!

Hi Aleksandr! Did you disappear? Have I missed v7?
  
Aleksandr Mikhalitsyn June 4, 2023, 6:07 p.m. UTC | #10
On Sun, Jun 4, 2023 at 8:02 PM Jakub Kicinski <kuba@kernel.org> wrote:
>
> On Wed, 24 May 2023 17:45:25 +0200 Aleksandr Mikhalitsyn wrote:
> > > How about you put the UNIX -> bool patch at the end of the series,
> > > (making it a 4 patch series) and if there's a discussion about it
> > > I'll just skip it and apply the first 3 patches?
> >
> > Sure, I will do that!
>
> Hi Aleksandr! Did you disappear? Have I missed v7?

Dear Jakub,

of course I'm not, I've just got distracted with other things last
week. Will send -v7 this week!
Thanks for paying attention to the series ;-)

Kind regards,
Alex
  
Aleksandr Mikhalitsyn June 8, 2023, 8:28 p.m. UTC | #11
On Sun, Jun 4, 2023 at 8:07 PM Aleksandr Mikhalitsyn
<aleksandr.mikhalitsyn@canonical.com> wrote:
>
> On Sun, Jun 4, 2023 at 8:02 PM Jakub Kicinski <kuba@kernel.org> wrote:
> >
> > On Wed, 24 May 2023 17:45:25 +0200 Aleksandr Mikhalitsyn wrote:
> > > > How about you put the UNIX -> bool patch at the end of the series,
> > > > (making it a 4 patch series) and if there's a discussion about it
> > > > I'll just skip it and apply the first 3 patches?
> > >
> > > Sure, I will do that!
> >
> > Hi Aleksandr! Did you disappear? Have I missed v7?
>
> Dear Jakub,
>
> of course I'm not, I've just got distracted with other things last
> week. Will send -v7 this week!
> Thanks for paying attention to the series ;-)
>
> Kind regards,
> Alex

Dear Jakub,

I've sent -v7:
https://lore.kernel.org/all/20230608202628.837772-1-aleksandr.mikhalitsyn@canonical.com/

Kind regards,
Alex
  

Patch

diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h
index 739891b94136..ff310613ae64 100644
--- a/arch/alpha/include/uapi/asm/socket.h
+++ b/arch/alpha/include/uapi/asm/socket.h
@@ -137,6 +137,8 @@ 
 
 #define SO_RCVMARK		75
 
+#define SO_PASSPIDFD		76
+
 #if !defined(__KERNEL__)
 
 #if __BITS_PER_LONG == 64
diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h
index 18f3d95ecfec..762dcb80e4ec 100644
--- a/arch/mips/include/uapi/asm/socket.h
+++ b/arch/mips/include/uapi/asm/socket.h
@@ -148,6 +148,8 @@ 
 
 #define SO_RCVMARK		75
 
+#define SO_PASSPIDFD		76
+
 #if !defined(__KERNEL__)
 
 #if __BITS_PER_LONG == 64
diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h
index f486d3dfb6bb..df16a3e16d64 100644
--- a/arch/parisc/include/uapi/asm/socket.h
+++ b/arch/parisc/include/uapi/asm/socket.h
@@ -129,6 +129,8 @@ 
 
 #define SO_RCVMARK		0x4049
 
+#define SO_PASSPIDFD		0x404A
+
 #if !defined(__KERNEL__)
 
 #if __BITS_PER_LONG == 64
diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h
index 2fda57a3ea86..6e2847804fea 100644
--- a/arch/sparc/include/uapi/asm/socket.h
+++ b/arch/sparc/include/uapi/asm/socket.h
@@ -130,6 +130,8 @@ 
 
 #define SO_RCVMARK               0x0054
 
+#define SO_PASSPIDFD             0x0055
+
 #if !defined(__KERNEL__)
 
 
diff --git a/include/linux/net.h b/include/linux/net.h
index b73ad8e3c212..c234dfbe7a30 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -43,6 +43,7 @@  struct net;
 #define SOCK_PASSSEC		4
 #define SOCK_SUPPORT_ZC		5
 #define SOCK_CUSTOM_SOCKOPT	6
+#define SOCK_PASSPIDFD		7
 
 #ifndef ARCH_HAS_SOCKET_TYPES
 /**
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 13c3a237b9c9..6bf90f251910 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -177,6 +177,7 @@  static inline size_t msg_data_left(struct msghdr *msg)
 #define	SCM_RIGHTS	0x01		/* rw: access rights (array of int) */
 #define SCM_CREDENTIALS 0x02		/* rw: struct ucred		*/
 #define SCM_SECURITY	0x03		/* rw: security label		*/
+#define SCM_PIDFD	0x04		/* ro: pidfd (int)		*/
 
 struct ucred {
 	__u32	pid;
diff --git a/include/net/scm.h b/include/net/scm.h
index 585adc1346bd..13b188422370 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -120,12 +120,46 @@  static inline bool scm_has_secdata(struct socket *sock)
 }
 #endif /* CONFIG_SECURITY_NETWORK */
 
+#if IS_BUILTIN(CONFIG_UNIX)
+static __inline__ void scm_pidfd_recv(struct msghdr *msg, struct scm_cookie *scm)
+{
+	struct file *pidfd_file = NULL;
+	int pidfd;
+
+	/*
+	 * put_cmsg() doesn't return an error if CMSG is truncated,
+	 * that's why we need to opencode these checks here.
+	 */
+	if ((msg->msg_controllen <= sizeof(struct cmsghdr)) ||
+	    (msg->msg_controllen - sizeof(struct cmsghdr)) < sizeof(int)) {
+		msg->msg_flags |= MSG_CTRUNC;
+		return;
+	}
+
+	WARN_ON_ONCE(!scm->pid);
+	pidfd = pidfd_prepare(scm->pid, 0, &pidfd_file);
+
+	if (put_cmsg(msg, SOL_SOCKET, SCM_PIDFD, sizeof(int), &pidfd)) {
+		if (pidfd_file) {
+			put_unused_fd(pidfd);
+			fput(pidfd_file);
+		}
+
+		return;
+	}
+
+	if (pidfd_file)
+		fd_install(pidfd, pidfd_file);
+}
+#endif
+
 static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
 				struct scm_cookie *scm, int flags)
 {
 	if (!msg->msg_control) {
-		if (test_bit(SOCK_PASSCRED, &sock->flags) || scm->fp ||
-		    scm_has_secdata(sock))
+		if (test_bit(SOCK_PASSCRED, &sock->flags) ||
+		    test_bit(SOCK_PASSPIDFD, &sock->flags) ||
+		    scm->fp || scm_has_secdata(sock))
 			msg->msg_flags |= MSG_CTRUNC;
 		scm_destroy(scm);
 		return;
@@ -141,6 +175,11 @@  static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
 		put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds);
 	}
 
+#if IS_BUILTIN(CONFIG_UNIX)
+	if (test_bit(SOCK_PASSPIDFD, &sock->flags))
+		scm_pidfd_recv(msg, scm);
+#endif
+
 	scm_destroy_cred(scm);
 
 	scm_passec(sock, msg, scm);
diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h
index 638230899e98..b76169fdb80b 100644
--- a/include/uapi/asm-generic/socket.h
+++ b/include/uapi/asm-generic/socket.h
@@ -132,6 +132,8 @@ 
 
 #define SO_RCVMARK		75
 
+#define SO_PASSPIDFD		76
+
 #if !defined(__KERNEL__)
 
 #if __BITS_PER_LONG == 64 || (defined(__x86_64__) && defined(__ILP32__))
diff --git a/net/core/sock.c b/net/core/sock.c
index 5440e67bcfe3..f6c415ef151f 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1246,6 +1246,15 @@  int sk_setsockopt(struct sock *sk, int level, int optname,
 			clear_bit(SOCK_PASSCRED, &sock->flags);
 		break;
 
+#if IS_BUILTIN(CONFIG_UNIX)
+	case SO_PASSPIDFD:
+		if (valbool)
+			set_bit(SOCK_PASSPIDFD, &sock->flags);
+		else
+			clear_bit(SOCK_PASSPIDFD, &sock->flags);
+		break;
+#endif
+
 	case SO_TIMESTAMP_OLD:
 	case SO_TIMESTAMP_NEW:
 	case SO_TIMESTAMPNS_OLD:
@@ -1732,6 +1741,12 @@  int sk_getsockopt(struct sock *sk, int level, int optname,
 		v.val = !!test_bit(SOCK_PASSCRED, &sock->flags);
 		break;
 
+#if IS_BUILTIN(CONFIG_UNIX)
+	case SO_PASSPIDFD:
+		v.val = !!test_bit(SOCK_PASSPIDFD, &sock->flags);
+		break;
+#endif
+
 	case SO_PEERCRED:
 	{
 		struct ucred peercred;
diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c
index d4258869ac48..5a80eb23089f 100644
--- a/net/mptcp/sockopt.c
+++ b/net/mptcp/sockopt.c
@@ -355,6 +355,9 @@  static int mptcp_setsockopt_sol_socket(struct mptcp_sock *msk, int optname,
 	case SO_BROADCAST:
 	case SO_BSDCOMPAT:
 	case SO_PASSCRED:
+#if IS_BUILTIN(CONFIG_UNIX)
+	case SO_PASSPIDFD:
+#endif
 	case SO_PASSSEC:
 	case SO_RXQ_OVFL:
 	case SO_WIFI_STATUS:
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index cc695c9f09ec..aac40106d036 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1361,7 +1361,8 @@  static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr,
 		if (err)
 			goto out;
 
-		if (test_bit(SOCK_PASSCRED, &sock->flags) &&
+		if ((test_bit(SOCK_PASSCRED, &sock->flags) ||
+		     test_bit(SOCK_PASSPIDFD, &sock->flags)) &&
 		    !unix_sk(sk)->addr) {
 			err = unix_autobind(sk);
 			if (err)
@@ -1469,7 +1470,8 @@  static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
 	if (err)
 		goto out;
 
-	if (test_bit(SOCK_PASSCRED, &sock->flags) && !u->addr) {
+	if ((test_bit(SOCK_PASSCRED, &sock->flags) ||
+	     test_bit(SOCK_PASSPIDFD, &sock->flags)) && !u->addr) {
 		err = unix_autobind(sk);
 		if (err)
 			goto out;
@@ -1670,6 +1672,8 @@  static void unix_sock_inherit_flags(const struct socket *old,
 {
 	if (test_bit(SOCK_PASSCRED, &old->flags))
 		set_bit(SOCK_PASSCRED, &new->flags);
+	if (test_bit(SOCK_PASSPIDFD, &old->flags))
+		set_bit(SOCK_PASSPIDFD, &new->flags);
 	if (test_bit(SOCK_PASSSEC, &old->flags))
 		set_bit(SOCK_PASSSEC, &new->flags);
 }
@@ -1819,8 +1823,10 @@  static bool unix_passcred_enabled(const struct socket *sock,
 				  const struct sock *other)
 {
 	return test_bit(SOCK_PASSCRED, &sock->flags) ||
+	       test_bit(SOCK_PASSPIDFD, &sock->flags) ||
 	       !other->sk_socket ||
-	       test_bit(SOCK_PASSCRED, &other->sk_socket->flags);
+	       test_bit(SOCK_PASSCRED, &other->sk_socket->flags) ||
+	       test_bit(SOCK_PASSPIDFD, &other->sk_socket->flags);
 }
 
 /*
@@ -1922,7 +1928,8 @@  static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
 			goto out;
 	}
 
-	if (test_bit(SOCK_PASSCRED, &sock->flags) && !u->addr) {
+	if ((test_bit(SOCK_PASSCRED, &sock->flags) ||
+	     test_bit(SOCK_PASSPIDFD, &sock->flags)) && !u->addr) {
 		err = unix_autobind(sk);
 		if (err)
 			goto out;
@@ -2824,7 +2831,8 @@  static int unix_stream_read_generic(struct unix_stream_read_state *state,
 			/* Never glue messages from different writers */
 			if (!unix_skb_scm_eq(skb, &scm))
 				break;
-		} else if (test_bit(SOCK_PASSCRED, &sock->flags)) {
+		} else if (test_bit(SOCK_PASSCRED, &sock->flags) ||
+			   test_bit(SOCK_PASSPIDFD, &sock->flags)) {
 			/* Copy credentials */
 			scm_set_cred(&scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
 			unix_set_secdata(&scm, skb);
diff --git a/tools/include/uapi/asm-generic/socket.h b/tools/include/uapi/asm-generic/socket.h
index 8756df13be50..fbbc4bf53ee3 100644
--- a/tools/include/uapi/asm-generic/socket.h
+++ b/tools/include/uapi/asm-generic/socket.h
@@ -121,6 +121,8 @@ 
 
 #define SO_RCVMARK		75
 
+#define SO_PASSPIDFD		76
+
 #if !defined(__KERNEL__)
 
 #if __BITS_PER_LONG == 64 || (defined(__x86_64__) && defined(__ILP32__))