summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2006-12-18 20:51:43 +0100
committerAdrian Bunk <bunk@stusta.de>2006-12-18 20:51:43 +0100
commitd0354e3ba19cdf9acc2ca89bbb59b1e6292a4f44 (patch)
treee2de02bc6b0b1f1f67f33608bbbd9cf83c73c638
parent17735bd9822900d82278842f6bbe7a0e1c64c3b1 (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.h15
-rw-r--r--net/bridge/br_forward.c10
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;