- patches.arch/x86_mce_intel_decode_physical_address.patch:
[linux-flexiantxendom0-3.2.10.git] / net / netfilter / x_tables.c
index 665f5be..e34622f 100644 (file)
@@ -12,7 +12,7 @@
  * published by the Free Software Foundation.
  *
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/kernel.h>
 #include <linux/socket.h>
 #include <linux/net.h>
@@ -55,12 +55,6 @@ struct xt_af {
 
 static struct xt_af *xt;
 
-#ifdef DEBUG_IP_FIREWALL_USER
-#define duprintf(format, args...) printk(format , ## args)
-#else
-#define duprintf(format, args...)
-#endif
-
 static const char *const xt_prefix[NFPROTO_NUMPROTO] = {
        [NFPROTO_UNSPEC] = "x",
        [NFPROTO_IPV4]   = "ip",
@@ -69,6 +63,9 @@ static const char *const xt_prefix[NFPROTO_NUMPROTO] = {
        [NFPROTO_IPV6]   = "ip6",
 };
 
+/* Allow this many total (re)entries. */
+static const unsigned int xt_jumpstack_multiplier = 2;
+
 /* Registration hooks for targets. */
 int
 xt_register_target(struct xt_target *target)
@@ -221,6 +218,17 @@ struct xt_match *xt_find_match(u8 af, const char *name, u8 revision)
 }
 EXPORT_SYMBOL(xt_find_match);
 
+struct xt_match *
+xt_request_find_match(uint8_t nfproto, const char *name, uint8_t revision)
+{
+       struct xt_match *match;
+
+       match = try_then_request_module(xt_find_match(nfproto, name, revision),
+                                       "%st_%s", xt_prefix[nfproto], name);
+       return (match != NULL) ? match : ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL_GPL(xt_request_find_match);
+
 /* Find target, grabs ref.  Returns ERR_PTR() on error. */
 struct xt_target *xt_find_target(u8 af, const char *name, u8 revision)
 {
@@ -257,9 +265,7 @@ struct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision)
 
        target = try_then_request_module(xt_find_target(af, name, revision),
                                         "%st_%s", xt_prefix[af], name);
-       if (IS_ERR(target) || !target)
-               return NULL;
-       return target;
+       return (target != NULL) ? target : ERR_PTR(-ENOENT);
 }
 EXPORT_SYMBOL_GPL(xt_request_find_target);
 
@@ -361,6 +367,8 @@ static char *textify_hooks(char *buf, size_t size, unsigned int mask)
 int xt_check_match(struct xt_mtchk_param *par,
                   unsigned int size, u_int8_t proto, bool inv_proto)
 {
+       int ret;
+
        if (XT_ALIGN(par->match->matchsize) != size &&
            par->match->matchsize != -1) {
                /*
@@ -397,8 +405,14 @@ int xt_check_match(struct xt_mtchk_param *par,
                       par->match->proto);
                return -EINVAL;
        }
-       if (par->match->checkentry != NULL && !par->match->checkentry(par))
-               return -EINVAL;
+       if (par->match->checkentry != NULL) {
+               ret = par->match->checkentry(par);
+               if (ret < 0)
+                       return ret;
+               else if (ret > 0)
+                       /* Flag up potential errors. */
+                       return -EIO;
+       }
        return 0;
 }
 EXPORT_SYMBOL_GPL(xt_check_match);
@@ -518,6 +532,8 @@ EXPORT_SYMBOL_GPL(xt_compat_match_to_user);
 int xt_check_target(struct xt_tgchk_param *par,
                    unsigned int size, u_int8_t proto, bool inv_proto)
 {
+       int ret;
+
        if (XT_ALIGN(par->target->targetsize) != size) {
                pr_err("%s_tables: %s.%u target: invalid size "
                       "%u (kernel) != (user) %u\n",
@@ -549,8 +565,14 @@ int xt_check_target(struct xt_tgchk_param *par,
                       par->target->proto);
                return -EINVAL;
        }
-       if (par->target->checkentry != NULL && !par->target->checkentry(par))
-               return -EINVAL;
+       if (par->target->checkentry != NULL) {
+               ret = par->target->checkentry(par);
+               if (ret < 0)
+                       return ret;
+               else if (ret > 0)
+                       /* Flag up potential errors. */
+                       return -EIO;
+       }
        return 0;
 }
 EXPORT_SYMBOL_GPL(xt_check_target);
@@ -662,6 +684,24 @@ void xt_free_table_info(struct xt_table_info *info)
                else
                        vfree(info->entries[cpu]);
        }
+
+       if (info->jumpstack != NULL) {
+               if (sizeof(void *) * info->stacksize > PAGE_SIZE) {
+                       for_each_possible_cpu(cpu)
+                               vfree(info->jumpstack[cpu]);
+               } else {
+                       for_each_possible_cpu(cpu)
+                               kfree(info->jumpstack[cpu]);
+               }
+       }
+
+       if (sizeof(void **) * nr_cpu_ids > PAGE_SIZE)
+               vfree(info->jumpstack);
+       else
+               kfree(info->jumpstack);
+
+       free_percpu(info->stackptr);
+
        kfree(info);
 }
 EXPORT_SYMBOL(xt_free_table_info);
@@ -706,6 +746,44 @@ EXPORT_SYMBOL_GPL(xt_compat_unlock);
 DEFINE_PER_CPU(struct xt_info_lock, xt_info_locks);
 EXPORT_PER_CPU_SYMBOL_GPL(xt_info_locks);
 
+static int xt_jumpstack_alloc(struct xt_table_info *i)
+{
+       unsigned int size;
+       int cpu;
+
+       i->stackptr = alloc_percpu(unsigned int);
+       if (i->stackptr == NULL)
+               return -ENOMEM;
+
+       size = sizeof(void **) * nr_cpu_ids;
+       if (size > PAGE_SIZE)
+               i->jumpstack = vmalloc(size);
+       else
+               i->jumpstack = kmalloc(size, GFP_KERNEL);
+       if (i->jumpstack == NULL)
+               return -ENOMEM;
+       memset(i->jumpstack, 0, size);
+
+       i->stacksize *= xt_jumpstack_multiplier;
+       size = sizeof(void *) * i->stacksize;
+       for_each_possible_cpu(cpu) {
+               if (size > PAGE_SIZE)
+                       i->jumpstack[cpu] = vmalloc_node(size,
+                               cpu_to_node(cpu));
+               else
+                       i->jumpstack[cpu] = kmalloc_node(size,
+                               GFP_KERNEL, cpu_to_node(cpu));
+               if (i->jumpstack[cpu] == NULL)
+                       /*
+                        * Freeing will be done later on by the callers. The
+                        * chain is: xt_replace_table -> __do_replace ->
+                        * do_replace -> xt_free_table_info.
+                        */
+                       return -ENOMEM;
+       }
+
+       return 0;
+}
 
 struct xt_table_info *
 xt_replace_table(struct xt_table *table,
@@ -714,6 +792,13 @@ xt_replace_table(struct xt_table *table,
              int *error)
 {
        struct xt_table_info *private;
+       int ret;
+
+       ret = xt_jumpstack_alloc(newinfo);
+       if (ret < 0) {
+               *error = ret;
+               return NULL;
+       }
 
        /* Do the substitution. */
        local_bh_disable();
@@ -721,7 +806,7 @@ xt_replace_table(struct xt_table *table,
 
        /* Check inside lock: is the old number correct? */
        if (num_counters != private->number) {
-               duprintf("num_counters != table->private->number (%u/%u)\n",
+               pr_debug("num_counters != table->private->number (%u/%u)\n",
                         num_counters, private->number);
                local_bh_enable();
                *error = -EAGAIN;
@@ -778,7 +863,7 @@ struct xt_table *xt_register_table(struct net *net,
                goto unlock;
 
        private = table->private;
-       duprintf("table->private->number = %u\n", private->number);
+       pr_debug("table->private->number = %u\n", private->number);
 
        /* save number of initial entries */
        private->initial_entries = private->number;