diff options
| author | Tom Jones <thj@FreeBSD.org> | 2026-01-23 12:43:25 +0000 |
|---|---|---|
| committer | Tom Jones <thj@FreeBSD.org> | 2026-01-27 13:20:33 +0000 |
| commit | 069a67374ed9641ff1ada2aecaac1cc61a560649 (patch) | |
| tree | b2f3f80fadba7e83c3b9f87e5f6b3b7c8d5db8cc /sys/netinet6 | |
| parent | 823f158a01330484f83f69c31d695035c607f8ee (diff) | |
Diffstat (limited to 'sys/netinet6')
| -rw-r--r-- | sys/netinet6/ip6_input.c | 110 | ||||
| -rw-r--r-- | sys/netinet6/ip6_output.c | 110 | ||||
| -rw-r--r-- | sys/netinet6/ip6_var.h | 3 | ||||
| -rw-r--r-- | sys/netinet6/udp6_usrreq.c | 22 |
4 files changed, 42 insertions, 203 deletions
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index d914bfbcbdbf..a23f5d46d6a3 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -219,7 +219,7 @@ VNET_PCPUSTAT_SYSUNINIT(ip6stat); 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. @@ -407,14 +407,14 @@ VNET_SYSUNINIT(inet6, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, ip6_destroy, NULL); #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 @@ -426,16 +426,11 @@ ip6_input_hbh(struct mbuf **mp, uint32_t *plen, uint32_t *rtalert, int *off, 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); @@ -774,6 +769,15 @@ passin: goto bad; } + plen = (uint32_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 @@ -850,11 +854,9 @@ passin: /* * 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; @@ -963,13 +965,12 @@ bad: /* * 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; @@ -999,7 +1000,7 @@ ip6_hopopts_input(u_int32_t *plenp, u_int32_t *rtalertp, 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); } @@ -1021,13 +1022,11 @@ ip6_hopopts_input(u_int32_t *plenp, u_int32_t *rtalertp, */ 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) { @@ -1060,71 +1059,8 @@ ip6_process_hopopts(struct mbuf *m, u_int8_t *opthead, int hbhlen, *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 index a9b31ac8061f..dca1bcf04371 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -142,7 +142,6 @@ static int ip6_setpktopt(int, u_char *, int, struct ip6_pktopts *, 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 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, 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 @@ nonh6lookup: 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 @@ nonh6lookup: 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 @@ passout: 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; @@ -1313,94 +1299,6 @@ ip6_copyexthdr(struct mbuf **mp, caddr_t hdr, int hlen) } /* - * 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. */ static int diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index db1631736c4a..c1645f587483 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -393,8 +393,7 @@ int ip6_lasthdr(const struct mbuf *, int, int, int *); 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 index ca7c95497510..1d1dcb75a1df 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -703,11 +703,6 @@ udp6_send(struct socket *so, int flags_arg, struct mbuf *m, 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,21 @@ udp6_send(struct socket *so, int flags_arg, struct mbuf *m, 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) { + 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 +909,10 @@ udp6_send(struct socket *so, int flags_arg, struct mbuf *m, * the entire UDPLite packet is covered by the checksum. */ cscov_partial = (cscov == 0) ? 0 : 1; - } else if (plen <= 0xffff) + } else { + MPASS(plen <= IPV6_MAXPAYLOAD); udp6->uh_ulen = htons((u_short)plen); - else - udp6->uh_ulen = 0; + } udp6->uh_sum = 0; ip6 = mtod(m, struct ip6_hdr *); |
