[NET]: Disable netfilter sockopts when not in the initial network namespace
[pandora-kernel.git] / net / netfilter / nf_sockopt.c
index 0a63d7d..aa28315 100644 (file)
@@ -1,4 +1,3 @@
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
@@ -33,13 +32,13 @@ int nf_register_sockopt(struct nf_sockopt_ops *reg)
        list_for_each(i, &nf_sockopts) {
                struct nf_sockopt_ops *ops = (struct nf_sockopt_ops *)i;
                if (ops->pf == reg->pf
-                   && (overlap(ops->set_optmin, ops->set_optmax, 
+                   && (overlap(ops->set_optmin, ops->set_optmax,
                                reg->set_optmin, reg->set_optmax)
-                       || overlap(ops->get_optmin, ops->get_optmax, 
+                       || overlap(ops->get_optmin, ops->get_optmax,
                                   reg->get_optmin, reg->get_optmax))) {
                        NFDEBUG("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u\n",
-                               ops->set_optmin, ops->set_optmax, 
-                               ops->get_optmin, ops->get_optmax, 
+                               ops->set_optmin, ops->set_optmax,
+                               ops->get_optmin, ops->get_optmax,
                                reg->set_optmin, reg->set_optmax,
                                reg->get_optmin, reg->get_optmax);
                        ret = -EBUSY;
@@ -56,41 +55,34 @@ EXPORT_SYMBOL(nf_register_sockopt);
 
 void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
 {
-       /* No point being interruptible: we're probably in cleanup_module() */
- restart:
        mutex_lock(&nf_sockopt_mutex);
-       if (reg->use != 0) {
-               /* To be woken by nf_sockopt call... */
-               /* FIXME: Stuart Young's name appears gratuitously. */
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               reg->cleanup_task = current;
-               mutex_unlock(&nf_sockopt_mutex);
-               schedule();
-               goto restart;
-       }
        list_del(&reg->list);
        mutex_unlock(&nf_sockopt_mutex);
 }
 EXPORT_SYMBOL(nf_unregister_sockopt);
 
 /* Call get/setsockopt() */
-static int nf_sockopt(struct sock *sk, int pf, int val, 
+static int nf_sockopt(struct sock *sk, int pf, int val,
                      char __user *opt, int *len, int get)
 {
        struct list_head *i;
        struct nf_sockopt_ops *ops;
        int ret;
 
+       if (sk->sk_net != &init_net)
+               return -ENOPROTOOPT;
+
        if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0)
                return -EINTR;
 
        list_for_each(i, &nf_sockopts) {
                ops = (struct nf_sockopt_ops *)i;
                if (ops->pf == pf) {
+                       if (!try_module_get(ops->owner))
+                               goto out_nosup;
                        if (get) {
                                if (val >= ops->get_optmin
                                    && val < ops->get_optmax) {
-                                       ops->use++;
                                        mutex_unlock(&nf_sockopt_mutex);
                                        ret = ops->get(sk, val, opt, len);
                                        goto out;
@@ -98,23 +90,20 @@ static int nf_sockopt(struct sock *sk, int pf, int val,
                        } else {
                                if (val >= ops->set_optmin
                                    && val < ops->set_optmax) {
-                                       ops->use++;
                                        mutex_unlock(&nf_sockopt_mutex);
                                        ret = ops->set(sk, val, opt, *len);
                                        goto out;
                                }
                        }
+                       module_put(ops->owner);
                }
        }
+ out_nosup:
        mutex_unlock(&nf_sockopt_mutex);
        return -ENOPROTOOPT;
-       
+
  out:
-       mutex_lock(&nf_sockopt_mutex);
-       ops->use--;
-       if (ops->cleanup_task)
-               wake_up_process(ops->cleanup_task);
-       mutex_unlock(&nf_sockopt_mutex);
+       module_put(ops->owner);
        return ret;
 }
 
@@ -139,16 +128,22 @@ static int compat_nf_sockopt(struct sock *sk, int pf, int val,
        struct nf_sockopt_ops *ops;
        int ret;
 
+       if (sk->sk_net != &init_net)
+               return -ENOPROTOOPT;
+
+
        if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0)
                return -EINTR;
 
        list_for_each(i, &nf_sockopts) {
                ops = (struct nf_sockopt_ops *)i;
                if (ops->pf == pf) {
+                       if (!try_module_get(ops->owner))
+                               goto out_nosup;
+
                        if (get) {
                                if (val >= ops->get_optmin
                                    && val < ops->get_optmax) {
-                                       ops->use++;
                                        mutex_unlock(&nf_sockopt_mutex);
                                        if (ops->compat_get)
                                                ret = ops->compat_get(sk,
@@ -161,7 +156,6 @@ static int compat_nf_sockopt(struct sock *sk, int pf, int val,
                        } else {
                                if (val >= ops->set_optmin
                                    && val < ops->set_optmax) {
-                                       ops->use++;
                                        mutex_unlock(&nf_sockopt_mutex);
                                        if (ops->compat_set)
                                                ret = ops->compat_set(sk,
@@ -172,17 +166,15 @@ static int compat_nf_sockopt(struct sock *sk, int pf, int val,
                                        goto out;
                                }
                        }
+                       module_put(ops->owner);
                }
        }
+ out_nosup:
        mutex_unlock(&nf_sockopt_mutex);
        return -ENOPROTOOPT;
 
  out:
-       mutex_lock(&nf_sockopt_mutex);
-       ops->use--;
-       if (ops->cleanup_task)
-               wake_up_process(ops->cleanup_task);
-       mutex_unlock(&nf_sockopt_mutex);
+       module_put(ops->owner);
        return ret;
 }