Commit 77cbe1a6 authored by Kuniyuki Iwashima's avatar Kuniyuki Iwashima Committed by David S. Miller
Browse files

af_unix: Introduce SO_PASSRIGHTS.

As long as recvmsg() or recvmmsg() is used with cmsg, it is not
possible to avoid receiving file descriptors via SCM_RIGHTS.

This behaviour has occasionally been flagged as problematic, as
it can be (ab)used to trigger DoS during close(), for example, by
passing a FUSE-controlled fd or a hung NFS fd.

For instance, as noted on the uAPI Group page [0], an untrusted peer
could send a file descriptor pointing to a hung NFS mount and then
close it.  Once the receiver calls recvmsg() with msg_control, the
descriptor is automatically installed, and then the responsibility
for the final close() now falls on the receiver, which may result
in blocking the process for a long time.

Regarding this, systemd calls cmsg_close_all() [1] after each
recvmsg() to close() unwanted file descriptors sent via SCM_RIGHTS.

However, this cannot work around the issue at all, because the final
fput() may still occur on the receiver's side once sendmsg() with
SCM_RIGHTS succeeds.  Also, even filtering by LSM at recvmsg() does
not work for the same reason.

Thus, we need a better way to refuse SCM_RIGHTS at sendmsg().

Let's introduce SO_PASSRIGHTS to disable SCM_RIGHTS.

Note that this option is enabled by default for backward
compatibility.

Link: https://uapi-group.org/kernel-features/#disabling-reception-of-scm_rights-for-af_unix-sockets #[0]
Link: https://github.com/systemd/systemd/blob/v257.5/src/basic/fd-util.c#L612-L628

 #[1]
Signed-off-by: default avatarKuniyuki Iwashima <kuniyu@amazon.com>
Reviewed-by: default avatarWillem de Bruijn <willemb@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 3f84d577
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -150,6 +150,8 @@

#define SO_RCVPRIORITY		82

#define SO_PASSRIGHTS		83

#if !defined(__KERNEL__)

#if __BITS_PER_LONG == 64
+2 −0
Original line number Diff line number Diff line
@@ -161,6 +161,8 @@

#define SO_RCVPRIORITY		82

#define SO_PASSRIGHTS		83

#if !defined(__KERNEL__)

#if __BITS_PER_LONG == 64
+2 −0
Original line number Diff line number Diff line
@@ -142,6 +142,8 @@
#define SCM_DEVMEM_DMABUF	SO_DEVMEM_DMABUF
#define SO_DEVMEM_DONTNEED	0x4050

#define SO_PASSRIGHTS		0x4051

#if !defined(__KERNEL__)

#if __BITS_PER_LONG == 64
+2 −0
Original line number Diff line number Diff line
@@ -143,6 +143,8 @@

#define SO_RCVPRIORITY           0x005b

#define SO_PASSRIGHTS            0x005c

#if !defined(__KERNEL__)


+3 −1
Original line number Diff line number Diff line
@@ -341,6 +341,7 @@ struct sk_filter;
  *	@sk_scm_credentials: flagged by SO_PASSCRED to recv SCM_CREDENTIALS
  *	@sk_scm_security: flagged by SO_PASSSEC to recv SCM_SECURITY
  *	@sk_scm_pidfd: flagged by SO_PASSPIDFD to recv SCM_PIDFD
  *	@sk_scm_rights: flagged by SO_PASSRIGHTS to recv SCM_RIGHTS
  *	@sk_scm_unused: unused flags for scm_recv()
  *	@ns_tracker: tracker for netns reference
  *	@sk_user_frags: xarray of pages the user is holding a reference on.
@@ -535,7 +536,8 @@ struct sock {
			u8	sk_scm_credentials : 1,
				sk_scm_security : 1,
				sk_scm_pidfd : 1,
				sk_scm_unused : 5;
				sk_scm_rights : 1,
				sk_scm_unused : 4;
		};
	};
	u8			sk_clockid;
Loading