From: David Newall <davidn@davidnewall.com>
To: David Miller <davem@davemloft.net>, bdschuym@pandora.be
Cc: netdev@vger.kernel.org, Vlad Yasevich <vyasevich@gmail.com>,
bridge@lists.linux-foundation.org, fw@strlen.de,
stephen@networkplumber.org, Bandan Das <bsd@redhat.com>,
netfilter-devel@vger.kernel.org
Subject: Re: [Bridge] Revert 462fb2af9788a82a534f8184abfde31574e1cfa0 (bridge : Sanitize skb before it enters the IP stack)
Date: Sat, 24 May 2014 15:26:24 +0930 [thread overview]
Message-ID: <53803488.6000400@davidnewall.com> (raw)
In-Reply-To: <20140521.161841.1806439174351824310.davem@davemloft.net>
On 22/05/14 05:48, David Miller wrote:
> From: Bart De Schuymer<bdschuym@pandora.be>
> Date: Wed, 21 May 2014 20:51:14 +0200
> > There's no reason why they should overlap in the cb: it's 48 bytes
> > big, so big enough to hold both struct br_input_skb_cb and struct
> > inet_skb_parm. The original problem was introduced when
> > BR_INPUT_SKB_CB was introduced (around Feb 27, 2010), so fixing
> > BR_INPUT_SKB_CB seems most appropriate to me.
>
> So you are suggesting the patch below will fix everything?
First, of course I was wrong about ip overflowing the cb area. Even I
thought that was unlikely. I've reread the code, much more carefully,
and spotted where I went wrong.
I've added the change that David Miller provided, to those which I am
proposing, and minimally tested them by pinging through a bridge with RR
set. No surprise: it works.
The patch now reverts the commit and mitigates the original problem by
ensuring bridge's use of cb does not overlap ip's.
--- linux-source-3.13.0/net/bridge/br_netfilter.c.orig 2014-05-17 00:12:23.418906498 +0930
+++ linux-source-3.13.0/net/bridge/br_netfilter.c 2014-05-17 01:04:43.540972961 +0930
@@ -253,73 +253,6 @@ static inline void nf_bridge_update_prot
skb->protocol = htons(ETH_P_PPP_SES);
}
-/* When handing a packet over to the IP layer
- * check whether we have a skb that is in the
- * expected format
- */
-
-static int br_parse_ip_options(struct sk_buff *skb)
-{
- struct ip_options *opt;
- const struct iphdr *iph;
- struct net_device *dev = skb->dev;
- u32 len;
-
- if (!pskb_may_pull(skb, sizeof(struct iphdr)))
- goto inhdr_error;
-
- iph = ip_hdr(skb);
- opt = &(IPCB(skb)->opt);
-
- /* Basic sanity checks */
- if (iph->ihl < 5 || iph->version != 4)
- goto inhdr_error;
-
- if (!pskb_may_pull(skb, iph->ihl*4))
- goto inhdr_error;
-
- iph = ip_hdr(skb);
- if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
- goto inhdr_error;
-
- len = ntohs(iph->tot_len);
- if (skb->len < len) {
- IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INTRUNCATEDPKTS);
- goto drop;
- } else if (len < (iph->ihl*4))
- goto inhdr_error;
-
- if (pskb_trim_rcsum(skb, len)) {
- IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS);
- goto drop;
- }
-
- memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
- if (iph->ihl == 5)
- return 0;
-
- opt->optlen = iph->ihl*4 - sizeof(struct iphdr);
- if (ip_options_compile(dev_net(dev), opt, skb))
- goto inhdr_error;
-
- /* Check correct handling of SRR option */
- if (unlikely(opt->srr)) {
- struct in_device *in_dev = __in_dev_get_rcu(dev);
- if (in_dev && !IN_DEV_SOURCE_ROUTE(in_dev))
- goto drop;
-
- if (ip_options_rcv_srr(skb))
- goto drop;
- }
-
- return 0;
-
-inhdr_error:
- IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INHDRERRORS);
-drop:
- return -1;
-}
-
/* Fill in the header for fragmented IP packets handled by
* the IPv4 connection tracking code.
*/
@@ -679,6 +612,7 @@ static unsigned int br_nf_pre_routing(co
{
struct net_bridge_port *p;
struct net_bridge *br;
+ const struct iphdr *iph;
__u32 len = nf_bridge_encap_header_len(skb);
if (unlikely(!pskb_may_pull(skb, len)))
@@ -704,10 +638,30 @@ static unsigned int br_nf_pre_routing(co
return NF_ACCEPT;
nf_bridge_pull_encap_header_rcsum(skb);
+
+ if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+ return NF_DROP;
- if (br_parse_ip_options(skb))
+ iph = ip_hdr(skb);
+ if (iph->ihl < 5 || iph->version != 4)
+ return NF_DROP;
+
+ if (!pskb_may_pull(skb, 4 * iph->ihl))
return NF_DROP;
+ iph = ip_hdr(skb);
+ if (ip_fast_csum((__u8 *) iph, iph->ihl) != 0)
+ return NF_DROP;
+
+ len = ntohs(iph->tot_len);
+ if (skb->len < len || len < 4 * iph->ihl)
+ return NF_DROP;
+
+ pskb_trim_rcsum(skb, len);
+
+ /* BUG: Should really parse the IP options here. */
+ memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
+
nf_bridge_put(skb->nf_bridge);
if (!nf_bridge_alloc(skb))
return NF_DROP;
@@ -806,9 +760,6 @@ static unsigned int br_nf_forward_ip(con
nf_bridge->mask |= BRNF_PKT_TYPE;
}
- if (pf == NFPROTO_IPV4 && br_parse_ip_options(skb))
- return NF_DROP;
-
/* The physdev module checks on this */
nf_bridge->mask |= BRNF_BRIDGED;
nf_bridge->physoutdev = skb->dev;
@@ -862,19 +813,14 @@ static unsigned int br_nf_forward_arp(co
#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV4)
static int br_nf_dev_queue_xmit(struct sk_buff *skb)
{
- int ret;
-
if (skb->nfct != NULL && skb->protocol == htons(ETH_P_IP) &&
skb->len + nf_bridge_mtu_reduction(skb) > skb->dev->mtu &&
!skb_is_gso(skb)) {
- if (br_parse_ip_options(skb))
- /* Drop invalid packet */
- return NF_DROP;
- ret = ip_fragment(skb, br_dev_queue_push_xmit);
+ /* BUG: Should really parse the IP options here. */
+ memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
+ return ip_fragment(skb, br_dev_queue_push_xmit);
} else
- ret = br_dev_queue_push_xmit(skb);
-
- return ret;
+ return br_dev_queue_push_xmit(skb);
}
#else
static int br_nf_dev_queue_xmit(struct sk_buff *skb)
--- linux-source-3.13.0/net/ipv4/ip_options.c.orig 2014-05-16 18:11:10.260370554 +0930
+++ linux-source-3.13.0/net/ipv4/ip_options.c 2014-05-17 01:01:56.738277137 +0930
@@ -475,7 +475,6 @@ error:
}
return -EINVAL;
}
-EXPORT_SYMBOL(ip_options_compile);
/*
* Undo all the changes done by ip_options_compile().
@@ -658,4 +657,3 @@ int ip_options_rcv_srr(struct sk_buff *s
}
return 0;
}
-EXPORT_SYMBOL(ip_options_rcv_srr);
--- /usr/src/linux-source-3.13.0/net/bridge/br_private.h.orig 2014-05-24 13:51:09.269709831 +0930
+++ /usr/src/linux-source-3.13.0/net/bridge/br_private.h 2014-05-24 13:53:20.243551927 +0930
@@ -18,6 +18,7 @@
#include <linux/netpoll.h>
#include <linux/u64_stats_sync.h>
#include <net/route.h>
+#include <net/ip.h>
#include <linux/if_vlan.h>
#define BR_HASH_BITS 8
@@ -304,6 +305,7 @@ struct net_bridge
};
struct br_input_skb_cb {
+ struct inet_skb_parm ip; /* we don't interfere with ip's use of cb area */
struct net_device *brdev;
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
int igmp;
WARNING: multiple messages have this Message-ID (diff)
From: David Newall <davidn@davidnewall.com>
To: David Miller <davem@davemloft.net>, bdschuym@pandora.be
Cc: fw@strlen.de, stephen@networkplumber.org, netdev@vger.kernel.org,
netfilter-devel@vger.kernel.org,
bridge@lists.linux-foundation.org, Bandan Das <bsd@redhat.com>,
Vlad Yasevich <vyasevich@gmail.com>
Subject: Re: Revert 462fb2af9788a82a534f8184abfde31574e1cfa0 (bridge : Sanitize skb before it enters the IP stack)
Date: Sat, 24 May 2014 15:26:24 +0930 [thread overview]
Message-ID: <53803488.6000400@davidnewall.com> (raw)
In-Reply-To: <20140521.161841.1806439174351824310.davem@davemloft.net>
On 22/05/14 05:48, David Miller wrote:
> From: Bart De Schuymer<bdschuym@pandora.be>
> Date: Wed, 21 May 2014 20:51:14 +0200
> > There's no reason why they should overlap in the cb: it's 48 bytes
> > big, so big enough to hold both struct br_input_skb_cb and struct
> > inet_skb_parm. The original problem was introduced when
> > BR_INPUT_SKB_CB was introduced (around Feb 27, 2010), so fixing
> > BR_INPUT_SKB_CB seems most appropriate to me.
>
> So you are suggesting the patch below will fix everything?
First, of course I was wrong about ip overflowing the cb area. Even I
thought that was unlikely. I've reread the code, much more carefully,
and spotted where I went wrong.
I've added the change that David Miller provided, to those which I am
proposing, and minimally tested them by pinging through a bridge with RR
set. No surprise: it works.
The patch now reverts the commit and mitigates the original problem by
ensuring bridge's use of cb does not overlap ip's.
--- linux-source-3.13.0/net/bridge/br_netfilter.c.orig 2014-05-17 00:12:23.418906498 +0930
+++ linux-source-3.13.0/net/bridge/br_netfilter.c 2014-05-17 01:04:43.540972961 +0930
@@ -253,73 +253,6 @@ static inline void nf_bridge_update_prot
skb->protocol = htons(ETH_P_PPP_SES);
}
-/* When handing a packet over to the IP layer
- * check whether we have a skb that is in the
- * expected format
- */
-
-static int br_parse_ip_options(struct sk_buff *skb)
-{
- struct ip_options *opt;
- const struct iphdr *iph;
- struct net_device *dev = skb->dev;
- u32 len;
-
- if (!pskb_may_pull(skb, sizeof(struct iphdr)))
- goto inhdr_error;
-
- iph = ip_hdr(skb);
- opt = &(IPCB(skb)->opt);
-
- /* Basic sanity checks */
- if (iph->ihl < 5 || iph->version != 4)
- goto inhdr_error;
-
- if (!pskb_may_pull(skb, iph->ihl*4))
- goto inhdr_error;
-
- iph = ip_hdr(skb);
- if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
- goto inhdr_error;
-
- len = ntohs(iph->tot_len);
- if (skb->len < len) {
- IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INTRUNCATEDPKTS);
- goto drop;
- } else if (len < (iph->ihl*4))
- goto inhdr_error;
-
- if (pskb_trim_rcsum(skb, len)) {
- IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS);
- goto drop;
- }
-
- memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
- if (iph->ihl == 5)
- return 0;
-
- opt->optlen = iph->ihl*4 - sizeof(struct iphdr);
- if (ip_options_compile(dev_net(dev), opt, skb))
- goto inhdr_error;
-
- /* Check correct handling of SRR option */
- if (unlikely(opt->srr)) {
- struct in_device *in_dev = __in_dev_get_rcu(dev);
- if (in_dev && !IN_DEV_SOURCE_ROUTE(in_dev))
- goto drop;
-
- if (ip_options_rcv_srr(skb))
- goto drop;
- }
-
- return 0;
-
-inhdr_error:
- IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INHDRERRORS);
-drop:
- return -1;
-}
-
/* Fill in the header for fragmented IP packets handled by
* the IPv4 connection tracking code.
*/
@@ -679,6 +612,7 @@ static unsigned int br_nf_pre_routing(co
{
struct net_bridge_port *p;
struct net_bridge *br;
+ const struct iphdr *iph;
__u32 len = nf_bridge_encap_header_len(skb);
if (unlikely(!pskb_may_pull(skb, len)))
@@ -704,10 +638,30 @@ static unsigned int br_nf_pre_routing(co
return NF_ACCEPT;
nf_bridge_pull_encap_header_rcsum(skb);
+
+ if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+ return NF_DROP;
- if (br_parse_ip_options(skb))
+ iph = ip_hdr(skb);
+ if (iph->ihl < 5 || iph->version != 4)
+ return NF_DROP;
+
+ if (!pskb_may_pull(skb, 4 * iph->ihl))
return NF_DROP;
+ iph = ip_hdr(skb);
+ if (ip_fast_csum((__u8 *) iph, iph->ihl) != 0)
+ return NF_DROP;
+
+ len = ntohs(iph->tot_len);
+ if (skb->len < len || len < 4 * iph->ihl)
+ return NF_DROP;
+
+ pskb_trim_rcsum(skb, len);
+
+ /* BUG: Should really parse the IP options here. */
+ memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
+
nf_bridge_put(skb->nf_bridge);
if (!nf_bridge_alloc(skb))
return NF_DROP;
@@ -806,9 +760,6 @@ static unsigned int br_nf_forward_ip(con
nf_bridge->mask |= BRNF_PKT_TYPE;
}
- if (pf == NFPROTO_IPV4 && br_parse_ip_options(skb))
- return NF_DROP;
-
/* The physdev module checks on this */
nf_bridge->mask |= BRNF_BRIDGED;
nf_bridge->physoutdev = skb->dev;
@@ -862,19 +813,14 @@ static unsigned int br_nf_forward_arp(co
#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV4)
static int br_nf_dev_queue_xmit(struct sk_buff *skb)
{
- int ret;
-
if (skb->nfct != NULL && skb->protocol == htons(ETH_P_IP) &&
skb->len + nf_bridge_mtu_reduction(skb) > skb->dev->mtu &&
!skb_is_gso(skb)) {
- if (br_parse_ip_options(skb))
- /* Drop invalid packet */
- return NF_DROP;
- ret = ip_fragment(skb, br_dev_queue_push_xmit);
+ /* BUG: Should really parse the IP options here. */
+ memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
+ return ip_fragment(skb, br_dev_queue_push_xmit);
} else
- ret = br_dev_queue_push_xmit(skb);
-
- return ret;
+ return br_dev_queue_push_xmit(skb);
}
#else
static int br_nf_dev_queue_xmit(struct sk_buff *skb)
--- linux-source-3.13.0/net/ipv4/ip_options.c.orig 2014-05-16 18:11:10.260370554 +0930
+++ linux-source-3.13.0/net/ipv4/ip_options.c 2014-05-17 01:01:56.738277137 +0930
@@ -475,7 +475,6 @@ error:
}
return -EINVAL;
}
-EXPORT_SYMBOL(ip_options_compile);
/*
* Undo all the changes done by ip_options_compile().
@@ -658,4 +657,3 @@ int ip_options_rcv_srr(struct sk_buff *s
}
return 0;
}
-EXPORT_SYMBOL(ip_options_rcv_srr);
--- /usr/src/linux-source-3.13.0/net/bridge/br_private.h.orig 2014-05-24 13:51:09.269709831 +0930
+++ /usr/src/linux-source-3.13.0/net/bridge/br_private.h 2014-05-24 13:53:20.243551927 +0930
@@ -18,6 +18,7 @@
#include <linux/netpoll.h>
#include <linux/u64_stats_sync.h>
#include <net/route.h>
+#include <net/ip.h>
#include <linux/if_vlan.h>
#define BR_HASH_BITS 8
@@ -304,6 +305,7 @@ struct net_bridge
};
struct br_input_skb_cb {
+ struct inet_skb_parm ip; /* we don't interfere with ip's use of cb area */
struct net_device *brdev;
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
int igmp;
next prev parent reply other threads:[~2014-05-24 5:56 UTC|newest]
Thread overview: 76+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-05-11 14:41 Bad checksum on bridge with IP options David Newall
2014-05-11 19:42 ` Lukas Tribus
2014-05-12 8:14 ` David Newall
2014-05-12 10:15 ` Lukas Tribus
2014-05-12 10:25 ` David Newall
2014-05-12 10:31 ` Lukas Tribus
2014-05-12 10:48 ` David Newall
2014-05-12 13:23 ` David Newall
2014-05-12 13:51 ` Florian Westphal
2014-05-12 14:19 ` David Newall
2014-05-12 18:54 ` Lukas Tribus
2014-05-12 23:46 ` David Newall
2014-05-14 13:08 ` David Newall
2014-05-16 14:33 ` Revert 462fb2af9788a82a534f8184abfde31574e1cfa0 (bridge : Sanitize skb before it enters the IP stack) David Newall
2014-05-16 15:19 ` Eric Dumazet
2014-05-16 15:23 ` David Newall
2014-05-16 15:24 ` David Newall
2014-05-19 12:58 ` [Bridge] " David Newall
2014-05-19 12:58 ` David Newall
2014-05-19 14:01 ` [Bridge] " Florian Westphal
2014-05-19 14:01 ` Florian Westphal
2014-05-19 14:19 ` [Bridge] " David Newall
2014-05-19 14:19 ` David Newall
2014-05-19 17:09 ` [Bridge] " Florian Westphal
2014-05-19 17:09 ` Florian Westphal
2014-05-19 20:49 ` [Bridge] " Bart De Schuymer
2014-05-19 20:49 ` Bart De Schuymer
2014-05-21 7:49 ` [Bridge] " David Newall
2014-05-21 7:49 ` David Newall
2014-05-21 18:51 ` [Bridge] " Bart De Schuymer
2014-05-21 18:51 ` Bart De Schuymer
2014-05-21 20:18 ` [Bridge] " David Miller
2014-05-21 20:18 ` David Miller
2014-05-22 18:57 ` [Bridge] " Bart De Schuymer
2014-05-22 18:57 ` Bart De Schuymer
2014-05-24 18:00 ` [Bridge] " David Miller
2014-05-24 18:00 ` David Miller
2014-05-24 5:56 ` David Newall [this message]
2014-05-24 5:56 ` David Newall
2014-05-24 17:43 ` [Bridge] " David Miller
2014-05-24 17:43 ` David Miller
2014-05-25 2:32 ` [Bridge] " David Newall
2014-05-25 2:32 ` David Newall
2014-05-25 3:02 ` [Bridge] " David Miller
2014-05-25 3:02 ` David Miller
2014-05-25 6:37 ` [Bridge] " David Newall
2014-05-25 6:37 ` David Newall
2014-05-27 8:55 ` [Bridge] " David Laight
2014-05-27 8:55 ` David Laight
2014-05-29 22:34 ` [Bridge] " David Miller
2014-05-29 22:34 ` David Miller
2014-05-30 9:17 ` [Bridge] " David Newall
2014-05-30 9:17 ` David Newall
2014-05-31 0:46 ` [Bridge] " David Miller
2014-05-31 0:46 ` David Miller
2014-05-31 6:13 ` [Bridge] " David Newall
2014-05-31 6:13 ` David Newall
2014-05-31 6:37 ` [Bridge] " David Miller
2014-05-31 6:37 ` David Miller
2014-05-22 3:50 ` [Bridge] " David Newall
2014-05-22 3:50 ` David Newall
2014-05-22 18:57 ` [Bridge] " Bart De Schuymer
2014-05-22 18:57 ` Bart De Schuymer
2014-05-20 3:57 ` [Bridge] " David Newall
2014-05-20 3:57 ` David Newall
2014-05-20 4:55 ` [Bridge] " Valdis.Kletnieks
2014-05-20 4:55 ` Valdis.Kletnieks
2014-05-20 16:05 ` [Bridge] " Vlad Yasevich
2014-05-20 16:05 ` Vlad Yasevich
2014-05-20 16:05 ` Vlad Yasevich
2014-05-21 8:10 ` [Bridge] " David Newall
2014-05-21 8:10 ` David Newall
2014-05-21 20:14 ` [Bridge] " David Miller
2014-05-21 20:14 ` David Miller
2014-05-21 20:14 ` David Miller
2014-05-22 20:06 ` Bandan Das
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=53803488.6000400@davidnewall.com \
--to=davidn@davidnewall.com \
--cc=bdschuym@pandora.be \
--cc=bridge@lists.linux-foundation.org \
--cc=bsd@redhat.com \
--cc=davem@davemloft.net \
--cc=fw@strlen.de \
--cc=netdev@vger.kernel.org \
--cc=netfilter-devel@vger.kernel.org \
--cc=stephen@networkplumber.org \
--cc=vyasevich@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.