Bug 4922 - Bug in netfilter.c when drivers do hardware checksum generation.
Summary: Bug in netfilter.c when drivers do hardware checksum generation.
Status: RESOLVED CODE_FIX
Alias: None
Product: Networking
Classification: Unclassified
Component: Netfilter/Iptables (show other bugs)
Hardware: i386 Linux
: P2 high
Assignee: Stephen Hemminger
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-07-21 11:39 UTC by Thomas F. Herbert
Modified: 2007-09-11 01:13 UTC (History)
1 user (show)

See Also:
Kernel Version: 2.6.12.2
Subsystem:
Regression: ---
Bisected commit-id:


Attachments

Description Thomas F. Herbert 2005-07-21 11:39:40 UTC
Distribution:

Has been reproduced in Fedora Core 2, Fedora Core 3, YDL 4.0.
with 2.6.8, 2.6.8.1 2.6.9, 2.6.10, 2.6.12.2

Hardware Environment:

x86 (tigon3 driver for BMC5705 tg3.c and ppc systems (mac mini) having ethernet
drivers that do hardware IP checksums.

Software Environment:

See kernel revs above.
Standard distributions. 
Problem Description:

There is a bug in the Linux kernel from 2.6.7 through 2.6.12.2.

The problem occurs when packets are being diverted to user space through
ipq/netlink sockets on systems that have ethernet drivers with hardware IP
checksum capability. It has been reproduced when user code is mangling the
packet headers. 

Where hardware has set ip_summed field in the skb and falsely indicates that the
checksum does not need to be re-generated after IP headers are mangled.

   This bug was originally introduced with a change to net/core/netfilter.c in
the 2.6.8 distribution.

Steps to reproduce:

   To reproduce the bug, divert packets through netlink ipq and change IP header
information.

The following patch fixes the problem on 2.6.12.2:

--- linux-2.6.12.2/net/core/netfilter.c.orig	2005-06-29 19:00:53.000000000 -0400
+++ linux-2.6.12.2/net/core/netfilter.c	2005-07-19 19:07:18.000000000 -0400
@@ -485,6 +485,14 @@
 	unsigned int verdict;
 	int ret = 0;
 
+        if ((*pskb)->ip_summed == CHECKSUM_HW) {
+                if (outdev == NULL) {
+                        (*pskb)->ip_summed = CHECKSUM_NONE;
+                } else {
+                        skb_checksum_help(*pskb, 0);
+                }
+        }
+
 	/* We may already have this, but read-locks nest anyway */
 	rcu_read_lock();
 

The following patch fixes the problem on 2.6.6 - 2.6.11

--- linux-2.6.7/net/core/netfilter.c	2005-07-19 13:02:11.000000000 -0400
+++ linux-2.6.7-netfilter/net/core/netfilter.c	2005-07-19 15:56:51.000000000 -0400
@@ -504,6 +504,14 @@
 	unsigned int verdict;
 	int ret = 0;
 
+        if (skb->ip_summed == CHECKSUM_HW) {
+                if (outdev == NULL) {
+                        skb->ip_summed = CHECKSUM_NONE;
+                } else {
+                        skb_checksum_help(&skb, 0);
+                }
+        }
+
 	/* We may already have this, but read-locks nest anyway */
 	rcu_read_lock();
 

Thanks in advance for your consideration of this bug,

--Tom Herbert

herbert@tfherbert.net  therbert@certicom.com
Comment 1 Stephen Hemminger 2007-09-11 01:13:50 UTC
The hardware checksum support was fixed in 2.6.19

Note You need to log in before you can comment on or make changes to this bug.