tech-net archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Calculation of IPv6 fragmented part length



Hello,

The current kernel tries to calculate the fragmented part length by ntohs(ip6->ip6_plen) - offset) and it checks if it is zero, but the calculation is incorrect.

Then the current kernel drops a IPv6 packet which consists of 40 octets IPv6 header, 8 octets Fragment Header, and 32 octets fragmented part.

The following changes will resolve the problem.
Please review & consider to apply it.

I did not import the code from FreeBSD to resolve it, because FreeBSD checks zero length fragment after handling atomic fragment.
FreeBSD would pass a zero length fragment with M flag = 0 and Fragment Offset = 0 to upper layer processing ( I did not test it, though).
It would be better to drop such packet without passing it to upper layer.

Best regards,


Index: sys/netinet6/frag6.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/frag6.c,v
retrieving revision 1.77
diff -u -p -r1.77 frag6.c
--- sys/netinet6/frag6.c	29 Aug 2023 17:01:35 -0000	1.77
+++ sys/netinet6/frag6.c	14 Apr 2024 13:42:43 -0000
@@ -206,9 +206,11 @@ frag6_input(struct mbuf **mp, int *offp,
 	 * sizeof(struct ip6_frag) == 8
 	 * sizeof(struct ip6_hdr) = 40
 	 */
-	if ((ip6f->ip6f_offlg & IP6F_MORE_FRAG) &&
-	    (((ntohs(ip6->ip6_plen) - offset) == 0) ||
-	     ((ntohs(ip6->ip6_plen) - offset) & 0x7) != 0)) {
+	frgpartlen = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen)
+			- offset - sizeof(struct ip6_frag);
+	if ((frgpartlen == 0) ||
+	    ((ip6f->ip6f_offlg & IP6F_MORE_FRAG) &&
+	     (frgpartlen & 0x7) != 0)) {
 		icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
 		    offsetof(struct ip6_hdr, ip6_plen));
 		in6_ifstat_inc(dstifp, ifs6_reass_fail);
@@ -316,7 +318,6 @@ frag6_input(struct mbuf **mp, int *offp,
 	 * in size. If it would exceed, discard the fragment and return an
 	 * ICMP error.
 	 */
-	frgpartlen = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) - offset;
 	if (q6->ip6q_unfrglen >= 0) {
 		/* The 1st fragment has already arrived. */
 		if (q6->ip6q_unfrglen + fragoff + frgpartlen > IPV6_MAXPACKET) {



Home | Main Index | Thread Index | Old Index