From b79eceb7f37331e0724c1eb4b575b3b779b8a47b Mon Sep 17 00:00:00 2001 From: mtm Date: Thu, 19 Apr 2007 15:48:16 +0000 Subject: Make inet6_rth_* family of functions more compliant with RFC3542: 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, behaving essentially like CMSG_FIRSTHDR(). 2. inet6_rth_(space|init|add) should do basic checking on their input to verify that the number of headers (segments) is between 0 and 127 inclusive. MFC-After: 1 month --- lib/libc/net/rthdr.c | 10 +++++++++- sys/sys/socket.h | 6 ++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/libc/net/rthdr.c b/lib/libc/net/rthdr.c index 5fbb4bb..f92fdec 100644 --- a/lib/libc/net/rthdr.c +++ b/lib/libc/net/rthdr.c @@ -292,7 +292,9 @@ inet6_rth_space(int type, int segments) { 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 @@ inet6_rth_init(void *bp, socklen_t bp_len, int type, int segments) /* 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 @@ inet6_rth_add(void *bp, const struct in6_addr *addr) 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++; diff --git a/sys/sys/socket.h b/sys/sys/socket.h index 8d0bab2..ac1b1ed 100644 --- a/sys/sys/socket.h +++ b/sys/sys/socket.h @@ -471,11 +471,13 @@ struct sockcred { /* 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 -- cgit v1.1