]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
bridge-netfilter: don't overwrite memory outside of skb
authorStephen Hemminger <shemminger@osdl.org>
Mon, 18 Dec 2006 19:51:43 +0000 (20:51 +0100)
committerAdrian Bunk <bunk@stusta.de>
Mon, 18 Dec 2006 19:51:43 +0000 (20:51 +0100)
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>
include/linux/netfilter_bridge.h
net/bridge/br_forward.c

index de4d397865ce52e440f2a93cb75f87ba53dfdcc0..52502000bbca553f4f1e5c07d2fd93653a833169 100644 (file)
@@ -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
index 2d24fb400e0cbbd79ef064758b69bbebf07e0ccb..dac7f0698193f3804c98353ad6990ea39a767dbb 100644 (file)
@@ -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;