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>