Subject: kern/16990: soreceive violates invariant for UDP if uiomove encounters an error
To: None <gnats-bugs@gnats.netbsd.org>
From: None <gdt@bbn.com>
List: netbsd-bugs
Date: 05/23/2002 14:51:54
>Number:         16990
>Category:       kern
>Synopsis:       soreceive violates invariant for UDP if uiomove encounters an error
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu May 23 11:53:01 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator:     Greg Troxel
>Release:        NetBSD 1.5.3_RC1
>Organization:
        BBN Technologies
>Environment:
	
	
System: NetBSD lab.q.bbn.com 1.5.3_RC1 NetBSD 1.5.3_RC1 (QUISTCVS) #9: Thu Mar 14 07:32:28 EST 2002 gdt@lab.q.bbn.com:/home/gdt/QUIST-current/netbsd/src/sys/arch/i386/compile/QUISTCVS i386
Architecture: i386
Machine: i386
>Description:
The function sys/kern/uipc_socket.c:soreceive() does not to handle
errors in uiomove properly.  In datagram sockets, this can violate the
socket receive buffer invariant, which essentially requires a record
with the peer's address and then a record with data.

At line 761, it is possible for uiomove to return an error.  In that
case, the MT_SONAME mbuf has already been removed and passed to the
caller (wich presumably sys/kern/uipc_syscalls.c:sys_recvfrom()).
Thus, the socket buffer can be left in an inconsistent state, with the
MT_SONAME mbuf removed but the MT_DATA mbuf remaining.  This will
cause a panic on the next recvfrom call (if DIAGNOSTIC is defined).

Also, at line 791, it seems that only some of the data is consumed.
But the MT_SONAME mbuf is gone, so this seems to be an inconsistent
state.  The sbdroprecord call on 837 is apparently to delete rest of
datagram if less was requested than datagram length, and thus preserve
the invariant.  But the interaction between this invariant-preserving
code and the while loop at 818 is not clear to me.  It seems the while
loop only operates on non-atomic sockets.

>How-To-Repeat:

Compile a kernel with DIAGNOSTIC.  Modify a program that calls
recvfrom on a UDP socket to pass in NULL for the buffer.  uiomove will
fail, and the next call triggers a panic ("soreceive 1a").

>Fix:
Apply the following:

Index: src/sys/kern/uipc_socket.c
===================================================================
RCS file: /QUIST-CVS/netbsd/src/sys/kern/uipc_socket.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- src/sys/kern/uipc_socket.c	2001/11/12 15:47:56	1.1.1.1
+++ src/sys/kern/uipc_socket.c	2002/05/01 18:14:47	1.2
@@ -757,8 +757,22 @@
 			splx(s);
 			error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio);
 			s = splsoftnet();
-			if (error)
+			if (error) {
+				/*
+				 * The MT_SONAME mbuf has already been removed
+				 * from the record, so it is necessary to
+				 * remove the data mbufs, if any, to preserve
+				 * the invariant in the case of PR_ADDR that
+				 * requires MT_SONAME mbufs at the head of
+				 * each record.
+				 */
+				if (m && pr->pr_flags & PR_ATOMIC
+				    && ((flags & MSG_PEEK) == 0)) {
+					printf("soreceive uio droprecord\n");
+					(void) sbdroprecord(&so->so_rcv);
+				}
 				goto release;
+			}
 		} else
 			uio->uio_resid -= len;
 		if (len == m->m_len - moff) {



>Release-Note:
>Audit-Trail:
>Unformatted:
 soreceive violates invariant for UDP if uiomove encounters an error
 sw-bug
 	
 	
 netbsd-1-5 as of 20020510