summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2008-03-31 21:15:21 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2008-03-31 21:15:21 +0000
commit5e57860b5b6bb1b876fafcb53bbe18340a2e9c82 (patch)
treeb1a290d4aa4d62e72e341a81fd3cde448e924603
parentc7765a3d7fab8b1fc3febf3f78c92a458b7a20fc (diff)
strictly interpret msg_controllen to be the exact total length of the
cmsg's, including alignments, ie. the sum of CMSG_SPACE()'s. any other interpretation would be in violation of various unix specifications. RFC3542 section 20.2 is totally and completely wrong -- it is not allowed to over-ride the specification of msg_controllen, since the intent is that one could mix-and-match various types of cmsg's and an exact match is therefore required. ok kettenis, tested by many
-rw-r--r--sys/netinet6/ip6_output.c36
1 files changed, 20 insertions, 16 deletions
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index 896edec236f..cca6865818d 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip6_output.c,v 1.99 2007/06/01 00:52:38 henning Exp $ */
+/* $OpenBSD: ip6_output.c,v 1.100 2008/03/31 21:15:20 deraadt Exp $ */
/* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */
/*
@@ -2689,7 +2689,10 @@ ip6_setpktopts(control, opt, stickyopt, priv, uproto)
struct ip6_pktopts *opt, *stickyopt;
int priv, uproto;
{
+ u_int clen;
struct cmsghdr *cm = 0;
+ caddr_t cmsgs;
+ int error;
if (control == NULL || opt == NULL)
return (EINVAL);
@@ -2718,24 +2721,25 @@ ip6_setpktopts(control, opt, stickyopt, priv, uproto)
if (control->m_next)
return (EINVAL);
- for (; control->m_len; control->m_data += CMSG_ALIGN(cm->cmsg_len),
- control->m_len -= CMSG_ALIGN(cm->cmsg_len)) {
- int error;
-
- if (control->m_len < CMSG_LEN(0))
+ clen = control->m_len;
+ cmsgs = mtod(control, caddr_t);
+ do {
+ if (clen < CMSG_LEN(0))
return (EINVAL);
-
- cm = mtod(control, struct cmsghdr *);
- if (cm->cmsg_len == 0 || cm->cmsg_len > control->m_len)
+ cm = (struct cmsghdr *)cmsgs;
+ if (cm->cmsg_len < CMSG_LEN(0) ||
+ CMSG_ALIGN(cm->cmsg_len) > clen)
return (EINVAL);
- if (cm->cmsg_level != IPPROTO_IPV6)
- continue;
+ if (cm->cmsg_level == IPPROTO_IPV6) {
+ error = ip6_setpktopt(cm->cmsg_type, CMSG_DATA(cm),
+ cm->cmsg_len - CMSG_LEN(0), opt, priv, 0, 1, uproto);
+ if (error)
+ return (error);
+ }
- error = ip6_setpktopt(cm->cmsg_type, CMSG_DATA(cm),
- cm->cmsg_len - CMSG_LEN(0), opt, priv, 0, 1, uproto);
- if (error)
- return (error);
- }
+ clen -= CMSG_ALIGN(cm->cmsg_len);
+ cmsgs += CMSG_ALIGN(cm->cmsg_len);
+ } while (clen);
return (0);
}