Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 4 Aug 2018 20:26:55 +0000 (UTC)
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r337328 - in head/sys: kern sys
Message-ID:  <201808042026.w74KQt6V006467@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: markj
Date: Sat Aug  4 20:26:54 2018
New Revision: 337328
URL: https://svnweb.freebsd.org/changeset/base/337328

Log:
  Don't check rcv sockbuf limits when sending on a unix stream socket.
  
  sosend_generic() performs an initial comparison of the amount of data
  (including control messages) to be transmitted with the send buffer
  size. When transmitting on a unix socket, we then compare the amount
  of data being sent with the amount of space in the receive buffer size;
  if insufficient space is available, sbappendcontrol() returns an error
  and the data is lost.  This is easily triggered by sending control
  messages together with an amount of data roughly equal to the send
  buffer size, since the control message size may change in uipc_send()
  as file descriptors are internalized.
  
  Fix the problem by removing the space check in sbappendcontrol(),
  whose only consumer is the unix sockets code.  The stream sockets code
  uses the SB_STOP mechanism to ensure that senders will block if the
  receive buffer fills up.
  
  PR:		181741
  MFC after:	1 month
  Sponsored by:	The FreeBSD Foundation
  Differential Revision:	https://reviews.freebsd.org/D16515

Modified:
  head/sys/kern/uipc_sockbuf.c
  head/sys/kern/uipc_usrreq.c
  head/sys/sys/sockbuf.h

Modified: head/sys/kern/uipc_sockbuf.c
==============================================================================
--- head/sys/kern/uipc_sockbuf.c	Sat Aug  4 20:16:36 2018	(r337327)
+++ head/sys/kern/uipc_sockbuf.c	Sat Aug  4 20:26:54 2018	(r337328)
@@ -955,21 +955,14 @@ sbappendaddr(struct sockbuf *sb, const struct sockaddr
 	return (retval);
 }
 
-int
+void
 sbappendcontrol_locked(struct sockbuf *sb, struct mbuf *m0,
     struct mbuf *control)
 {
-	struct mbuf *m, *n, *mlast;
-	int space;
+	struct mbuf *m, *mlast;
 
-	SOCKBUF_LOCK_ASSERT(sb);
-
-	space = m_length(control, &n) + m_length(m0, NULL);
-
-	if (space > sbspace(sb))
-		return (0);
 	m_clrprotoflags(m0);
-	n->m_next = m0;			/* concatenate data to control */
+	m_last(control)->m_next = m0;
 
 	SBLASTRECORDCHK(sb);
 
@@ -983,18 +976,15 @@ sbappendcontrol_locked(struct sockbuf *sb, struct mbuf
 	SBLASTMBUFCHK(sb);
 
 	SBLASTRECORDCHK(sb);
-	return (1);
 }
 
-int
+void
 sbappendcontrol(struct sockbuf *sb, struct mbuf *m0, struct mbuf *control)
 {
-	int retval;
 
 	SOCKBUF_LOCK(sb);
-	retval = sbappendcontrol_locked(sb, m0, control);
+	sbappendcontrol_locked(sb, m0, control);
 	SOCKBUF_UNLOCK(sb);
-	return (retval);
 }
 
 /*

Modified: head/sys/kern/uipc_usrreq.c
==============================================================================
--- head/sys/kern/uipc_usrreq.c	Sat Aug  4 20:16:36 2018	(r337327)
+++ head/sys/kern/uipc_usrreq.c	Sat Aug  4 20:26:54 2018	(r337328)
@@ -1174,16 +1174,22 @@ uipc_send(struct socket *so, int flags, struct mbuf *m
 			unp2->unp_flags &= ~UNP_WANTCRED;
 			control = unp_addsockcred(td, control);
 		}
+
 		/*
-		 * Send to paired receive port, and then reduce send buffer
-		 * hiwater marks to maintain backpressure.  Wake up readers.
+		 * Send to paired receive port and wake up readers.  Don't
+		 * check for space available in the receive buffer if we're
+		 * attaching ancillary data; Unix domain sockets only check
+		 * for space in the sending sockbuf, and that check is
+		 * performed one level up the stack.  At that level we cannot
+		 * precisely account for the amount of buffer space used
+		 * (e.g., because control messages are not yet internalized).
 		 */
 		switch (so->so_type) {
 		case SOCK_STREAM:
 			if (control != NULL) {
-				if (sbappendcontrol_locked(&so2->so_rcv, m,
-				    control))
-					control = NULL;
+				sbappendcontrol_locked(&so2->so_rcv, m,
+				    control);
+				control = NULL;
 			} else
 				sbappend_locked(&so2->so_rcv, m, flags);
 			break;
@@ -1192,14 +1198,8 @@ uipc_send(struct socket *so, int flags, struct mbuf *m
 			const struct sockaddr *from;
 
 			from = &sun_noname;
-			/*
-			 * Don't check for space available in so2->so_rcv.
-			 * Unix domain sockets only check for space in the
-			 * sending sockbuf, and that check is performed one
-			 * level up the stack.
-			 */
 			if (sbappendaddr_nospacecheck_locked(&so2->so_rcv,
-				from, m, control))
+			    from, m, control))
 				control = NULL;
 			break;
 			}

Modified: head/sys/sys/sockbuf.h
==============================================================================
--- head/sys/sys/sockbuf.h	Sat Aug  4 20:16:36 2018	(r337327)
+++ head/sys/sys/sockbuf.h	Sat Aug  4 20:26:54 2018	(r337328)
@@ -139,9 +139,9 @@ int	sbappendaddr_locked(struct sockbuf *sb, const stru
 	    struct mbuf *m0, struct mbuf *control);
 int	sbappendaddr_nospacecheck_locked(struct sockbuf *sb,
 	    const struct sockaddr *asa, struct mbuf *m0, struct mbuf *control);
-int	sbappendcontrol(struct sockbuf *sb, struct mbuf *m0,
+void	sbappendcontrol(struct sockbuf *sb, struct mbuf *m0,
 	    struct mbuf *control);
-int	sbappendcontrol_locked(struct sockbuf *sb, struct mbuf *m0,
+void	sbappendcontrol_locked(struct sockbuf *sb, struct mbuf *m0,
 	    struct mbuf *control);
 void	sbappendrecord(struct sockbuf *sb, struct mbuf *m0);
 void	sbappendrecord_locked(struct sockbuf *sb, struct mbuf *m0);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201808042026.w74KQt6V006467>