diff options
author | Stephen Hemminger <shemminger@osdl.org> | 2006-12-18 20:51:43 +0100 |
---|---|---|
committer | Adrian Bunk <bunk@stusta.de> | 2006-12-18 20:51:43 +0100 |
commit | d0354e3ba19cdf9acc2ca89bbb59b1e6292a4f44 (patch) | |
tree | e2de02bc6b0b1f1f67f33608bbbd9cf83c73c638 | |
parent | 17735bd9822900d82278842f6bbe7a0e1c64c3b1 (diff) |
bridge-netfilter: don't overwrite memory outside of skb
The bridge netfilter code needs to check for space at the
front of the skb before overwriting; otherwise if skb from
device doesn't have headroom, then it will cause random
memory corruption.
Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
-rw-r--r-- | include/linux/netfilter_bridge.h | 15 | ||||
-rw-r--r-- | net/bridge/br_forward.c | 10 |
2 files changed, 19 insertions, 6 deletions
diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h index de4d397865ce..52502000bbca 100644 --- a/include/linux/netfilter_bridge.h +++ b/include/linux/netfilter_bridge.h @@ -65,16 +65,25 @@ struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb) } /* Only used in br_forward.c */ -static inline -void nf_bridge_maybe_copy_header(struct sk_buff *skb) +static inline int nf_bridge_maybe_copy_header(struct sk_buff *skb) { + int err; + if (skb->nf_bridge) { if (skb->protocol == __constant_htons(ETH_P_8021Q)) { + err = skb_cow(skb, 18); + if (err) + return err; memcpy(skb->data - 18, skb->nf_bridge->data, 18); skb_push(skb, 4); - } else + } else { + err = skb_cow(skb, 16); + if (err) + return err; memcpy(skb->data - 16, skb->nf_bridge->data, 16); + } } + return 0; } static inline diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index 2d24fb400e0c..dac7f0698193 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c @@ -37,11 +37,15 @@ int br_dev_queue_push_xmit(struct sk_buff *skb) else { #ifdef CONFIG_BRIDGE_NETFILTER /* ip_refrag calls ip_fragment, doesn't copy the MAC header. */ - nf_bridge_maybe_copy_header(skb); + if (nf_bridge_maybe_copy_header(skb)) + kfree_skb(skb); + else #endif - skb_push(skb, ETH_HLEN); + { + skb_push(skb, ETH_HLEN); - dev_queue_xmit(skb); + dev_queue_xmit(skb); + } } return 0; |