Merge branch 'master' of /repos/git/net-next-2.6
[safe/jmp/linux-2.6] / net / bridge / netfilter / ebtables.c
index 7d8ead5..208f4e3 100644 (file)
@@ -55,7 +55,6 @@
 
 
 static DEFINE_MUTEX(ebt_mutex);
-static LIST_HEAD(ebt_tables);
 
 static struct xt_target ebt_standard_target = {
        .name       = "standard",
@@ -64,32 +63,35 @@ static struct xt_target ebt_standard_target = {
        .targetsize = sizeof(int),
 };
 
-static inline int ebt_do_watcher (struct ebt_entry_watcher *w,
-   struct sk_buff *skb, unsigned int hooknr, const struct net_device *in,
-   const struct net_device *out)
+static inline int
+ebt_do_watcher(const struct ebt_entry_watcher *w, struct sk_buff *skb,
+              struct xt_target_param *par)
 {
-       w->u.watcher->target(skb, in, out, hooknr, w->u.watcher, w->data);
+       par->target   = w->u.watcher;
+       par->targinfo = w->data;
+       w->u.watcher->target(skb, par);
        /* watchers don't give a verdict */
        return 0;
 }
 
 static inline int ebt_do_match (struct ebt_entry_match *m,
-   const struct sk_buff *skb, const struct net_device *in,
-   const struct net_device *out, bool *hotdrop)
+   const struct sk_buff *skb, struct xt_match_param *par)
 {
-       return m->u.match->match(skb, in, out, m->u.match,
-              m->data, 0, 0, hotdrop);
+       par->match     = m->u.match;
+       par->matchinfo = m->data;
+       return m->u.match->match(skb, par) ? EBT_MATCH : EBT_NOMATCH;
 }
 
 static inline int ebt_dev_check(char *entry, const struct net_device *device)
 {
        int i = 0;
-       const char *devname = device->name;
+       const char *devname;
 
        if (*entry == '\0')
                return 0;
        if (!device)
                return 1;
+       devname = device->name;
        /* 1 is the wildcard token */
        while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i])
                i++;
@@ -140,6 +142,12 @@ static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h,
        return 0;
 }
 
+static inline __pure
+struct ebt_entry *ebt_next_entry(const struct ebt_entry *entry)
+{
+       return (void *)entry + entry->next_offset;
+}
+
 /* Do some firewalling */
 unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
    const struct net_device *in, const struct net_device *out,
@@ -155,6 +163,14 @@ unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
        char *base;
        struct ebt_table_info *private;
        bool hotdrop = false;
+       struct xt_match_param mtpar;
+       struct xt_target_param tgpar;
+
+       mtpar.family  = tgpar.family = NFPROTO_BRIDGE;
+       mtpar.in      = tgpar.in  = in;
+       mtpar.out     = tgpar.out = out;
+       mtpar.hotdrop = &hotdrop;
+       mtpar.hooknum = tgpar.hooknum = hook;
 
        read_lock_bh(&table->lock);
        private = table->private;
@@ -175,8 +191,7 @@ unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
                if (ebt_basic_match(point, eth_hdr(skb), in, out))
                        goto letscontinue;
 
-               if (EBT_MATCH_ITERATE(point, ebt_do_match, skb,
-                   in, out, &hotdrop) != 0)
+               if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, &mtpar) != 0)
                        goto letscontinue;
                if (hotdrop) {
                        read_unlock_bh(&table->lock);
@@ -189,17 +204,18 @@ unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
 
                /* these should only watch: not modify, nor tell us
                   what to do with the packet */
-               EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, hook, in,
-                  out);
+               EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, &tgpar);
 
                t = (struct ebt_entry_target *)
                   (((char *)point) + point->target_offset);
                /* standard target */
                if (!t->u.target->target)
                        verdict = ((struct ebt_standard_target *)t)->verdict;
-               else
-                       verdict = t->u.target->target(skb, in, out, hook,
-                                 t->u.target, t->data);
+               else {
+                       tgpar.target   = t->u.target;
+                       tgpar.targinfo = t->data;
+                       verdict = t->u.target->target(skb, &tgpar);
+               }
                if (verdict == EBT_ACCEPT) {
                        read_unlock_bh(&table->lock);
                        return NF_ACCEPT;
@@ -239,8 +255,7 @@ letsreturn:
                /* jump to a udc */
                cs[sp].n = i + 1;
                cs[sp].chaininfo = chaininfo;
-               cs[sp].e = (struct ebt_entry *)
-                  (((char *)point) + point->next_offset);
+               cs[sp].e = ebt_next_entry(point);
                i = 0;
                chaininfo = (struct ebt_entries *) (base + verdict);
 #ifdef CONFIG_NETFILTER_DEBUG
@@ -256,8 +271,7 @@ letsreturn:
                sp++;
                continue;
 letscontinue:
-               point = (struct ebt_entry *)
-                  (((char *)point) + point->next_offset);
+               point = ebt_next_entry(point);
                i++;
        }
 
@@ -295,34 +309,28 @@ find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
        return NULL;
 }
 
-#ifndef CONFIG_KMOD
-#define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
-#else
 static void *
 find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
    int *error, struct mutex *mutex)
 {
-       void *ret;
-
-       ret = find_inlist_lock_noload(head, name, error, mutex);
-       if (!ret) {
-               request_module("%s%s", prefix, name);
-               ret = find_inlist_lock_noload(head, name, error, mutex);
-       }
-       return ret;
+       return try_then_request_module(
+                       find_inlist_lock_noload(head, name, error, mutex),
+                       "%s%s", prefix, name);
 }
-#endif
 
 static inline struct ebt_table *
-find_table_lock(const char *name, int *error, struct mutex *mutex)
+find_table_lock(struct net *net, const char *name, int *error,
+               struct mutex *mutex)
 {
-       return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex);
+       return find_inlist_lock(&net->xt.tables[NFPROTO_BRIDGE], name,
+                               "ebtable_", error, mutex);
 }
 
 static inline int
-ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e,
-   const char *name, unsigned int hookmask, unsigned int *cnt)
+ebt_check_match(struct ebt_entry_match *m, struct xt_mtchk_param *par,
+               unsigned int *cnt)
 {
+       const struct ebt_entry *e = par->entryinfo;
        struct xt_match *match;
        size_t left = ((char *)e + e->watchers_offset) - (char *)m;
        int ret;
@@ -339,16 +347,13 @@ ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e,
                return -ENOENT;
        m->u.match = match;
 
-       ret = xt_check_match(match, NFPROTO_BRIDGE, m->match_size,
-             name, hookmask, e->ethproto, e->invflags & EBT_IPROTO);
+       par->match     = match;
+       par->matchinfo = m->data;
+       ret = xt_check_match(par, m->match_size,
+             e->ethproto, e->invflags & EBT_IPROTO);
        if (ret < 0) {
                module_put(match->me);
                return ret;
-       } else if (match->checkentry != NULL &&
-           !match->checkentry(name, e, NULL, m->data, hookmask)) {
-               module_put(match->me);
-               BUGPRINT("match->check failed\n");
-               return -EINVAL;
        }
 
        (*cnt)++;
@@ -356,9 +361,10 @@ ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e,
 }
 
 static inline int
-ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,
-   const char *name, unsigned int hookmask, unsigned int *cnt)
+ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
+                 unsigned int *cnt)
 {
+       const struct ebt_entry *e = par->entryinfo;
        struct xt_target *watcher;
        size_t left = ((char *)e + e->target_offset) - (char *)w;
        int ret;
@@ -376,16 +382,13 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,
                return -ENOENT;
        w->u.watcher = watcher;
 
-       ret = xt_check_target(watcher, NFPROTO_BRIDGE, w->watcher_size,
-             name, hookmask, e->ethproto, e->invflags & EBT_IPROTO);
+       par->target   = watcher;
+       par->targinfo = w->data;
+       ret = xt_check_target(par, w->watcher_size,
+             e->ethproto, e->invflags & EBT_IPROTO);
        if (ret < 0) {
                module_put(watcher->me);
                return ret;
-       } else if (watcher->checkentry != NULL &&
-           !watcher->checkentry(name, e, NULL, w->data, hookmask)) {
-               module_put(watcher->me);
-               BUGPRINT("watcher->check failed\n");
-               return -EINVAL;
        }
 
        (*cnt)++;
@@ -558,32 +561,45 @@ ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
 }
 
 static inline int
-ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i)
+ebt_cleanup_match(struct ebt_entry_match *m, struct net *net, unsigned int *i)
 {
+       struct xt_mtdtor_param par;
+
        if (i && (*i)-- == 0)
                return 1;
-       if (m->u.match->destroy)
-               m->u.match->destroy(m->u.match, m->data);
-       module_put(m->u.match->me);
 
+       par.net       = net;
+       par.match     = m->u.match;
+       par.matchinfo = m->data;
+       par.family    = NFPROTO_BRIDGE;
+       if (par.match->destroy != NULL)
+               par.match->destroy(&par);
+       module_put(par.match->me);
        return 0;
 }
 
 static inline int
-ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
+ebt_cleanup_watcher(struct ebt_entry_watcher *w, struct net *net, unsigned int *i)
 {
+       struct xt_tgdtor_param par;
+
        if (i && (*i)-- == 0)
                return 1;
-       if (w->u.watcher->destroy)
-               w->u.watcher->destroy(w->u.watcher, w->data);
-       module_put(w->u.watcher->me);
 
+       par.net      = net;
+       par.target   = w->u.watcher;
+       par.targinfo = w->data;
+       par.family   = NFPROTO_BRIDGE;
+       if (par.target->destroy != NULL)
+               par.target->destroy(&par);
+       module_put(par.target->me);
        return 0;
 }
 
 static inline int
-ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
+ebt_cleanup_entry(struct ebt_entry *e, struct net *net, unsigned int *cnt)
 {
+       struct xt_tgdtor_param par;
        struct ebt_entry_target *t;
 
        if (e->bitmask == 0)
@@ -591,18 +607,24 @@ ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
        /* we're done */
        if (cnt && (*cnt)-- == 0)
                return 1;
-       EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
-       EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL);
+       EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, net, NULL);
+       EBT_MATCH_ITERATE(e, ebt_cleanup_match, net, NULL);
        t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
-       if (t->u.target->destroy)
-               t->u.target->destroy(t->u.target, t->data);
-       module_put(t->u.target->me);
 
+       par.net      = net;
+       par.target   = t->u.target;
+       par.targinfo = t->data;
+       par.family   = NFPROTO_BRIDGE;
+       if (par.target->destroy != NULL)
+               par.target->destroy(&par);
+       module_put(par.target->me);
        return 0;
 }
 
 static inline int
-ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
+ebt_check_entry(struct ebt_entry *e,
+   struct net *net,
+   struct ebt_table_info *newinfo,
    const char *name, unsigned int *cnt,
    struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
 {
@@ -611,6 +633,8 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
        unsigned int i, j, hook = 0, hookmask = 0;
        size_t gap;
        int ret;
+       struct xt_mtchk_param mtpar;
+       struct xt_tgchk_param tgpar;
 
        /* don't mess with the struct ebt_entries */
        if (e->bitmask == 0)
@@ -651,11 +675,17 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
                        hookmask = cl_s[i - 1].hookmask;
        }
        i = 0;
-       ret = EBT_MATCH_ITERATE(e, ebt_check_match, e, name, hookmask, &i);
+
+       mtpar.net       = tgpar.net       = net;
+       mtpar.table     = tgpar.table     = name;
+       mtpar.entryinfo = tgpar.entryinfo = e;
+       mtpar.hook_mask = tgpar.hook_mask = hookmask;
+       mtpar.family    = tgpar.family    = NFPROTO_BRIDGE;
+       ret = EBT_MATCH_ITERATE(e, ebt_check_match, &mtpar, &i);
        if (ret != 0)
                goto cleanup_matches;
        j = 0;
-       ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, e, name, hookmask, &j);
+       ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, &tgpar, &j);
        if (ret != 0)
                goto cleanup_watchers;
        t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
@@ -691,23 +721,20 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
                goto cleanup_watchers;
        }
 
-       ret = xt_check_target(target, NFPROTO_BRIDGE, t->target_size,
-             name, hookmask, e->ethproto, e->invflags & EBT_IPROTO);
+       tgpar.target   = target;
+       tgpar.targinfo = t->data;
+       ret = xt_check_target(&tgpar, t->target_size,
+             e->ethproto, e->invflags & EBT_IPROTO);
        if (ret < 0) {
                module_put(target->me);
                goto cleanup_watchers;
-       } else if (t->u.target->checkentry &&
-           !t->u.target->checkentry(name, e, NULL, t->data, hookmask)) {
-               module_put(t->u.target->me);
-               ret = -EINVAL;
-               goto cleanup_watchers;
        }
        (*cnt)++;
        return 0;
 cleanup_watchers:
-       EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);
+       EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, net, &j);
 cleanup_matches:
-       EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i);
+       EBT_MATCH_ITERATE(e, ebt_cleanup_match, net, &i);
        return ret;
 }
 
@@ -770,7 +797,7 @@ static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s
                        /* this can't be 0, so the loop test is correct */
                        cl_s[i].cs.n = pos + 1;
                        pos = 0;
-                       cl_s[i].cs.e = ((void *)e + e->next_offset);
+                       cl_s[i].cs.e = ebt_next_entry(e);
                        e = (struct ebt_entry *)(hlp2->data);
                        nentries = hlp2->nentries;
                        cl_s[i].from = chain_nr;
@@ -780,14 +807,15 @@ static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s
                        continue;
                }
 letscontinue:
-               e = (void *)e + e->next_offset;
+               e = ebt_next_entry(e);
                pos++;
        }
        return 0;
 }
 
 /* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
-static int translate_table(char *name, struct ebt_table_info *newinfo)
+static int translate_table(struct net *net, char *name,
+                          struct ebt_table_info *newinfo)
 {
        unsigned int i, j, k, udc_cnt;
        int ret;
@@ -896,10 +924,10 @@ static int translate_table(char *name, struct ebt_table_info *newinfo)
        /* used to know what we need to clean up if something goes wrong */
        i = 0;
        ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
-          ebt_check_entry, newinfo, name, &i, cl_s, udc_cnt);
+          ebt_check_entry, net, newinfo, name, &i, cl_s, udc_cnt);
        if (ret != 0) {
                EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
-                  ebt_cleanup_entry, &i);
+                                 ebt_cleanup_entry, net, &i);
        }
        vfree(cl_s);
        return ret;
@@ -929,7 +957,7 @@ static void get_counters(struct ebt_counter *oldcounters,
 }
 
 /* replace the table */
-static int do_replace(void __user *user, unsigned int len)
+static int do_replace(struct net *net, void __user *user, unsigned int len)
 {
        int ret, i, countersize;
        struct ebt_table_info *newinfo;
@@ -996,12 +1024,12 @@ static int do_replace(void __user *user, unsigned int len)
        if (ret != 0)
                goto free_counterstmp;
 
-       ret = translate_table(tmp.name, newinfo);
+       ret = translate_table(net, tmp.name, newinfo);
 
        if (ret != 0)
                goto free_counterstmp;
 
-       t = find_table_lock(tmp.name, &ret, &ebt_mutex);
+       t = find_table_lock(net, tmp.name, &ret, &ebt_mutex);
        if (!t) {
                ret = -ENOENT;
                goto free_iterate;
@@ -1049,7 +1077,7 @@ static int do_replace(void __user *user, unsigned int len)
 
        /* decrease module count and free resources */
        EBT_ENTRY_ITERATE(table->entries, table->entries_size,
-          ebt_cleanup_entry, NULL);
+                         ebt_cleanup_entry, net, NULL);
 
        vfree(table->entries);
        if (table->chainstack) {
@@ -1066,7 +1094,7 @@ free_unlock:
        mutex_unlock(&ebt_mutex);
 free_iterate:
        EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
-          ebt_cleanup_entry, NULL);
+                         ebt_cleanup_entry, net, NULL);
 free_counterstmp:
        vfree(counterstmp);
        /* can be initialized in translate_table() */
@@ -1082,26 +1110,34 @@ free_newinfo:
        return ret;
 }
 
-int ebt_register_table(struct ebt_table *table)
+struct ebt_table *
+ebt_register_table(struct net *net, const struct ebt_table *input_table)
 {
        struct ebt_table_info *newinfo;
-       struct ebt_table *t;
+       struct ebt_table *t, *table;
        struct ebt_replace_kernel *repl;
        int ret, i, countersize;
        void *p;
 
-       if (!table || !(repl = table->table) || !repl->entries ||
-           repl->entries_size == 0 ||
-           repl->counters || table->private) {
+       if (input_table == NULL || (repl = input_table->table) == NULL ||
+           repl->entries == 0 || repl->entries_size == 0 ||
+           repl->counters != NULL || input_table->private != NULL) {
                BUGPRINT("Bad table data for ebt_register_table!!!\n");
-               return -EINVAL;
+               return ERR_PTR(-EINVAL);
+       }
+
+       /* Don't add one table to multiple lists. */
+       table = kmemdup(input_table, sizeof(struct ebt_table), GFP_KERNEL);
+       if (!table) {
+               ret = -ENOMEM;
+               goto out;
        }
 
        countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
        newinfo = vmalloc(sizeof(*newinfo) + countersize);
        ret = -ENOMEM;
        if (!newinfo)
-               return -ENOMEM;
+               goto free_table;
 
        p = vmalloc(repl->entries_size);
        if (!p)
@@ -1125,7 +1161,7 @@ int ebt_register_table(struct ebt_table *table)
                        newinfo->hook_entry[i] = p +
                                ((char *)repl->hook_entry[i] - repl->entries);
        }
-       ret = translate_table(repl->name, newinfo);
+       ret = translate_table(net, repl->name, newinfo);
        if (ret != 0) {
                BUGPRINT("Translate_table failed\n");
                goto free_chainstack;
@@ -1133,7 +1169,7 @@ int ebt_register_table(struct ebt_table *table)
 
        if (table->check && table->check(newinfo, table->valid_hooks)) {
                BUGPRINT("The table doesn't like its own initial data, lol\n");
-               return -EINVAL;
+               return ERR_PTR(-EINVAL);
        }
 
        table->private = newinfo;
@@ -1142,7 +1178,7 @@ int ebt_register_table(struct ebt_table *table)
        if (ret != 0)
                goto free_chainstack;
 
-       list_for_each_entry(t, &ebt_tables, list) {
+       list_for_each_entry(t, &net->xt.tables[NFPROTO_BRIDGE], list) {
                if (strcmp(t->name, table->name) == 0) {
                        ret = -EEXIST;
                        BUGPRINT("Table name already exists\n");
@@ -1155,9 +1191,9 @@ int ebt_register_table(struct ebt_table *table)
                ret = -ENOENT;
                goto free_unlock;
        }
-       list_add(&table->list, &ebt_tables);
+       list_add(&table->list, &net->xt.tables[NFPROTO_BRIDGE]);
        mutex_unlock(&ebt_mutex);
-       return 0;
+       return table;
 free_unlock:
        mutex_unlock(&ebt_mutex);
 free_chainstack:
@@ -1169,10 +1205,13 @@ free_chainstack:
        vfree(newinfo->entries);
 free_newinfo:
        vfree(newinfo);
-       return ret;
+free_table:
+       kfree(table);
+out:
+       return ERR_PTR(ret);
 }
 
-void ebt_unregister_table(struct ebt_table *table)
+void ebt_unregister_table(struct net *net, struct ebt_table *table)
 {
        int i;
 
@@ -1183,6 +1222,10 @@ void ebt_unregister_table(struct ebt_table *table)
        mutex_lock(&ebt_mutex);
        list_del(&table->list);
        mutex_unlock(&ebt_mutex);
+       EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size,
+                         ebt_cleanup_entry, net, NULL);
+       if (table->private->nentries)
+               module_put(table->me);
        vfree(table->private->entries);
        if (table->private->chainstack) {
                for_each_possible_cpu(i)
@@ -1190,10 +1233,11 @@ void ebt_unregister_table(struct ebt_table *table)
                vfree(table->private->chainstack);
        }
        vfree(table->private);
+       kfree(table);
 }
 
 /* userspace just supplied us with counters */
-static int update_counters(void __user *user, unsigned int len)
+static int update_counters(struct net *net, void __user *user, unsigned int len)
 {
        int i, ret;
        struct ebt_counter *tmp;
@@ -1213,7 +1257,7 @@ static int update_counters(void __user *user, unsigned int len)
                return -ENOMEM;
        }
 
-       t = find_table_lock(hlp.name, &ret, &ebt_mutex);
+       t = find_table_lock(net, hlp.name, &ret, &ebt_mutex);
        if (!t)
                goto free_tmp;
 
@@ -1369,12 +1413,15 @@ static int do_ebt_set_ctl(struct sock *sk,
 {
        int ret;
 
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
        switch(cmd) {
        case EBT_SO_SET_ENTRIES:
-               ret = do_replace(user, len);
+               ret = do_replace(sock_net(sk), user, len);
                break;
        case EBT_SO_SET_COUNTERS:
-               ret = update_counters(user, len);
+               ret = update_counters(sock_net(sk), user, len);
                break;
        default:
                ret = -EINVAL;
@@ -1388,10 +1435,13 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
        struct ebt_replace tmp;
        struct ebt_table *t;
 
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
        if (copy_from_user(&tmp, user, sizeof(tmp)))
                return -EFAULT;
 
-       t = find_table_lock(tmp.name, &ret, &ebt_mutex);
+       t = find_table_lock(sock_net(sk), tmp.name, &ret, &ebt_mutex);
        if (!t)
                return ret;