[PATCH] net/sched: act_csum: skip malformed IPv4 headers

Samuel Moelius posted 1 patch 2 days, 12 hours ago
net/sched/act_csum.c | 26 +++++++++++++++-----------
1 file changed, 15 insertions(+), 11 deletions(-)
[PATCH] net/sched: act_csum: skip malformed IPv4 headers
Posted by Samuel Moelius 2 days, 12 hours ago
act_csum trusts the IPv4 IHL field before using it to locate transport
header fields.  Packets with an invalid short IHL can make the action
write checksum data into the IPv4 header instead of the intended L4
header.

The action should not repair or modify packets whose IPv4 header length
is invalid.  Treat those packets as not eligible for checksum repair and
leave the configured action result unchanged.

Return success without updating checksums when the IPv4 version, IHL, or
total length cannot describe a complete IPv4 header.

Assisted-by: Codex:gpt-5.5-cyber-preview
Signed-off-by: Samuel Moelius <sam.moelius@trailofbits.com>
---
 net/sched/act_csum.c | 26 +++++++++++++++-----------
 1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c
index a9e4635d899e..faedf6abd448 100644
--- a/net/sched/act_csum.c
+++ b/net/sched/act_csum.c
@@ -385,6 +385,8 @@ static int tcf_csum_sctp(struct sk_buff *skb, unsigned int ihl,
 static int tcf_csum_ipv4(struct sk_buff *skb, u32 update_flags)
 {
 	const struct iphdr *iph;
+	unsigned int ihl;
+	unsigned int ipl;
 	int ntkoff;
 
 	ntkoff = skb_network_offset(skb);
@@ -393,41 +395,43 @@ static int tcf_csum_ipv4(struct sk_buff *skb, u32 update_flags)
 		goto fail;
 
 	iph = ip_hdr(skb);
+	if (iph->version != 4 || iph->ihl < 5)
+		return 1;
+
+	ihl = iph->ihl * 4;
+	ipl = ntohs(iph->tot_len);
+	if (ipl < ihl)
+		return 1;
 
 	switch (iph->frag_off & htons(IP_OFFSET) ? 0 : iph->protocol) {
 	case IPPROTO_ICMP:
 		if (update_flags & TCA_CSUM_UPDATE_FLAG_ICMP)
-			if (!tcf_csum_ipv4_icmp(skb, iph->ihl * 4,
-						ntohs(iph->tot_len)))
+			if (!tcf_csum_ipv4_icmp(skb, ihl, ipl))
 				goto fail;
 		break;
 	case IPPROTO_IGMP:
 		if (update_flags & TCA_CSUM_UPDATE_FLAG_IGMP)
-			if (!tcf_csum_ipv4_igmp(skb, iph->ihl * 4,
-						ntohs(iph->tot_len)))
+			if (!tcf_csum_ipv4_igmp(skb, ihl, ipl))
 				goto fail;
 		break;
 	case IPPROTO_TCP:
 		if (update_flags & TCA_CSUM_UPDATE_FLAG_TCP)
-			if (!tcf_csum_ipv4_tcp(skb, iph->ihl * 4,
-					       ntohs(iph->tot_len)))
+			if (!tcf_csum_ipv4_tcp(skb, ihl, ipl))
 				goto fail;
 		break;
 	case IPPROTO_UDP:
 		if (update_flags & TCA_CSUM_UPDATE_FLAG_UDP)
-			if (!tcf_csum_ipv4_udp(skb, iph->ihl * 4,
-					       ntohs(iph->tot_len), 0))
+			if (!tcf_csum_ipv4_udp(skb, ihl, ipl, 0))
 				goto fail;
 		break;
 	case IPPROTO_UDPLITE:
 		if (update_flags & TCA_CSUM_UPDATE_FLAG_UDPLITE)
-			if (!tcf_csum_ipv4_udp(skb, iph->ihl * 4,
-					       ntohs(iph->tot_len), 1))
+			if (!tcf_csum_ipv4_udp(skb, ihl, ipl, 1))
 				goto fail;
 		break;
 	case IPPROTO_SCTP:
 		if ((update_flags & TCA_CSUM_UPDATE_FLAG_SCTP) &&
-		    !tcf_csum_sctp(skb, iph->ihl * 4, ntohs(iph->tot_len)))
+		    !tcf_csum_sctp(skb, ihl, ipl))
 			goto fail;
 		break;
 	}
-- 
2.43.0