Fri Apr 19 05:04:06 2024 UTC (21d)
frag6: fix calculation of fragment length

Because of the miscalculation, 32 bytes fragmented IPv6 packets
have been wrongly dropped.

See https://mail-index.netbsd.org/tech-net/2024/04/14/msg008741.html
for more details.

Patch from Yasuyuki KOZAKAI (with minor tweaks)


(ozaki-r)
diff -r1.77 -r1.78 src/sys/netinet6/frag6.c

cvs diff -r1.77 -r1.78 src/sys/netinet6/frag6.c (expand / switch to unified diff)

--- src/sys/netinet6/frag6.c 2023/08/29 17:01:35 1.77
+++ src/sys/netinet6/frag6.c 2024/04/19 05:04:06 1.78
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: frag6.c,v 1.77 2023/08/29 17:01:35 christos Exp $ */ 1/* $NetBSD: frag6.c,v 1.78 2024/04/19 05:04:06 ozaki-r Exp $ */
2/* $KAME: frag6.c,v 1.40 2002/05/27 21:40:31 itojun Exp $ */ 2/* $KAME: frag6.c,v 1.40 2002/05/27 21:40:31 itojun Exp $ */
3 3
4/* 4/*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
8 * Redistribution and use in source and binary forms, with or without 8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions 9 * modification, are permitted provided that the following conditions
10 * are met: 10 * are met:
11 * 1. Redistributions of source code must retain the above copyright 11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer. 12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright 13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the 14 * notice, this list of conditions and the following disclaimer in the
@@ -21,27 +21,27 @@ @@ -21,27 +21,27 @@
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE. 30 * SUCH DAMAGE.
31 */ 31 */
32 32
33#include <sys/cdefs.h> 33#include <sys/cdefs.h>
34__KERNEL_RCSID(0, "$NetBSD: frag6.c,v 1.77 2023/08/29 17:01:35 christos Exp $"); 34__KERNEL_RCSID(0, "$NetBSD: frag6.c,v 1.78 2024/04/19 05:04:06 ozaki-r Exp $");
35 35
36#ifdef _KERNEL_OPT 36#ifdef _KERNEL_OPT
37#include "opt_net_mpsafe.h" 37#include "opt_net_mpsafe.h"
38#endif 38#endif
39 39
40#include <sys/param.h> 40#include <sys/param.h>
41#include <sys/systm.h> 41#include <sys/systm.h>
42#include <sys/mbuf.h> 42#include <sys/mbuf.h>
43#include <sys/errno.h> 43#include <sys/errno.h>
44#include <sys/time.h> 44#include <sys/time.h>
45#include <sys/kmem.h> 45#include <sys/kmem.h>
46#include <sys/kernel.h> 46#include <sys/kernel.h>
47#include <sys/syslog.h> 47#include <sys/syslog.h>
@@ -196,29 +196,30 @@ frag6_input(struct mbuf **mp, int *offp, @@ -196,29 +196,30 @@ frag6_input(struct mbuf **mp, int *offp,
196 /* jumbo payload can't contain a fragment header */ 196 /* jumbo payload can't contain a fragment header */
197 if (ip6->ip6_plen == 0) { 197 if (ip6->ip6_plen == 0) {
198 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset); 198 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset);
199 in6_ifstat_inc(dstifp, ifs6_reass_fail); 199 in6_ifstat_inc(dstifp, ifs6_reass_fail);
200 goto done; 200 goto done;
201 } 201 }
202 202
203 /* 203 /*
204 * Check whether fragment packet's fragment length is non-zero and 204 * Check whether fragment packet's fragment length is non-zero and
205 * multiple of 8 octets. 205 * multiple of 8 octets.
206 * sizeof(struct ip6_frag) == 8 206 * sizeof(struct ip6_frag) == 8
207 * sizeof(struct ip6_hdr) = 40 207 * sizeof(struct ip6_hdr) = 40
208 */ 208 */
209 if ((ip6f->ip6f_offlg & IP6F_MORE_FRAG) && 209 frgpartlen = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) - offset
210 (((ntohs(ip6->ip6_plen) - offset) == 0) || 210 - sizeof(struct ip6_frag);
211 ((ntohs(ip6->ip6_plen) - offset) & 0x7) != 0)) { 211 if ((frgpartlen == 0) ||
 212 ((ip6f->ip6f_offlg & IP6F_MORE_FRAG) && (frgpartlen & 0x7) != 0)) {
212 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, 213 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
213 offsetof(struct ip6_hdr, ip6_plen)); 214 offsetof(struct ip6_hdr, ip6_plen));
214 in6_ifstat_inc(dstifp, ifs6_reass_fail); 215 in6_ifstat_inc(dstifp, ifs6_reass_fail);
215 goto done; 216 goto done;
216 } 217 }
217 218
218 IP6_STATINC(IP6_STAT_FRAGMENTS); 219 IP6_STATINC(IP6_STAT_FRAGMENTS);
219 in6_ifstat_inc(dstifp, ifs6_reass_reqd); 220 in6_ifstat_inc(dstifp, ifs6_reass_reqd);
220 221
221 /* offset now points to data portion */ 222 /* offset now points to data portion */
222 offset += sizeof(struct ip6_frag); 223 offset += sizeof(struct ip6_frag);
223 224
224 /* 225 /*
@@ -306,27 +307,26 @@ frag6_input(struct mbuf **mp, int *offp, @@ -306,27 +307,26 @@ frag6_input(struct mbuf **mp, int *offp,
306 * unfragmentable part and the next header of the fragment header. 307 * unfragmentable part and the next header of the fragment header.
307 */ 308 */
308 if (fragoff == 0) { 309 if (fragoff == 0) {
309 q6->ip6q_unfrglen = offset - sizeof(struct ip6_hdr) - 310 q6->ip6q_unfrglen = offset - sizeof(struct ip6_hdr) -
310 sizeof(struct ip6_frag); 311 sizeof(struct ip6_frag);
311 q6->ip6q_nxt = ip6f->ip6f_nxt; 312 q6->ip6q_nxt = ip6f->ip6f_nxt;
312 } 313 }
313 314
314 /* 315 /*
315 * Check that the reassembled packet would not exceed 65535 bytes 316 * Check that the reassembled packet would not exceed 65535 bytes
316 * in size. If it would exceed, discard the fragment and return an 317 * in size. If it would exceed, discard the fragment and return an
317 * ICMP error. 318 * ICMP error.
318 */ 319 */
319 frgpartlen = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) - offset; 
320 if (q6->ip6q_unfrglen >= 0) { 320 if (q6->ip6q_unfrglen >= 0) {
321 /* The 1st fragment has already arrived. */ 321 /* The 1st fragment has already arrived. */
322 if (q6->ip6q_unfrglen + fragoff + frgpartlen > IPV6_MAXPACKET) { 322 if (q6->ip6q_unfrglen + fragoff + frgpartlen > IPV6_MAXPACKET) {
323 mutex_exit(&frag6_lock); 323 mutex_exit(&frag6_lock);
324 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, 324 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
325 offset - sizeof(struct ip6_frag) + 325 offset - sizeof(struct ip6_frag) +
326 offsetof(struct ip6_frag, ip6f_offlg)); 326 offsetof(struct ip6_frag, ip6f_offlg));
327 goto done; 327 goto done;
328 } 328 }
329 } else if (fragoff + frgpartlen > IPV6_MAXPACKET) { 329 } else if (fragoff + frgpartlen > IPV6_MAXPACKET) {
330 mutex_exit(&frag6_lock); 330 mutex_exit(&frag6_lock);
331 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, 331 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
332 offset - sizeof(struct ip6_frag) + 332 offset - sizeof(struct ip6_frag) +