Commit daaa8be2 authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller

[NETFILTER]: nf_queue: clean up error paths

Move duplicated error handling to end of function and add a helper function
to release the device and module references from the queue entry.
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4b3d15ef
...@@ -80,6 +80,27 @@ void nf_unregister_queue_handlers(const struct nf_queue_handler *qh) ...@@ -80,6 +80,27 @@ void nf_unregister_queue_handlers(const struct nf_queue_handler *qh)
} }
EXPORT_SYMBOL_GPL(nf_unregister_queue_handlers); EXPORT_SYMBOL_GPL(nf_unregister_queue_handlers);
static void nf_queue_entry_release_refs(struct nf_queue_entry *entry)
{
/* Release those devices we held, or Alexey will kill me. */
if (entry->indev)
dev_put(entry->indev);
if (entry->outdev)
dev_put(entry->outdev);
#ifdef CONFIG_BRIDGE_NETFILTER
if (entry->skb->nf_bridge) {
struct nf_bridge_info *nf_bridge = entry->skb->nf_bridge;
if (nf_bridge->physindev)
dev_put(nf_bridge->physindev);
if (nf_bridge->physoutdev)
dev_put(nf_bridge->physoutdev);
}
#endif
/* Drop reference to owner of hook which queued us. */
module_put(entry->elem->owner);
}
/* /*
* Any packet that leaves via this function must come back * Any packet that leaves via this function must come back
* through nf_reinject(). * through nf_reinject().
...@@ -93,10 +114,10 @@ static int __nf_queue(struct sk_buff *skb, ...@@ -93,10 +114,10 @@ static int __nf_queue(struct sk_buff *skb,
unsigned int queuenum) unsigned int queuenum)
{ {
int status; int status;
struct nf_queue_entry *entry; struct nf_queue_entry *entry = NULL;
#ifdef CONFIG_BRIDGE_NETFILTER #ifdef CONFIG_BRIDGE_NETFILTER
struct net_device *physindev = NULL; struct net_device *physindev;
struct net_device *physoutdev = NULL; struct net_device *physoutdev;
#endif #endif
struct nf_afinfo *afinfo; struct nf_afinfo *afinfo;
const struct nf_queue_handler *qh; const struct nf_queue_handler *qh;
...@@ -105,28 +126,16 @@ static int __nf_queue(struct sk_buff *skb, ...@@ -105,28 +126,16 @@ static int __nf_queue(struct sk_buff *skb,
rcu_read_lock(); rcu_read_lock();
qh = rcu_dereference(queue_handler[pf]); qh = rcu_dereference(queue_handler[pf]);
if (!qh) { if (!qh)
rcu_read_unlock(); goto err_unlock;
kfree_skb(skb);
return 1;
}
afinfo = nf_get_afinfo(pf); afinfo = nf_get_afinfo(pf);
if (!afinfo) { if (!afinfo)
rcu_read_unlock(); goto err_unlock;
kfree_skb(skb);
return 1;
}
entry = kmalloc(sizeof(*entry) + afinfo->route_key_size, GFP_ATOMIC); entry = kmalloc(sizeof(*entry) + afinfo->route_key_size, GFP_ATOMIC);
if (!entry) { if (!entry)
if (net_ratelimit()) goto err_unlock;
printk(KERN_ERR "OOM queueing packet %p\n",
skb);
rcu_read_unlock();
kfree_skb(skb);
return 1;
}
*entry = (struct nf_queue_entry) { *entry = (struct nf_queue_entry) {
.skb = skb, .skb = skb,
...@@ -166,25 +175,18 @@ static int __nf_queue(struct sk_buff *skb, ...@@ -166,25 +175,18 @@ static int __nf_queue(struct sk_buff *skb,
rcu_read_unlock(); rcu_read_unlock();
if (status < 0) { if (status < 0) {
/* James M doesn't say fuck enough. */ nf_queue_entry_release_refs(entry);
if (indev) goto err;
dev_put(indev);
if (outdev)
dev_put(outdev);
#ifdef CONFIG_BRIDGE_NETFILTER
if (physindev)
dev_put(physindev);
if (physoutdev)
dev_put(physoutdev);
#endif
module_put(entry->elem->owner);
kfree(entry);
kfree_skb(skb);
return 1;
} }
return 1; return 1;
err_unlock:
rcu_read_unlock();
err:
kfree_skb(skb);
kfree(entry);
return 1;
} }
int nf_queue(struct sk_buff *skb, int nf_queue(struct sk_buff *skb,
...@@ -235,22 +237,7 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) ...@@ -235,22 +237,7 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
rcu_read_lock(); rcu_read_lock();
/* Release those devices we held, or Alexey will kill me. */ nf_queue_entry_release_refs(entry);
if (entry->indev)
dev_put(entry->indev);
if (entry->outdev)
dev_put(entry->outdev);
#ifdef CONFIG_BRIDGE_NETFILTER
if (skb->nf_bridge) {
if (skb->nf_bridge->physindev)
dev_put(skb->nf_bridge->physindev);
if (skb->nf_bridge->physoutdev)
dev_put(skb->nf_bridge->physoutdev);
}
#endif
/* Drop reference to owner of hook which queued us. */
module_put(entry->elem->owner);
/* Continue traversal iff userspace said ok... */ /* Continue traversal iff userspace said ok... */
if (verdict == NF_REPEAT) { if (verdict == NF_REPEAT) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment