diff mbox

Bad checksum on bridge with IP options

Message ID 5370CB47.4010400@davidnewall.com
State RFC, archived
Delegated to: David Miller
Headers show

Commit Message

David Newall May 12, 2014, 1:23 p.m. UTC
I've got a patch which fixes the faulty checksums, and now ping works 
with RR or TS set.  I'm not quite sure, though, that it fixes the right 
thing.  I wonder if the problem is less that the checksum becomes wrong, 
and more that the route and timestamps ought not to be changed by the 
bridge interface.

Anyway, for discussion, here's the patch:


--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Florian Westphal May 12, 2014, 1:51 p.m. UTC | #1
David Newall <davidn@davidnewall.com> wrote:
> I've got a patch which fixes the faulty checksums, and now ping
> works with RR or TS set.  I'm not quite sure, though, that it fixes
> the right thing.  I wonder if the problem is less that the checksum
> becomes wrong, and more that the route and timestamps ought not to
> be changed by the bridge interface.

Agree, bridge should not alter ip options.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Newall May 12, 2014, 2:19 p.m. UTC | #2
On 12/05/14 23:21, Florian Westphal wrote:
> Agree, bridge should not alter ip options.

It would be easy to remove the call to ip_options_compile instead of 
recalculating checksum after it, but I suspect there may be good reasons 
why this, too, would be wrong.  The source file is br_netfilter.c, 
suggesting that a change in options is needed in some situations.

In the situation that caught my attention, it obviously does it wrong 
(probably didn't add 0.0.0.0 to the route record, probably just 
incremented the pointer; and seriously damaged the timestamps as well as 
an incremented pointer without actually adding a value.)

I'm in a quandary.

Is it possible that bridge has exceeded it's mandate?  I can't find it 
now, but I saw a comment that it just copies packets unchanged. I think 
it's use now goes further than that would allow.

I welcome words of advice.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lukas Tribus May 12, 2014, 6:54 p.m. UTC | #3
> I've got a patch which fixes the faulty checksums, and now ping works
> with RR or TS set. I'm not quite sure, though, that it fixes the right
> thing. I wonder if the problem is less that the checksum becomes wrong,
> and more that the route and timestamps ought not to be changed by the
> bridge interface.

Looks like your testcase:
- works in 2.6.36 and older
- crashes starting with 2.6.37 (-rc1), likely due to Bandan's commit 462fb2af9788a82 (bridge : Sanitize skb before it enters the IP stack) [1]
- crash fix is in 2.6.38.4, likely due to Eric's commit f8e9881c2aef1e9 (bridge: reset IPCB in br_parse_ip_options) [2]
- doesn't work post-crashfix



[1] http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=462fb2af9788a82a534f8184abfde31574e1cfa0
[2] http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=f8e9881c2aef1e982e5abc25c046820cd0b7cf64
 		 	   		  --
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

--- br_netfilter.c.orig	2014-05-12 22:10:59.809988125 +0930
+++ br_netfilter.c	2014-05-12 22:27:46.769299379 +0930
@@ -261,8 +261,10 @@ 
  static int br_parse_ip_options(struct sk_buff *skb)
  {
  	struct ip_options *opt;
-	const struct iphdr *iph;
+	struct iphdr *iph;
  	struct net_device *dev = skb->dev;
+	__sum16 oldsum;
+	int err;
  	u32 len;
  
  	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
@@ -298,8 +300,15 @@ 
  	if (iph->ihl == 5)
  		return 0;
  
+	oldsum = iph->check;
  	opt->optlen = iph->ihl*4 - sizeof(struct iphdr);
-	if (ip_options_compile(dev_net(dev), opt, skb))
+	err = ip_options_compile(dev_net(dev), opt, skb);
+	ip_send_check(iph);
+	if (iph->check != oldsum)
+		LIMIT_NETDEBUG(KERN_ERR
+			pr_fmt("br_parse_ip_options: bad sum %x replaced by %x\n"),
+			                       oldsum, iph->check);
+	if (err)
  		goto inhdr_error;
  
  	/* Check correct handling of SRR option */