: bridge-netfilter: fix net_device refcnt leaks
Subsystems (3)
PATCH 2/2 : bridge-netfilter: fix net_device refcnt leaks
commit 6738b41be08760572a3fd013c57b4554de0080f5
Author: Patrick McHardy <[email protected]> Date: Tue Jan 29 19:02:59 2008 +0100
[NETFILTER]: bridge-netfilter: fix net_device refcnt leaks
Upstream commit 2dc2f207fb251666d2396fe1a69272b307ecc333
When packets are flood-forwarded to multiple output devices, the bridge-netfilter code reuses skb->nf_bridge for each clone to store the bridge port. When queueing packets using NFQUEUE netfilter takes a reference to skb->nf_bridge->physoutdev, which is overwritten when the packet is forwarded to the second port. This causes refcount unterflows for the first device and refcount leaks for all others. Additionally this provides incorrect data to the iptables physdev match.
Unshare skb->nf_bridge by copying it if it is shared before assigning the physoutdev device.
Reported, tested and based on initial patch by Jan Christoph Nordholz <[email protected]>.
net/bridge/br_netfilter.c +27 -0
@@ -142,6 +142,23 @@ static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb)return skb->nf_bridge; } +static inline struct nf_bridge_info *nf_bridge_unshare (struct sk_buff *skb) +{ +struct nf_bridge_info *nf_bridge = skb->nf_bridge; + +if (atomic_read (&nf_bridge->use) >1 ) { +struct nf_bridge_info *tmp =nf_bridge_alloc (skb); + +if (tmp) { +memcpy (tmp, nf_bridge,sizeof (struct nf_bridge_info )); +atomic_set (&tmp->use,1 ); +nf_bridge_put (nf_bridge); + } + nf_bridge = tmp; + } +return nf_bridge; +} +static inline void nf_bridge_push_encap_header (struct sk_buff *skb) {unsigned int len =nf_bridge_encap_header_len (skb);
@@ -644,6 +661,11 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff **pskb,if (!skb->nf_bridge)return NF_ACCEPT ; +/* Need exclusive nf_bridge_info since we might have multiple +* different physoutdevs. */ +if (!nf_bridge_unshare (skb)) +return NF_DROP ; + parent =bridge_parent (out);if (!parent)return NF_DROP ;
@@ -727,6 +749,11 @@ static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb,if (!skb->nf_bridge)return NF_ACCEPT ; +/* Need exclusive nf_bridge_info since we might have multiple +* different physoutdevs. */ +if (!nf_bridge_unshare (skb)) +return NF_DROP ; + nf_bridge = skb->nf_bridge;if (!(nf_bridge->mask &BRNF_BRIDGED_DNAT ))return NF_ACCEPT ;
patch netfilter-bridge-netfilter-fix-net_device-refcnt-leaks.patch queued to -stable tree
This is a note to let you know that we have just queued up the patch titled
Subject: Netfilter: bridge-netfilter: fix net_device refcnt leaks
to the 2.6.23-stable tree. Its filename is
netfilter-bridge-netfilter-fix-net_device-refcnt-leaks.patch
A git repo of this tree can be found at
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
Quoted 1 line
From [email protected] Tue Jan 29 10:09:08 2008
From: Patrick McHardy <[email protected]>
Date: Tue, 29 Jan 2008 19:08:28 +0100
Subject: Netfilter: bridge-netfilter: fix net_device refcnt leaks
To: [email protected]
Cc: Netfilter Development Mailinglist <[email protected]>, "David S. Miller" <[email protected]>
Message-ID: <[email protected]>
From: Patrick McHardy <[email protected]>
[NETFILTER]: bridge-netfilter: fix net_device refcnt leaks
Upstream commit 2dc2f207fb251666d2396fe1a69272b307ecc333
When packets are flood-forwarded to multiple output devices, the bridge-netfilter code reuses skb->nf_bridge for each clone to store the bridge port. When queueing packets using NFQUEUE netfilter takes a reference to skb->nf_bridge->physoutdev, which is overwritten when the packet is forwarded to the second port. This causes refcount unterflows for the first device and refcount leaks for all others. Additionally this provides incorrect data to the iptables physdev match.
Unshare skb->nf_bridge by copying it if it is shared before assigning the physoutdev device.
Reported, tested and based on initial patch by Jan Christoph Nordholz <[email protected]>.
--- net/bridge/br_netfilter.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
net/bridge/br_netfilter.c +27 -0
@@ -142,6 +142,23 @@ static inline struct nf_bridge_info *nf_return skb->nf_bridge; } +static inline struct nf_bridge_info *nf_bridge_unshare (struct sk_buff *skb) +{ +struct nf_bridge_info *nf_bridge = skb->nf_bridge; + +if (atomic_read (&nf_bridge->use) >1 ) { +struct nf_bridge_info *tmp =nf_bridge_alloc (skb); + +if (tmp) { +memcpy (tmp, nf_bridge,sizeof (struct nf_bridge_info )); +atomic_set (&tmp->use,1 ); +nf_bridge_put (nf_bridge); + } + nf_bridge = tmp; + } +return nf_bridge; +} +static inline void nf_bridge_push_encap_header (struct sk_buff *skb) {unsigned int len =nf_bridge_encap_header_len (skb);
@@ -644,6 +661,11 @@ static unsigned int br_nf_forward_ip(unsif (!skb->nf_bridge)return NF_ACCEPT ; +/* Need exclusive nf_bridge_info since we might have multiple +* different physoutdevs. */ +if (!nf_bridge_unshare (skb)) +return NF_DROP ; + parent =bridge_parent (out);if (!parent)return NF_DROP ;
@@ -727,6 +749,11 @@ static unsigned int br_nf_local_out(unsiif (!skb->nf_bridge)return NF_ACCEPT ; +/* Need exclusive nf_bridge_info since we might have multiple +* different physoutdevs. */ +if (!nf_bridge_unshare (skb)) +return NF_DROP ; + nf_bridge = skb->nf_bridge;if (!(nf_bridge->mask &BRNF_BRIDGED_DNAT ))return NF_ACCEPT ;
Patches currently in stable-queue which might be from [email protected] are
queue-2.6.23/netfilter-bridge-fix-double-post_routing-invocation.patch queue-2.6.23/netfilter-bridge-netfilter-fix-net_device-refcnt-leaks.patch