bridge-netfilter: don't overwrite memory outside of skb
authorStephen Hemminger <shemminger@osdl.org>
Wed, 23 Aug 2006 00:19:28 +0000 (17:19 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 8 Sep 2006 21:51:37 +0000 (14:51 -0700)
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: Greg Kroah-Hartman <gregkh@suse.de>
include/linux/netfilter_bridge.h
net/bridge/br_forward.c

index a75b84bb9a884db6c71b4153613a8365b980a2a9..178a97e1a4d25258861b35a3c16844b4d1357927 100644 (file)
@@ -47,18 +47,26 @@ enum nf_br_hook_priorities {
 #define BRNF_BRIDGED                   0x08
 #define BRNF_NF_BRIDGE_PREROUTING      0x10
 
-
 /* 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;
 }
 
 /* This is called by the IP fragmenting code and it ensures there is
index 56f3aa47e758f40dab34a007d8eeb50940046190..ddb7e1cedc1998dfdcefb91367befe83edad8cd8 100644 (file)
@@ -43,11 +43,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;