From: Stephen Hemminger Date: Wed, 23 Aug 2006 00:19:28 +0000 (-0700) Subject: bridge-netfilter: don't overwrite memory outside of skb X-Git-Tag: v2.6.17.12~32 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9d3925d7a0eb89385cfef62020578baff230dfce;p=thirdparty%2Fkernel%2Fstable.git 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 Signed-off-by: Greg Kroah-Hartman --- diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h index a75b84bb9a884..178a97e1a4d25 100644 --- a/include/linux/netfilter_bridge.h +++ b/include/linux/netfilter_bridge.h @@ -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 diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index 56f3aa47e758f..ddb7e1cedc199 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c @@ -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;