Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 16 Apr 2007 19:53:30 +0300
From:      Mike Makonnen <mtm@FreeBSD.Org>
To:        freebsd-net@freebsd.org
Subject:   inet6_rthdr_* functions fixes
Message-ID:  <20070416165330.GA1956@rogue.navcom.lan>

next in thread | raw e-mail | index | archive | help

--fdj2RfSjLxBAspz7
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi guys,

Please take a look at the attached patch. They fix some issues I found
while investigating the ping(8) PR (kern/99425). The behaviour of
these functions is documented in rfc3542.

Here are the details of the patch:
1. CMSG_NXTHDR(mhdr, cmsg) is supposed to dereference cmsg and return
   the next header in the chain. If cmsg is NULL it should return
   the first header. Currently if cmsg is NULL it doesn't compile,
   so I fixed it to return the first header if cmesg is NULL.
2. inet6_rth_(space|init|add) should do basic checking on their input
   to verify that the number of headers is between 0 and 127 inclusive.
   The second part of the patch to libc/net/rthdr.c addresses this issue.

Cheers.
-- 
Mike Makonnen          | GPG-KEY: http://people.freebsd.org/~mtm/mtm.asc
mmakonnen @ gmail.com | AC7B 5672 2D11 F4D0 EBF8  5279 5359 2B82 7CD4 1F55
mtm @ FreeBSD.Org     | FreeBSD - http://www.freebsd.org

--fdj2RfSjLxBAspz7
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="rthdr.diff"

Index: lib/libc/net/rthdr.c
===================================================================
RCS file: /home/ncvs/src/lib/libc/net/rthdr.c,v
retrieving revision 1.8
diff -u -u -r1.8 rthdr.c
--- lib/libc/net/rthdr.c	19 Jul 2005 18:13:58 -0000	1.8
+++ lib/libc/net/rthdr.c	15 Apr 2007 19:35:32 -0000
@@ -292,7 +292,9 @@
 {
 	switch (type) {
 	case IPV6_RTHDR_TYPE_0:
-		return (((segments * 2) + 1) << 3);
+		if ((segments >= 0) && (segments <= 127))
+			return (((segments * 2) + 1) << 3);
+		/* FALLTHROUGH */
 	default:
 		return (0);	/* type not suppported */
 	}
@@ -309,6 +311,9 @@
 		/* length validation */
 		if (bp_len < inet6_rth_space(IPV6_RTHDR_TYPE_0, segments))
 			return (NULL);
+		/* segment validation */
+		if ((segments < 0) || (segments > 127))
+			return (NULL);
 
 		memset(bp, 0, bp_len);
 		rth0 = (struct ip6_rthdr0 *)rth;
@@ -334,6 +339,9 @@
 	switch (rth->ip6r_type) {
 	case IPV6_RTHDR_TYPE_0:
 		rth0 = (struct ip6_rthdr0 *)rth;
+		/* Don't exceed the number of stated segments */
+		if (rth0->ip6r0_segleft == (rth0->ip6r0_len / 2))
+			return (-1);
 		nextaddr = (struct in6_addr *)(rth0 + 1) + rth0->ip6r0_segleft;
 		*nextaddr = *addr;
 		rth0->ip6r0_segleft++;
Index: sys/sys/socket.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/socket.h,v
retrieving revision 1.92
diff -u -u -r1.92 socket.h
--- sys/sys/socket.h	3 Nov 2006 15:23:16 -0000	1.92
+++ sys/sys/socket.h	15 Apr 2007 14:53:04 -0000
@@ -471,11 +471,13 @@
 
 /* given pointer to struct cmsghdr, return pointer to next cmsghdr */
 #define	CMSG_NXTHDR(mhdr, cmsg)	\
-	(((char *)(cmsg) + _ALIGN((cmsg)->cmsg_len) + \
+	((char *)(cmsg) == NULL ? CMSG_FIRSTHDR(mhdr) : \
+	    ((char *)(cmsg) + _ALIGN(((struct cmsghdr *)(cmsg))->cmsg_len) + \
 	  _ALIGN(sizeof(struct cmsghdr)) > \
 	    (char *)(mhdr)->msg_control + (mhdr)->msg_controllen) ? \
 	    (struct cmsghdr *)0 : \
-	    (struct cmsghdr *)((char *)(cmsg) + _ALIGN((cmsg)->cmsg_len)))
+	    (struct cmsghdr *)((char *)(cmsg) + \
+	    _ALIGN(((struct cmsghdr *)(cmsg))->cmsg_len)))
 
 /*
  * RFC 2292 requires to check msg_controllen, in case that the kernel returns

--fdj2RfSjLxBAspz7--



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