kern/99779: kernel panic due to Invlalid next packet identification in soreceive()

JINMEI Tatuya jinmei at isl.rdc.toshiba.co.jp
Tue Jul 4 12:20:25 UTC 2006


>Number:         99779
>Category:       kern
>Synopsis:       kernel panic due to Invlalid next packet identification in soreceive()
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Jul 04 12:20:23 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     JINMEI Tatuya
>Release:        FreeBSD 6.1-RELEASE-p2 i386
>Organization:
Toshiba Corporation / KAME Project
>Environment:
System: FreeBSD opera.isl.rdc.toshiba.co.jp 6.1-RELEASE-p2 FreeBSD 6.1-RELEASE-p2 #2: Tue Jul 4 20:29:29 JST 2006 jinmei at opera.isl.rdc.toshiba.co.jp:/local/usr.local/freebsd/src/sys/i386/compile/GENERIC i386


Intel Pentium 4 1.7GHZ, FreeBSD 6.1R, no particular patch
>Description:
If an AF_INET6 socket receives an empty packet with ancillary data
object, soreceive() will point to a bogus place in the socket buffer,
which can subsequenlty causes kernel panic.  Such an empty packet
can be sent to the socket by the use of the IPv6 IPV6_RECVPATHMTU
socket option.

Any non-privileged user can (potentially) trigger this bug.
	
>How-To-Repeat:
Compile the following code, set the MTU of the loopback interface
to some small value (e.g., 1500) by
# ifconfig lo0 mtu 1500
and then run this program.

#include <sys/types.h>
#include <sys/socket.h>

#include <netinet/in.h>

#include <netdb.h>

main() {
	int cc, s, on, error;
	char buf[4096];
	struct addrinfo *res, hints;
	struct sockaddr_in6 from;
	socklen_t fromlen;

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_INET6;
	hints.ai_socktype = SOCK_DGRAM;
	hints.ai_protocol = IPPROTO_UDP;
	getaddrinfo("::1", "5000", &hints, &res);
	s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);

	on = 1;
	if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPATHMTU, &on, sizeof(on))
	    != 0) {
		perror("setsockopt(IPV6_RECVPATHMTU)");
		exit(1);
	}

	on = 1;
	if (setsockopt(s, IPPROTO_IPV6, IPV6_DONTFRAG, &on, sizeof(on)) != 0) {
		perror("setsockopt(IPV6_DONTFRAG)");
		exit(1);
	}

	if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {
		perror("bind");
		exit(1);
	}

	cc = sendto(s, buf, sizeof(buf), 0, res->ai_addr, res->ai_addrlen);
	if (cc < 0)
		perror("sendto");

	fromlen = sizeof(from);
	cc = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *)&from,
	    &fromlen);
	if (cc < 0)
		perror("recvfrom");

	exit(0);
}

>Fix:

A patch that fixes the problem is attached below.  FreeBSD 5.x also seems
to have the same bug.

--- uipc_socket.c	Tue Jul  4 20:29:16 2006
+++ uipc_socket.c.new	Mon Jul  3 14:04:42 2006
@@ -1169,7 +1169,10 @@
 			}
 			cm = cmn;
 		}
-		nextrecord = so->so_rcv.sb_mb->m_nextpkt;
+		if (m != NULL)
+			nextrecord = so->so_rcv.sb_mb->m_nextpkt;
+		else
+			nextrecord = so->so_rcv.sb_mb;
 		orig_resid = 0;
 	}
 	if (m != NULL) {

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list