From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=209.85.128.49 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1792605935; b=ILsUGE2ySeuTrpuOIvxreKnaZEqJk8dq6G5twRuqqLkQhMEm9yzzus02J2CryMsm2A3p M5Gs0YpYDtfG4u9pXn8Z18rp8ZKuSv9pP3GbejI1YpCSegZHNbpSqGwDffnQZ/XNJ+HaI Gad55DQO2Ct42a+3tU+N4ijT+jIkkK0juSM9dp9ct1ahsyIWBdUPaG+uP95JtZGil53zh gEVIzAAEjAur2rsGKaR6iWZ5bIP/cF2YNRYKqB0b9G5+HYenibtOTbMiwqlrR8aVaWtiD uojhoybasm9GsS144aHD4bGqKX5FW5SgmdFYUPthZh6kqqvhEn1QO/jCVI5zch+tIEw== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1792605935; h=DMARC-Filter:Received:DKIM-Signature:X-Google-DKIM-Signature: X-Forwarded-Encrypted:X-Gm-Message-State:X-Gm-Gg:X-Received:Received: From:To:Cc:Subject:Date:Message-ID:X-Mailer:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding; bh=36CIvPZFqSR3d1bRp5FOUkDzIh2a6VXH38LqlQMMHgo=; b=pskatD5hhM9fyPXYidFjXo2b6elhGvZRFAHi7qqtIOot7BdLMj5b2RXXtHEtbdSqWUAn NPSEahePG0hKc7fewavTnA4zDsArcRfAM7CrPVy65tJZ6ivnFeq/ClPPd7YyP9c9X4IG4 LitYy6Y6gx6G6rvyM+L3Da5B/38WjyjK0AaqoyKVEi9B+V5HaeYoLjHxPhvGpEiJB7xdc 7H35hT7N4MRwFdgrbZ+7cVgeh56lkXcO+urzYbg5Q/dOylqa2BmLCdVq5Vmf9zBPF0umU ROOTxF1BsrLvrsWs8PhWDzUHi28QpmBY7tzlINE802M3pUjOA9xWlnXFgBlFue01G4w== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20251104 header.b=qc4ZTUYU; arc=none smtp.remote-ip=209.85.128.49 Received: from mail-wm1-f49.google.com (mail-wm1-f49.google.com [209.85.128.49]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E941A606A322 for ; Wed, 21 Oct 2026 18:05:34 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org E941A606A322 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20251104 header.b=qc4ZTUYU Received: by mail-wm1-f49.google.com with SMTP id 5b1f17b1804b1-49d05d51553so7831635e9.2 for ; Wed, 21 Oct 2026 11:05:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1792605933; x=1793210733; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=36CIvPZFqSR3d1bRp5FOUkDzIh2a6VXH38LqlQMMHgo=; b=qc4ZTUYUtGBB48YloE+K0yBo9J5Ll7KjPH93H7mZt7pvpD0QD4DqCJEB+kKxPfziZA xlN0wB+iMjfxQvbswipWTCR3WZ7SCRmmc1D3tHgPnikQtaHeDP44PML6bUmtBLTbA6U3 UdTun/vxjIpnqBvAS1kpG6RmAEeRDNSx/knlx1t+N8SH4oPWEB8jW2V4t06LBprss9nA b5eRhKau1OqtphqKj9cS+O+hhE2tYWCeQH9ZUbz46Vk73rldwslq12AwYEn6SkZGN7/f LxjEPlpGYL4713pUWpZ+JPhuPWAjpVwpScOCEhkYnSId84tcd2vaJgQInXzvbNL8Td7f HwKg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1792605933; x=1793210733; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=36CIvPZFqSR3d1bRp5FOUkDzIh2a6VXH38LqlQMMHgo=; b=Nz9xlrPSrUGVCWLoVH69DzqQeHvI+s+mVvirgMOyfvbBGCXD7Vu8CaMcwQkXeiK8Wm LNdTIw+fKDaFnjOn9w0p9BaBeHjFYFW2KXTekNPZABj+lhBPIgjcv4NOCBLQ79HADN5W Z35rNpzJWVfLiL6dQuWDQR1AYErBfaUXEo5eduteNUTwI1VyYJ+8+ea4F+VpHzy31oXY lbGD1e/9frG9j1yMHFI+md7quzYR/RVdHkp4V7k4VPaDkSBm4RhojVTfRtKGQUN4eH49 yMqAq4kIcfiIPOZiiPPXNBgapOS4xcJd55qfY2WZaZH0pSnbmbksohSkmipI+Sk3VKTL hp8Q== X-Forwarded-Encrypted: i=1; AKwUvBzeOBeFMRKrTIVMLK0Rd0EGNHSruh0k9/wzHZV12QomR3jeNbumUeQG501+peQSIYLihluitVH4blnBaBg=@vger.kernel.org X-Gm-Message-State: AFq9FYLZxbBrRi7FrXSg86idFecF6Zh5GaQvUyUx7uzaX4l8bqD0LMii 7Lp5ONDnvDnnwe4zJTk9gWSOkh4w7OEQUNmaakb1l+VngfajTsXtPtdk X-Gm-Gg: AYBFou0BDzTnl+CuYj3f2AV1oWpj8AevQvnUu5ikBn0IezJa7OC1AuouStVWXb0bPVW UKcwknqFsYu426E5yMPYNtF5KeobhVWdxLQ9FqhpKAhoip/xYCJccl6TTpGWQFINf47S8ZGWAJA m3LJc2mkvelOvZ5uOZA5NHAHbPXmsqIKSUHc7VIyzROPT9cLEHgMLl6PRv7SUCuhgQlfvN7tYlk 5WDQdWrk7MxjLLP/kbvKJOLRIbXcDCn/DHhiXp1pVb2z8ZpeVFsP0qNjimamU2a4wLW/qvtnljf +5NUOn0p6iFjoRMQ3AO6e0TD79vOUte4KJe0s1zNq9b0YbTy9niCm72ajqwUcdwPcju3Vvm9iuB V05+X6d9EJ+kngAa493pAKyVglRa0CSWYNZQko5tfKAiSm7n5VH4GPsg9uTjYUfnJJesIYnabE5 IqQiYRn40xQ87lScXmRwJu4HHqHcYdzQZZvsLx6VjCYd8Ei2eqBHG+SWHZfLQzZsZWRy34qF3hP 7cvwKxMXP8SdapfFMFvLJ70CkcvLe0/VdozV4qKgbv5lQqt5Q1fhIGRNcIJRx36gnLRDyRe2vbv EODFNf0GS/0P/0IfmQj9GcQ3NFYL3XIgx99AcGDge2KpQ0BDGDEvS/UgvQmD8ycucBGgCRSQ8V5 p2W/cKxnmrQM7HUkjlMx19ukq+R2RZhrU X-Received: by 2002:a05:600d:864b:20b0:4a2:1e1:d55 with SMTP id 5b1f17b1804b1-4a201e10debmr28279805e9.28.1792605932936; Wed, 21 Oct 2026 11:05:32 -0700 (PDT) Received: from localhost.localdomain ([2a00:23c6:e6ea:6401:f04a:ac6f:988e:f33d]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4a1fcd13891sm47007775e9.2.2026.10.21.11.05.31 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Wed, 21 Oct 2026 11:05:32 -0700 (PDT) From: Nick Simpson To: Magnus Karlsson , Maciej Fijalkowski , David Ahern , Ido Schimmel Cc: Stanislav Fomichev , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Pablo Neira Ayuso , Florian Westphal , Phil Sutter , Alexei Starovoitov , Daniel Borkmann , Jesper Dangaard Brouer , John Fastabend , "Michael S . Tsirkin" , Willem de Bruijn , Jason Xing , Song Yoong Siang , Rusty Russell , Max Krasnyansky , Sridhar Samudrala , Jonathan Corbet , Shuah Khan , Randy Dunlap , netdev@vger.kernel.org, linux-doc@vger.kernel.org, bpf@vger.kernel.org, netfilter-devel@vger.kernel.org, coreteam@netfilter.org, linux-kernel@vger.kernel.org Subject: [PATCH net 3/3] ipv6: validate checksum_start before fragmenting Date: Wed, 21 Oct 2026 19:03:29 +0100 Message-ID: <20261021180329.26358-4-nick.simo@gmail.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20261021180329.26358-1-nick.simo@gmail.com> References: <20261021180329.26358-1-nick.simo@gmail.com> X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit ip6_fragment() and br_ip6_fragment() complete CHECKSUM_PARTIAL skbs with skb_checksum_help() without checking where csum_start points. After reassembly by nf_defrag_ipv6, the IPv6 header has moved forward by the 8 bytes of the fragment header while csum_start has not, so a CHECKSUM_PARTIAL skb from an untrusted source (tun/tap or packet sockets with a virtio_net_hdr, or AF_XDP TX metadata) can have csum_start inside the IPv6 header, and the checksum is then written into a header that the forward hook has already accepted. When csum_start lies before the network header, skb_checksum_help() warns. Add the IPv6 counterpart of ip_check_csum_start() from commit 6785011f8b16 ("ipv4: validate checksum_start before completing checksum") to the two IPv6 fragmentation paths: refuse to complete a checksum that starts inside the unfragmentable part of the packet (the IPv6 header and the extension headers before the fragment header) and drop the packet instead. For IPv4, ip_check_csum_start() is also called from nfnetlink_queue, xt_CHECKSUM and xfrm_output; their IPv6 counterparts are not changed here. A reassembled packet that is not fragmented again, such as an atomic fragment, and an unfragmented packet whose checksum is completed at egress are not covered either; those have to be handled where the CHECKSUM_PARTIAL skb is created, or by a check at reassembly time. The problem was found with LLM-assisted code review. Fixes: f43798c27684 ("tun: Allow GSO using virtio_net_hdr") Fixes: bfd5f4a3d605 ("packet: Add GSO/csum offload support.") Fixes: 48eb03dd2630 ("xsk: Add TX timestamp and TX checksum offload support") Assisted-by: LLM Signed-off-by: Nick Simpson --- include/net/ipv6.h | 12 ++++++++++++ net/ipv6/ip6_output.c | 10 +++++++--- net/ipv6/netfilter.c | 10 +++++++--- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 3de07e738538..949695cb6764 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -1029,6 +1029,18 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr); +/* Refuse to complete a checksum that starts inside the unfragmentable + * part of the packet, i.e. the IPv6 header and the extension headers + * that precede the fragment header. + */ +static inline int ip6_check_csum_start(const struct sk_buff *skb, + unsigned int hlen) +{ + if (unlikely(skb->csum_start < skb->network_header + hlen)) + return -EINVAL; + return 0; +} + int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 550965058991..55d7af9084d5 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -942,9 +942,13 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, frag_id = ipv6_select_ident(net, &ipv6_hdr(skb)->daddr, &ipv6_hdr(skb)->saddr); - if (skb->ip_summed == CHECKSUM_PARTIAL && - (err = skb_checksum_help(skb))) - goto fail; + if (skb->ip_summed == CHECKSUM_PARTIAL) { + err = ip6_check_csum_start(skb, hlen); + if (!err) + err = skb_checksum_help(skb); + if (err) + goto fail; + } prevhdr = skb_network_header(skb) + nexthdr_offset; hroom = LL_RESERVED_SPACE(rt->dst.dev); diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index a7025ec87035..8476e4ba399c 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -144,9 +144,13 @@ int br_ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, frag_id = ipv6_select_ident(net, &ipv6_hdr(skb)->daddr, &ipv6_hdr(skb)->saddr); - if (skb->ip_summed == CHECKSUM_PARTIAL && - (err = skb_checksum_help(skb))) - goto blackhole; + if (skb->ip_summed == CHECKSUM_PARTIAL) { + err = ip6_check_csum_start(skb, hlen); + if (!err) + err = skb_checksum_help(skb); + if (err) + goto blackhole; + } prevhdr = skb_network_header(skb) + nexthdr_offset; hroom = LL_RESERVED_SPACE(skb->dev); -- 2.53.0