pending-4.9: 610-netfilter_match_bypass_default_check: fix 32bit compat layer
[openwrt/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 @@ -545,6 +571,8 @@ find_check_entry(struct ipt_entry *e, st
63 struct xt_entry_match *ematch;
64 unsigned long pcnt;
65
66 + ip_checkdefault(&e->ip);
67 +
68 pcnt = xt_percpu_counter_alloc();
69 if (IS_ERR_VALUE(pcnt))
70 return -ENOMEM;
71 @@ -824,6 +852,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 @@ -851,6 +880,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 @@ -1240,12 +1277,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);