netfilter: use rcu_read_bh() in ipt_do_table()
[firefly-linux-kernel-4.4.55.git] / net / ipv4 / netfilter / ip_tables.c
index e5294aec967d45762cf15e1aaed577b83455a8c5..810c0b62c7d4b213ea21c8ab0aaf3198e7e7bc36 100644 (file)
@@ -74,25 +74,6 @@ do {                                                         \
 
    Hence the start of any table is given by get_table() below.  */
 
-static unsigned long ifname_compare(const char *_a, const char *_b,
-                                   const unsigned char *_mask)
-{
-       const unsigned long *a = (const unsigned long *)_a;
-       const unsigned long *b = (const unsigned long *)_b;
-       const unsigned long *mask = (const unsigned long *)_mask;
-       unsigned long ret;
-
-       ret = (a[0] ^ b[0]) & mask[0];
-       if (IFNAMSIZ > sizeof(unsigned long))
-               ret |= (a[1] ^ b[1]) & mask[1];
-       if (IFNAMSIZ > 2 * sizeof(unsigned long))
-               ret |= (a[2] ^ b[2]) & mask[2];
-       if (IFNAMSIZ > 3 * sizeof(unsigned long))
-               ret |= (a[3] ^ b[3]) & mask[3];
-       BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long));
-       return ret;
-}
-
 /* Returns whether matches rule or not. */
 /* Performance critical - called for every packet */
 static inline bool
@@ -121,7 +102,7 @@ ip_packet_match(const struct iphdr *ip,
                return false;
        }
 
-       ret = ifname_compare(indev, ipinfo->iniface, ipinfo->iniface_mask);
+       ret = ifname_compare_aligned(indev, ipinfo->iniface, ipinfo->iniface_mask);
 
        if (FWINV(ret != 0, IPT_INV_VIA_IN)) {
                dprintf("VIA in mismatch (%s vs %s).%s\n",
@@ -130,7 +111,7 @@ ip_packet_match(const struct iphdr *ip,
                return false;
        }
 
-       ret = ifname_compare(outdev, ipinfo->outiface, ipinfo->outiface_mask);
+       ret = ifname_compare_aligned(outdev, ipinfo->outiface, ipinfo->outiface_mask);
 
        if (FWINV(ret != 0, IPT_INV_VIA_OUT)) {
                dprintf("VIA out mismatch (%s vs %s).%s\n",
@@ -358,7 +339,7 @@ ipt_do_table(struct sk_buff *skb,
 
        IP_NF_ASSERT(table->valid_hooks & (1 << hook));
 
-       rcu_read_lock();
+       rcu_read_lock_bh();
        private = rcu_dereference(table->private);
        table_base = rcu_dereference(private->entries[smp_processor_id()]);
 
@@ -456,7 +437,7 @@ ipt_do_table(struct sk_buff *skb,
                }
        } while (!hotdrop);
 
-       rcu_read_unlock();
+       rcu_read_unlock_bh();
 
 #ifdef DEBUG_ALLOW_ALL
        return NF_ACCEPT;
@@ -507,7 +488,9 @@ mark_source_chains(struct xt_table_info *newinfo,
                            && unconditional(&e->ip)) || visited) {
                                unsigned int oldpos, size;
 
-                               if (t->verdict < -NF_MAX_VERDICT - 1) {
+                               if ((strcmp(t->target.u.user.name,
+                                           IPT_STANDARD_TARGET) == 0) &&
+                                   t->verdict < -NF_MAX_VERDICT - 1) {
                                        duprintf("mark_source_chains: bad "
                                                "negative verdict (%i)\n",
                                                                t->verdict);