Page MenuHomeFreeBSD

D19960.id170265.diff
No OneTemporary

D19960.id170265.diff

diff --git a/sys/netinet/ip6.h b/sys/netinet/ip6.h
--- a/sys/netinet/ip6.h
+++ b/sys/netinet/ip6.h
@@ -258,6 +258,7 @@
#define IPV6_MMTU 1280 /* minimal MTU and reassembly. 1024 + 256 */
#define IPV6_MAXPACKET 65535 /* ip6 max packet size without Jumbo payload*/
+#define IPV6_MAXPAYLOAD 65535 /* ip6 max payload size */
#define IPV6_MAXOPTHDR 2048 /* max option header size, 256 64-bit words */
#endif /* not _NETINET_IP6_H_ */
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -219,7 +219,7 @@
struct rmlock in6_ifaddr_lock;
RM_SYSINIT(in6_ifaddr_lock, &in6_ifaddr_lock, "in6_ifaddr_lock");
-static int ip6_hopopts_input(u_int32_t *, u_int32_t *, struct mbuf **, int *);
+static int ip6_hopopts_input(u_int32_t *, struct mbuf **, int *);
/*
* IP6 initialization: fill in IP6 protocol switch table.
@@ -408,14 +408,14 @@
#endif
static int
-ip6_input_hbh(struct mbuf **mp, uint32_t *plen, uint32_t *rtalert, int *off,
+ip6_input_hbh(struct mbuf **mp, uint32_t *rtalert, int *off,
int *nxt, int *ours)
{
struct mbuf *m;
struct ip6_hdr *ip6;
struct ip6_hbh *hbh;
- if (ip6_hopopts_input(plen, rtalert, mp, off)) {
+ if (ip6_hopopts_input(rtalert, mp, off)) {
#if 0 /*touches NULL pointer*/
in6_ifstat_inc((*mp)->m_pkthdr.rcvif, ifs6_in_discard);
#endif
@@ -427,16 +427,11 @@
ip6 = mtod(m, struct ip6_hdr *);
/*
- * if the payload length field is 0 and the next header field
- * indicates Hop-by-Hop Options header, then a Jumbo Payload
- * option MUST be included.
+ * If the payload length field is 0 and the next header field indicates
+ * Hop-by-Hop Options header, then a Jumbo Payload option MUST be
+ * included. We no not support Jumbo Payloads so report an error.
*/
- if (ip6->ip6_plen == 0 && *plen == 0) {
- /*
- * Note that if a valid jumbo payload option is
- * contained, ip6_hopopts_input() must set a valid
- * (non-zero) payload length to the variable plen.
- */
+ if (ip6->ip6_plen == 0) {
IP6STAT_INC(ip6s_badoptions);
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard);
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr);
@@ -775,6 +770,15 @@
goto bad;
}
+ plen = (u_int32_t)ntohs(ip6->ip6_plen);
+
+ /*
+ * We don't support Jumbograms, reject packets with plen == 0 as early
+ * as we can.
+ */
+ if (plen == 0)
+ goto bad;
+
/*
* Disambiguate address scope zones (if there is ambiguity).
* We first make sure that the original source or destination address
@@ -851,11 +855,9 @@
/*
* Process Hop-by-Hop options header if it's contained.
* m may be modified in ip6_hopopts_input().
- * If a JumboPayload option is included, plen will also be modified.
*/
- plen = (u_int32_t)ntohs(ip6->ip6_plen);
if (ip6->ip6_nxt == IPPROTO_HOPOPTS) {
- if (ip6_input_hbh(&m, &plen, &rtalert, &off, &nxt, &ours) != 0)
+ if (ip6_input_hbh(&m, &rtalert, &off, &nxt, &ours) != 0)
return;
} else
nxt = ip6->ip6_nxt;
@@ -964,13 +966,12 @@
/*
* Hop-by-Hop options header processing. If a valid jumbo payload option is
- * included, the real payload length will be stored in plenp.
+ * included report an error.
*
* rtalertp - XXX: should be stored more smart way
*/
static int
-ip6_hopopts_input(u_int32_t *plenp, u_int32_t *rtalertp,
- struct mbuf **mp, int *offp)
+ip6_hopopts_input(u_int32_t *rtalertp, struct mbuf **mp, int *offp)
{
struct mbuf *m = *mp;
int off = *offp, hbhlen;
@@ -1000,7 +1001,7 @@
off += hbhlen;
hbhlen -= sizeof(struct ip6_hbh);
if (ip6_process_hopopts(m, (u_int8_t *)hbh + sizeof(struct ip6_hbh),
- hbhlen, rtalertp, plenp) < 0) {
+ hbhlen, rtalertp) < 0) {
*mp = NULL;
return (-1);
}
@@ -1022,13 +1023,11 @@
*/
int
ip6_process_hopopts(struct mbuf *m, u_int8_t *opthead, int hbhlen,
- u_int32_t *rtalertp, u_int32_t *plenp)
+ u_int32_t *rtalertp)
{
- struct ip6_hdr *ip6;
int optlen = 0;
u_int8_t *opt = opthead;
u_int16_t rtalert_val;
- u_int32_t jumboplen;
const int erroff = sizeof(struct ip6_hdr) + sizeof(struct ip6_hbh);
for (; hbhlen > 0; hbhlen -= optlen, opt += optlen) {
@@ -1061,71 +1060,8 @@
*rtalertp = ntohs(rtalert_val);
break;
case IP6OPT_JUMBO:
- /* XXX may need check for alignment */
- if (hbhlen < IP6OPT_JUMBO_LEN) {
- IP6STAT_INC(ip6s_toosmall);
- goto bad;
- }
- if (*(opt + 1) != IP6OPT_JUMBO_LEN - 2) {
- /* XXX stat */
- icmp6_error(m, ICMP6_PARAM_PROB,
- ICMP6_PARAMPROB_HEADER,
- erroff + opt + 1 - opthead);
- return (-1);
- }
- optlen = IP6OPT_JUMBO_LEN;
-
- /*
- * IPv6 packets that have non 0 payload length
- * must not contain a jumbo payload option.
- */
- ip6 = mtod(m, struct ip6_hdr *);
- if (ip6->ip6_plen) {
- IP6STAT_INC(ip6s_badoptions);
- icmp6_error(m, ICMP6_PARAM_PROB,
- ICMP6_PARAMPROB_HEADER,
- erroff + opt - opthead);
- return (-1);
- }
-
- /*
- * We may see jumbolen in unaligned location, so
- * we'd need to perform bcopy().
- */
- bcopy(opt + 2, &jumboplen, sizeof(jumboplen));
- jumboplen = (u_int32_t)htonl(jumboplen);
-
-#if 1
- /*
- * if there are multiple jumbo payload options,
- * *plenp will be non-zero and the packet will be
- * rejected.
- * the behavior may need some debate in ipngwg -
- * multiple options does not make sense, however,
- * there's no explicit mention in specification.
- */
- if (*plenp != 0) {
- IP6STAT_INC(ip6s_badoptions);
- icmp6_error(m, ICMP6_PARAM_PROB,
- ICMP6_PARAMPROB_HEADER,
- erroff + opt + 2 - opthead);
- return (-1);
- }
-#endif
-
- /*
- * jumbo payload length must be larger than 65535.
- */
- if (jumboplen <= IPV6_MAXPACKET) {
- IP6STAT_INC(ip6s_badoptions);
- icmp6_error(m, ICMP6_PARAM_PROB,
- ICMP6_PARAMPROB_HEADER,
- erroff + opt + 2 - opthead);
- return (-1);
- }
- *plenp = jumboplen;
-
- break;
+ /* We do not support the Jumbo Payload option. */
+ goto bad;
default: /* unknown option */
if (hbhlen < IP6OPT_MINLEN) {
IP6STAT_INC(ip6s_toosmall);
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -142,7 +142,6 @@
static int ip6_copyexthdr(struct mbuf **, caddr_t, int);
static int ip6_insertfraghdr(struct mbuf *, struct mbuf *, int,
struct ip6_frag **);
-static int ip6_insert_jumboopt(struct ip6_exthdrs *, u_int32_t);
static int ip6_splithdr(struct mbuf *, struct ip6_exthdrs *);
static void ip6_getpmtu(struct route_in6 *, int,
struct ifnet *, const struct in6_addr *, u_long *, u_int, u_int);
@@ -542,21 +541,9 @@
m->m_pkthdr.len += optlen;
plen = m->m_pkthdr.len - sizeof(*ip6);
- /* If this is a jumbo payload, insert a jumbo payload option. */
if (plen > IPV6_MAXPACKET) {
- if (!hdrsplit) {
- if ((error = ip6_splithdr(m, &exthdrs)) != 0) {
- m = NULL;
- goto freehdrs;
- }
- m = exthdrs.ip6e_ip6;
- ip6 = mtod(m, struct ip6_hdr *);
- hdrsplit = true;
- }
- if ((error = ip6_insert_jumboopt(&exthdrs, plen)) != 0)
- goto freehdrs;
- ip6->ip6_plen = 0;
- optlen += 8; /* JUMBOOPTLEN */
+ error = EMSGSIZE;
+ goto freehdrs;
} else
ip6->ip6_plen = htons(plen);
nexthdrp = &ip6->ip6_nxt;
@@ -982,7 +969,6 @@
if (exthdrs.ip6e_hbh) {
struct ip6_hbh *hbh = mtod(exthdrs.ip6e_hbh, struct ip6_hbh *);
u_int32_t dummy; /* XXX unused */
- u_int32_t plen = 0; /* XXX: ip6_process will check the value */
#ifdef DIAGNOSTIC
if ((hbh->ip6h_len + 1) << 3 > exthdrs.ip6e_hbh->m_len)
@@ -998,7 +984,7 @@
m->m_pkthdr.rcvif = ifp;
if (ip6_process_hopopts(m, (u_int8_t *)(hbh + 1),
((hbh->ip6h_len + 1) << 3) - sizeof(struct ip6_hbh),
- &dummy, &plen) < 0) {
+ &dummy) < 0) {
/* m was already freed at this point. */
error = EINVAL;/* better error? */
goto done;
@@ -1186,7 +1172,7 @@
in6_ifstat_inc(ifp, ifs6_out_fragfail);
goto bad;
} else if (ip6->ip6_plen == 0) {
- /* Jumbo payload cannot be fragmented. */
+ /* We do not support jumbo payload. */
error = EMSGSIZE;
in6_ifstat_inc(ifp, ifs6_out_fragfail);
goto bad;
@@ -1312,94 +1298,6 @@
return (0);
}
-/*
- * Insert jumbo payload option.
- */
-static int
-ip6_insert_jumboopt(struct ip6_exthdrs *exthdrs, u_int32_t plen)
-{
- struct mbuf *mopt;
- u_char *optbuf;
- u_int32_t v;
-
-#define JUMBOOPTLEN 8 /* length of jumbo payload option and padding */
-
- /*
- * If there is no hop-by-hop options header, allocate new one.
- * If there is one but it doesn't have enough space to store the
- * jumbo payload option, allocate a cluster to store the whole options.
- * Otherwise, use it to store the options.
- */
- if (exthdrs->ip6e_hbh == NULL) {
- mopt = m_get(M_NOWAIT, MT_DATA);
- if (mopt == NULL)
- return (ENOBUFS);
- mopt->m_len = JUMBOOPTLEN;
- optbuf = mtod(mopt, u_char *);
- optbuf[1] = 0; /* = ((JUMBOOPTLEN) >> 3) - 1 */
- exthdrs->ip6e_hbh = mopt;
- } else {
- struct ip6_hbh *hbh;
-
- mopt = exthdrs->ip6e_hbh;
- if (M_TRAILINGSPACE(mopt) < JUMBOOPTLEN) {
- /*
- * XXX assumption:
- * - exthdrs->ip6e_hbh is not referenced from places
- * other than exthdrs.
- * - exthdrs->ip6e_hbh is not an mbuf chain.
- */
- int oldoptlen = mopt->m_len;
- struct mbuf *n;
-
- /*
- * XXX: give up if the whole (new) hbh header does
- * not fit even in an mbuf cluster.
- */
- if (oldoptlen + JUMBOOPTLEN > MCLBYTES)
- return (ENOBUFS);
-
- /*
- * As a consequence, we must always prepare a cluster
- * at this point.
- */
- n = m_getcl(M_NOWAIT, MT_DATA, 0);
- if (n == NULL)
- return (ENOBUFS);
- n->m_len = oldoptlen + JUMBOOPTLEN;
- bcopy(mtod(mopt, caddr_t), mtod(n, caddr_t),
- oldoptlen);
- optbuf = mtod(n, caddr_t) + oldoptlen;
- m_freem(mopt);
- mopt = exthdrs->ip6e_hbh = n;
- } else {
- optbuf = mtod(mopt, u_char *) + mopt->m_len;
- mopt->m_len += JUMBOOPTLEN;
- }
- optbuf[0] = IP6OPT_PADN;
- optbuf[1] = 1;
-
- /*
- * Adjust the header length according to the pad and
- * the jumbo payload option.
- */
- hbh = mtod(mopt, struct ip6_hbh *);
- hbh->ip6h_len += (JUMBOOPTLEN >> 3);
- }
-
- /* fill in the option. */
- optbuf[2] = IP6OPT_JUMBO;
- optbuf[3] = 4;
- v = (u_int32_t)htonl(plen + JUMBOOPTLEN);
- bcopy(&v, &optbuf[4], sizeof(u_int32_t));
-
- /* finally, adjust the packet header length */
- exthdrs->ip6e_ip6->m_pkthdr.len += JUMBOOPTLEN;
-
- return (0);
-#undef JUMBOOPTLEN
-}
-
/*
* Insert fragment header and copy unfragmentable header portions.
*/
diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h
--- a/sys/netinet6/ip6_var.h
+++ b/sys/netinet6/ip6_var.h
@@ -393,8 +393,7 @@
extern int (*ip6_mforward)(struct ip6_hdr *, struct ifnet *,
struct mbuf *);
-int ip6_process_hopopts(struct mbuf *, u_int8_t *, int, u_int32_t *,
- u_int32_t *);
+int ip6_process_hopopts(struct mbuf *, u_int8_t *, int, u_int32_t *);
struct mbuf **ip6_savecontrol_v4(struct inpcb *, struct mbuf *,
struct mbuf **, int *);
void ip6_savecontrol(struct inpcb *, struct mbuf *, struct mbuf **);
diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -703,11 +703,6 @@
sin6 = (struct sockaddr_in6 *)addr6;
- /*
- * In contrast to IPv4 we do not validate the max. packet length
- * here due to IPv6 Jumbograms (RFC2675).
- */
-
scope_ambiguous = 0;
if (sin6) {
/* Protect *addr6 from overwrites. */
@@ -865,10 +860,22 @@
fport = inp->inp_fport;
}
+
+ /*
+ * We do not support IPv6 Jumbograms (RFC2675), so validate the payload
+ * length fits in a normal gram.
+ */
ulen = m->m_pkthdr.len;
plen = sizeof(struct udphdr) + ulen;
hlen = sizeof(struct ip6_hdr);
+ if (plen > IPV6_MAXPAYLOAD) {
+ if (control)
+ m_freem(control);
+ m_freem(m);
+ return (EMSGSIZE);
+ }
+
/*
* Calculate data length and get a mbuf for UDP, IP6, and possible
* link-layer headers. Immediate slide the data pointer back forward
@@ -903,10 +910,9 @@
* the entire UDPLite packet is covered by the checksum.
*/
cscov_partial = (cscov == 0) ? 0 : 1;
- } else if (plen <= 0xffff)
+ } else {
udp6->uh_ulen = htons((u_short)plen);
- else
- udp6->uh_ulen = 0;
+ }
udp6->uh_sum = 0;
ip6 = mtod(m, struct ip6_hdr *);

File Metadata

Mime Type
text/plain
Expires
Tue, Jan 27, 2:18 AM (19 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28048431
Default Alt Text
D19960.id170265.diff (12 KB)

Event Timeline