]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 22 Jun 2016 21:18:43 +0000 (14:18 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 22 Jun 2016 21:18:43 +0000 (14:18 -0700)
added patches:
netfilter-x_tables-don-t-move-to-non-existent-next-rule.patch
netfilter-x_tables-validate-targets-of-jumps.patch

queue-3.14/netfilter-x_tables-don-t-move-to-non-existent-next-rule.patch [new file with mode: 0644]
queue-3.14/netfilter-x_tables-validate-targets-of-jumps.patch [new file with mode: 0644]
queue-3.14/series

diff --git a/queue-3.14/netfilter-x_tables-don-t-move-to-non-existent-next-rule.patch b/queue-3.14/netfilter-x_tables-don-t-move-to-non-existent-next-rule.patch
new file mode 100644 (file)
index 0000000..d19e00f
--- /dev/null
@@ -0,0 +1,106 @@
+From f24e230d257af1ad7476c6e81a8dc3127a74204e Mon Sep 17 00:00:00 2001
+From: Florian Westphal <fw@strlen.de>
+Date: Fri, 1 Apr 2016 14:17:21 +0200
+Subject: netfilter: x_tables: don't move to non-existent next rule
+
+From: Florian Westphal <fw@strlen.de>
+
+commit f24e230d257af1ad7476c6e81a8dc3127a74204e upstream.
+
+Ben Hawkes says:
+
+ In the mark_source_chains function (net/ipv4/netfilter/ip_tables.c) it
+ is possible for a user-supplied ipt_entry structure to have a large
+ next_offset field. This field is not bounds checked prior to writing a
+ counter value at the supplied offset.
+
+Base chains enforce absolute verdict.
+
+User defined chains are supposed to end with an unconditional return,
+xtables userspace adds them automatically.
+
+But if such return is missing we will move to non-existent next rule.
+
+Reported-by: Ben Hawkes <hawkes@google.com>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/ipv4/netfilter/arp_tables.c |    8 +++++---
+ net/ipv4/netfilter/ip_tables.c  |    4 ++++
+ net/ipv6/netfilter/ip6_tables.c |    4 ++++
+ 3 files changed, 13 insertions(+), 3 deletions(-)
+
+--- a/net/ipv4/netfilter/arp_tables.c
++++ b/net/ipv4/netfilter/arp_tables.c
+@@ -435,6 +435,8 @@ static int mark_source_chains(const stru
+                               size = e->next_offset;
+                               e = (struct arpt_entry *)
+                                       (entry0 + pos + size);
++                              if (pos + size >= newinfo->size)
++                                      return 0;
+                               e->counters.pcnt = pos;
+                               pos += size;
+                       } else {
+@@ -457,6 +459,8 @@ static int mark_source_chains(const stru
+                               } else {
+                                       /* ... this is a fallthru */
+                                       newpos = pos + e->next_offset;
++                                      if (newpos >= newinfo->size)
++                                              return 0;
+                               }
+                               e = (struct arpt_entry *)
+                                       (entry0 + newpos);
+@@ -681,10 +685,8 @@ static int translate_table(struct xt_tab
+               }
+       }
+-      if (!mark_source_chains(newinfo, repl->valid_hooks, entry0)) {
+-              duprintf("Looping hook\n");
++      if (!mark_source_chains(newinfo, repl->valid_hooks, entry0))
+               return -ELOOP;
+-      }
+       /* Finally, each sanity check must pass */
+       i = 0;
+--- a/net/ipv4/netfilter/ip_tables.c
++++ b/net/ipv4/netfilter/ip_tables.c
+@@ -516,6 +516,8 @@ mark_source_chains(const struct xt_table
+                               size = e->next_offset;
+                               e = (struct ipt_entry *)
+                                       (entry0 + pos + size);
++                              if (pos + size >= newinfo->size)
++                                      return 0;
+                               e->counters.pcnt = pos;
+                               pos += size;
+                       } else {
+@@ -537,6 +539,8 @@ mark_source_chains(const struct xt_table
+                               } else {
+                                       /* ... this is a fallthru */
+                                       newpos = pos + e->next_offset;
++                                      if (newpos >= newinfo->size)
++                                              return 0;
+                               }
+                               e = (struct ipt_entry *)
+                                       (entry0 + newpos);
+--- a/net/ipv6/netfilter/ip6_tables.c
++++ b/net/ipv6/netfilter/ip6_tables.c
+@@ -526,6 +526,8 @@ mark_source_chains(const struct xt_table
+                               size = e->next_offset;
+                               e = (struct ip6t_entry *)
+                                       (entry0 + pos + size);
++                              if (pos + size >= newinfo->size)
++                                      return 0;
+                               e->counters.pcnt = pos;
+                               pos += size;
+                       } else {
+@@ -547,6 +549,8 @@ mark_source_chains(const struct xt_table
+                               } else {
+                                       /* ... this is a fallthru */
+                                       newpos = pos + e->next_offset;
++                                      if (newpos >= newinfo->size)
++                                              return 0;
+                               }
+                               e = (struct ip6t_entry *)
+                                       (entry0 + newpos);
diff --git a/queue-3.14/netfilter-x_tables-validate-targets-of-jumps.patch b/queue-3.14/netfilter-x_tables-validate-targets-of-jumps.patch
new file mode 100644 (file)
index 0000000..384b84d
--- /dev/null
@@ -0,0 +1,133 @@
+From 36472341017529e2b12573093cc0f68719300997 Mon Sep 17 00:00:00 2001
+From: Florian Westphal <fw@strlen.de>
+Date: Fri, 1 Apr 2016 14:17:22 +0200
+Subject: netfilter: x_tables: validate targets of jumps
+
+From: Florian Westphal <fw@strlen.de>
+
+commit 36472341017529e2b12573093cc0f68719300997 upstream.
+
+When we see a jump also check that the offset gets us to beginning of
+a rule (an ipt_entry).
+
+The extra overhead is negible, even with absurd cases.
+
+300k custom rules, 300k jumps to 'next' user chain:
+[ plus one jump from INPUT to first userchain ]:
+
+Before:
+real    0m24.874s
+user    0m7.532s
+sys     0m16.076s
+
+After:
+real    0m27.464s
+user    0m7.436s
+sys     0m18.840s
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/ipv4/netfilter/arp_tables.c |   16 ++++++++++++++++
+ net/ipv4/netfilter/ip_tables.c  |   16 ++++++++++++++++
+ net/ipv6/netfilter/ip6_tables.c |   16 ++++++++++++++++
+ 3 files changed, 48 insertions(+)
+
+--- a/net/ipv4/netfilter/arp_tables.c
++++ b/net/ipv4/netfilter/arp_tables.c
+@@ -363,6 +363,18 @@ static inline bool unconditional(const s
+              memcmp(&e->arp, &uncond, sizeof(uncond)) == 0;
+ }
++static bool find_jump_target(const struct xt_table_info *t,
++                           const struct arpt_entry *target)
++{
++      struct arpt_entry *iter;
++
++      xt_entry_foreach(iter, t->entries, t->size) {
++               if (iter == target)
++                      return true;
++      }
++      return false;
++}
++
+ /* Figures out from what hook each rule can be called: returns 0 if
+  * there are loops.  Puts hook bitmask in comefrom.
+  */
+@@ -456,6 +468,10 @@ static int mark_source_chains(const stru
+                                       /* This a jump; chase it. */
+                                       duprintf("Jump rule %u -> %u\n",
+                                                pos, newpos);
++                                      e = (struct arpt_entry *)
++                                              (entry0 + newpos);
++                                      if (!find_jump_target(newinfo, e))
++                                              return 0;
+                               } else {
+                                       /* ... this is a fallthru */
+                                       newpos = pos + e->next_offset;
+--- a/net/ipv4/netfilter/ip_tables.c
++++ b/net/ipv4/netfilter/ip_tables.c
+@@ -439,6 +439,18 @@ ipt_do_table(struct sk_buff *skb,
+ #endif
+ }
++static bool find_jump_target(const struct xt_table_info *t,
++                           const struct ipt_entry *target)
++{
++      struct ipt_entry *iter;
++
++      xt_entry_foreach(iter, t->entries, t->size) {
++               if (iter == target)
++                      return true;
++      }
++      return false;
++}
++
+ /* Figures out from what hook each rule can be called: returns 0 if
+    there are loops.  Puts hook bitmask in comefrom. */
+ static int
+@@ -536,6 +548,10 @@ mark_source_chains(const struct xt_table
+                                       /* This a jump; chase it. */
+                                       duprintf("Jump rule %u -> %u\n",
+                                                pos, newpos);
++                                      e = (struct ipt_entry *)
++                                              (entry0 + newpos);
++                                      if (!find_jump_target(newinfo, e))
++                                              return 0;
+                               } else {
+                                       /* ... this is a fallthru */
+                                       newpos = pos + e->next_offset;
+--- a/net/ipv6/netfilter/ip6_tables.c
++++ b/net/ipv6/netfilter/ip6_tables.c
+@@ -449,6 +449,18 @@ ip6t_do_table(struct sk_buff *skb,
+ #endif
+ }
++static bool find_jump_target(const struct xt_table_info *t,
++                           const struct ip6t_entry *target)
++{
++      struct ip6t_entry *iter;
++
++      xt_entry_foreach(iter, t->entries, t->size) {
++               if (iter == target)
++                      return true;
++      }
++      return false;
++}
++
+ /* Figures out from what hook each rule can be called: returns 0 if
+    there are loops.  Puts hook bitmask in comefrom. */
+ static int
+@@ -546,6 +558,10 @@ mark_source_chains(const struct xt_table
+                                       /* This a jump; chase it. */
+                                       duprintf("Jump rule %u -> %u\n",
+                                                pos, newpos);
++                                      e = (struct ip6t_entry *)
++                                              (entry0 + newpos);
++                                      if (!find_jump_target(newinfo, e))
++                                              return 0;
+                               } else {
+                                       /* ... this is a fallthru */
+                                       newpos = pos + e->next_offset;
index a8fd38cb0bd7ffc35c470b0e911218facb16baee..39d568b00e6ed9a38eca81b2bf469d42aadc101a 100644 (file)
@@ -16,3 +16,5 @@ netfilter-x_tables-make-sure-e-next_offset-covers-remaining-blob-size.patch
 netfilter-x_tables-fix-unconditional-helper.patch
 xfs-fix-up-backport-error-in-fs-xfs-xfs_inode.c.patch
 pipe-limit-the-per-user-amount-of-pages-allocated-in-pipes.patch
+netfilter-x_tables-don-t-move-to-non-existent-next-rule.patch
+netfilter-x_tables-validate-targets-of-jumps.patch