From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 95D274EFFB7; Tue, 13 Oct 2026 11:46:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791892017; cv=none; b=LGAeFbrxn46ezRXmEEXg7kvVW+fRtNHKpnaLjzuXX/2BaRXpiatUXOn1ZMTUVG3ve3AKeJBur0FPiBvoBljXAiNRuAPn9yXKasDgWWDVIZVpbmE1o1xGicxHRCQmp7msgcnWlY44k5MyZ9Rdwe5tJOEEhhiHSc/mwFdAjuc1lXI= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791892017; c=relaxed/simple; bh=zx7rb4jjAdTJTLllU0luvRKPbyCPEN+NAPd8VoJS1tk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Cra5uT6nwAj5EJ05pZOM/takWHh6a7XBDe6s6B8ky9RCRBThH/is0sX7dabx4O4BEinadpMqYMfhsxr+Ii69HsvPJ5lt6TC6ADz1hRsZLE9uRb9wBp3/I/OpWieT7eKcwmo+pWsyCawEZG5+y2FAFEHJQsRXcc824tQLn8ELbSI= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b=0Q4YOMc6; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b="0Q4YOMc6" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AA99C1F000FF; Tue, 13 Oct 2026 11:46:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1791892015; bh=LqP+p7fQvSCWDuY8I9U/ViSXlIbFx6kD2RVQorxptc0=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=0Q4YOMc60079wPut8c2OPUvWh1tNXFjFScLOnClFn5ZmH3O/c9X0+t48ECHEPVX+o yIHp9Xd+sDgug06CUR9AqyQv5++SbxeaoOJ8RZAIokGIYXm+WbJsm2LcL84RC8Jk9X oi8G0sIu+5PREmwNhFHrZCbBlL3UOW+eL8UUNFis= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, Paulos Yibelo , "Michael S. Tsirkin" , Willem de Bruijn , Jakub Kicinski Subject: [PATCH 7.2 008/281] ipv4: validate checksum_start before completing checksum Date: Tue, 13 Oct 2026 13:35:24 +0200 Message-ID: <20261013112855.253958493@linuxfoundation.org> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261013112855.045212108@linuxfoundation.org> References: <20261013112855.045212108@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore Precedence: bulk X-Mailing-List: patches@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 7.2-stable review patch. If anyone has any objections, please let me know. ------------------ From: Michael S. Tsirkin commit 6785011f8b16abf40b1e9d8b2e332232b3e68822 upstream. If a packet with bad checksum metadata gets into the ipv4 stack, skb_checksum_help can corrupt the network header and cause a bunch of mischief. This was discovered and reported by Paulos, and has been reporoduced by others independently since. We really shouldn't allow such packets in, but as a defence in depth measure, let's also check before we complete the checksum. A more complete validation at input is forthcoming, but needs more work. Cc: stable@vger.kernel.org Fixes: f43798c27684 ("tun: Allow GSO using virtio_net_hdr") Fixes: bfd5f4a3d605 ("packet: Add GSO/csum offload support.") Reported-by: Paulos Yibelo Closes: https://lore.kernel.org/netdev/20260922030310.8684-2-habte.yibelo@gmail.com/ Signed-off-by: Michael S. Tsirkin Reviewed-by: Willem de Bruijn Link: https://patch.msgid.link/0a012b4923e189c4c593ef4f471e5ff0edbe9030.1791412497.git.mst@redhat.com Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- include/net/ip.h | 7 +++++++ net/bridge/netfilter/nf_conntrack_bridge.c | 10 +++++++--- net/ipv4/ip_output.c | 10 +++++++--- net/netfilter/nfnetlink_queue.c | 7 +++++++ net/netfilter/xt_CHECKSUM.c | 6 +++++- net/xfrm/xfrm_output.c | 16 +++++++++++----- 6 files changed, 44 insertions(+), 12 deletions(-) --- a/include/net/ip.h +++ b/include/net/ip.h @@ -74,6 +74,13 @@ static inline unsigned int ip_hdrlen(con return ip_hdr(skb)->ihl * 4; } +static inline int ip_check_csum_start(const struct sk_buff *skb) +{ + if (unlikely(skb->csum_start < skb->network_header + ip_hdrlen(skb))) + return -EINVAL; + return 0; +} + struct ipcm_cookie { struct sockcm_cookie sockc; __be32 addr; --- a/net/bridge/netfilter/nf_conntrack_bridge.c +++ b/net/bridge/netfilter/nf_conntrack_bridge.c @@ -39,9 +39,13 @@ static int nf_br_ip_fragment(struct net int err = 0; /* for offloaded checksums cleanup checksum before fragmentation */ - if (skb->ip_summed == CHECKSUM_PARTIAL && - (err = skb_checksum_help(skb))) - goto blackhole; + if (skb->ip_summed == CHECKSUM_PARTIAL) { + err = ip_check_csum_start(skb); + if (!err) + err = skb_checksum_help(skb); + if (err) + goto blackhole; + } iph = ip_hdr(skb); --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -771,9 +771,13 @@ int ip_do_fragment(struct net *net, stru int err = 0; /* for offloaded checksums cleanup checksum before fragmentation */ - if (skb->ip_summed == CHECKSUM_PARTIAL && - (err = skb_checksum_help(skb))) - goto fail; + if (skb->ip_summed == CHECKSUM_PARTIAL) { + err = ip_check_csum_start(skb); + if (!err) + err = skb_checksum_help(skb); + if (err) + goto fail; + } /* * Point into the IP datagram header. --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -667,6 +668,12 @@ nla_put_failure: static int nf_queue_checksum_help(struct sk_buff *entskb) { + if (entskb->protocol == htons(ETH_P_IP)) { + if (!pskb_network_may_pull(entskb, sizeof(struct iphdr)) || + ip_check_csum_start(entskb)) + return -EINVAL; + } + if (skb_csum_is_sctp(entskb)) return skb_crc32c_csum_help(entskb); --- a/net/netfilter/xt_CHECKSUM.c +++ b/net/netfilter/xt_CHECKSUM.c @@ -15,6 +15,7 @@ #include #include +#include MODULE_LICENSE("GPL"); MODULE_AUTHOR("Michael S. Tsirkin "); @@ -25,8 +26,11 @@ MODULE_ALIAS("ip6t_CHECKSUM"); static unsigned int checksum_tg(struct sk_buff *skb, const struct xt_action_param *par) { - if (skb->ip_summed == CHECKSUM_PARTIAL && !skb_is_gso(skb)) + if (skb->ip_summed == CHECKSUM_PARTIAL && !skb_is_gso(skb)) { + if (xt_family(par) == NFPROTO_IPV4 && ip_check_csum_start(skb)) + return NF_DROP; skb_checksum_help(skb); + } return XT_CONTINUE; } --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -823,16 +823,22 @@ int xfrm_output(struct sock *sk, struct } if (skb->ip_summed == CHECKSUM_PARTIAL) { - err = skb_checksum_help(skb); - if (err) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR); - kfree_skb(skb); - return err; + if (skb->protocol == htons(ETH_P_IP)) { + err = ip_check_csum_start(skb); + if (err) + goto error; } + err = skb_checksum_help(skb); + if (err) + goto error; } out: return xfrm_output2(net, sk, skb); +error: + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR); + kfree_skb(skb); + return err; } EXPORT_SYMBOL_GPL(xfrm_output);