d3a6afa804b7f754afe46fa11057b3a1d4033bf5
[oweals/openwrt.git] / target / linux / generic / pending-4.9 / 610-netfilter_match_bypass_default_checks.patch
1 From: Felix Fietkau <nbd@nbd.name>
2 Subject: kernel: add a new version of my netfilter speedup patches for linux 2.6.39 and 3.0
3
4 Signed-off-by: Felix Fietkau <nbd@nbd.name>
5 ---
6  include/uapi/linux/netfilter_ipv4/ip_tables.h |  1 +
7  net/ipv4/netfilter/ip_tables.c                | 37 +++++++++++++++++++++++++++
8  2 files changed, 38 insertions(+)
9
10 --- a/include/uapi/linux/netfilter_ipv4/ip_tables.h
11 +++ b/include/uapi/linux/netfilter_ipv4/ip_tables.h
12 @@ -88,6 +88,7 @@ struct ipt_ip {
13  #define IPT_F_FRAG             0x01    /* Set if rule is a fragment rule */
14  #define IPT_F_GOTO             0x02    /* Set if jump is a goto */
15  #define IPT_F_MASK             0x03    /* All possible flag bits mask. */
16 +#define IPT_F_NO_DEF_MATCH     0x80    /* Internal: no default match rules present */
17  
18  /* Values for "inv" field in struct ipt_ip. */
19  #define IPT_INV_VIA_IN         0x01    /* Invert the sense of IN IFACE. */
20 --- a/net/ipv4/netfilter/ip_tables.c
21 +++ b/net/ipv4/netfilter/ip_tables.c
22 @@ -58,6 +58,9 @@ ip_packet_match(const struct iphdr *ip,
23  {
24         unsigned long ret;
25  
26 +       if (ipinfo->flags & IPT_F_NO_DEF_MATCH)
27 +               return true;
28 +
29         if (NF_INVF(ipinfo, IPT_INV_SRCIP,
30                     (ip->saddr & ipinfo->smsk.s_addr) != ipinfo->src.s_addr) ||
31             NF_INVF(ipinfo, IPT_INV_DSTIP,
32 @@ -88,6 +91,29 @@ ip_packet_match(const struct iphdr *ip,
33         return true;
34  }
35  
36 +static void
37 +ip_checkdefault(struct ipt_ip *ip)
38 +{
39 +       static const char iface_mask[IFNAMSIZ] = {};
40 +
41 +       if (ip->invflags || ip->flags & IPT_F_FRAG)
42 +               return;
43 +
44 +       if (memcmp(ip->iniface_mask, iface_mask, IFNAMSIZ) != 0)
45 +               return;
46 +
47 +       if (memcmp(ip->outiface_mask, iface_mask, IFNAMSIZ) != 0)
48 +               return;
49 +
50 +       if (ip->smsk.s_addr || ip->dmsk.s_addr)
51 +               return;
52 +
53 +       if (ip->proto)
54 +               return;
55 +
56 +       ip->flags |= IPT_F_NO_DEF_MATCH;
57 +}
58 +
59  static bool
60  ip_checkentry(const struct ipt_ip *ip)
61  {
62 @@ -550,6 +576,8 @@ find_check_entry(struct ipt_entry *e, st
63         struct xt_mtchk_param mtpar;
64         struct xt_entry_match *ematch;
65  
66 +       ip_checkdefault(&e->ip);
67 +
68         if (!xt_percpu_counter_alloc(alloc_state, &e->counters))
69                 return -ENOMEM;
70  
71 @@ -830,6 +858,7 @@ copy_entries_to_user(unsigned int total_
72         const struct xt_table_info *private = table->private;
73         int ret = 0;
74         const void *loc_cpu_entry;
75 +       u8 flags;
76  
77         counters = alloc_counters(table);
78         if (IS_ERR(counters))
79 @@ -857,6 +886,14 @@ copy_entries_to_user(unsigned int total_
80                         goto free_counters;
81                 }
82  
83 +               flags = e->ip.flags & IPT_F_MASK;
84 +               if (copy_to_user(userptr + off
85 +                                + offsetof(struct ipt_entry, ip.flags),
86 +                                &flags, sizeof(flags)) != 0) {
87 +                       ret = -EFAULT;
88 +                       goto free_counters;
89 +               }
90 +
91                 for (i = sizeof(struct ipt_entry);
92                      i < e->target_offset;
93                      i += m->u.match_size) {
94 @@ -1246,12 +1283,15 @@ compat_copy_entry_to_user(struct ipt_ent
95         compat_uint_t origsize;
96         const struct xt_entry_match *ematch;
97         int ret = 0;
98 +       u8 flags = e->ip.flags & IPT_F_MASK;
99  
100         origsize = *size;
101         ce = (struct compat_ipt_entry __user *)*dstptr;
102         if (copy_to_user(ce, e, sizeof(struct ipt_entry)) != 0 ||
103             copy_to_user(&ce->counters, &counters[i],
104 -           sizeof(counters[i])) != 0)
105 +           sizeof(counters[i])) != 0 ||
106 +           copy_to_user(&ce->ip.flags, &flags,
107 +           sizeof(flags)) != 0)
108                 return -EFAULT;
109  
110         *dstptr += sizeof(struct compat_ipt_entry);