af49530
From 2b32a7d82223d76ace432305b18c5816cadff878 Mon Sep 17 00:00:00 2001
af49530
From: Florian Westphal <fw () strlen ! de>
af49530
Date: Thu, 10 Mar 2016 00:56:02 -0800
af49530
Subject: [PATCH] netfilter: x_tables: deal with bogus nextoffset values
b653e2e
b653e2e
Ben Hawkes says:
b653e2e
b653e2e
 In the mark_source_chains function (net/ipv4/netfilter/ip_tables.c) it
b653e2e
 is possible for a user-supplied ipt_entry structure to have a large
b653e2e
 next_offset field. This field is not bounds checked prior to writing a
b653e2e
 counter value at the supplied offset.
b653e2e
b653e2e
Problem is that xt_entry_foreach() macro stops iterating once e->next_offset
b653e2e
is out of bounds, assuming this is the last entry.
b653e2e
b653e2e
With malformed data thats not necessarily the case so we can
b653e2e
write outside of allocated area later as we might not have walked the
b653e2e
entire blob.
b653e2e
b653e2e
Fix this by simplifying mark_source_chains -- it already has to check
b653e2e
if nextoff is in range to catch invalid jumps, so just do the check
b653e2e
when we move to a next entry as well.
b653e2e
b653e2e
Signed-off-by: Florian Westphal <fw@strlen.de>
b653e2e
---
af49530
 net/ipv4/netfilter/arp_tables.c | 8 ++++++++
af49530
 net/ipv4/netfilter/ip_tables.c  | 8 ++++++++
af49530
 net/ipv6/netfilter/ip6_tables.c | 6 ++++++
af49530
 3 files changed, 22 insertions(+)
b653e2e
b653e2e
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
af49530
index 2033f92..a9b6c76 100644
b653e2e
--- a/net/ipv4/netfilter/arp_tables.c
b653e2e
+++ b/net/ipv4/netfilter/arp_tables.c
af49530
@@ -376,6 +376,10 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
b653e2e
 
b653e2e
 				/* Move along one */
b653e2e
 				size = e->next_offset;
b653e2e
+
b653e2e
+				if (pos + size > newinfo->size - sizeof(*e))
b653e2e
+					return 0;
b653e2e
+
b653e2e
 				e = (struct arpt_entry *)
b653e2e
 					(entry0 + pos + size);
af49530
 				if (pos + size >= newinfo->size)
af49530
@@ -399,6 +403,10 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
af49530
 					if (newpos >= newinfo->size)
af49530
 						return 0;
b653e2e
 				}
b653e2e
+
b653e2e
+				if (newpos > newinfo->size - sizeof(*e))
b653e2e
+					return 0;
b653e2e
+
b653e2e
 				e = (struct arpt_entry *)
b653e2e
 					(entry0 + newpos);
b653e2e
 				e->counters.pcnt = pos;
b653e2e
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
af49530
index 54906e0..7530ecd 100644
b653e2e
--- a/net/ipv4/netfilter/ip_tables.c
b653e2e
+++ b/net/ipv4/netfilter/ip_tables.c
af49530
@@ -447,6 +447,10 @@ mark_source_chains(const struct xt_table_info *newinfo,
b653e2e
 
b653e2e
 				/* Move along one */
b653e2e
 				size = e->next_offset;
b653e2e
+
b653e2e
+				if (pos + size > newinfo->size - sizeof(*e))
b653e2e
+					return 0;
b653e2e
+
b653e2e
 				e = (struct ipt_entry *)
b653e2e
 					(entry0 + pos + size);
af49530
 				if (pos + size >= newinfo->size)
af49530
@@ -470,6 +474,10 @@ mark_source_chains(const struct xt_table_info *newinfo,
af49530
 					if (newpos >= newinfo->size)
af49530
 						return 0;
b653e2e
 				}
b653e2e
+
b653e2e
+				if (newpos > newinfo->size - sizeof(*e))
b653e2e
+					return 0;
b653e2e
+
b653e2e
 				e = (struct ipt_entry *)
b653e2e
 					(entry0 + newpos);
b653e2e
 				e->counters.pcnt = pos;
b653e2e
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
af49530
index 63e06c3..894da69 100644
b653e2e
--- a/net/ipv6/netfilter/ip6_tables.c
b653e2e
+++ b/net/ipv6/netfilter/ip6_tables.c
af49530
@@ -474,6 +474,8 @@ mark_source_chains(const struct xt_table_info *newinfo,
b653e2e
 
b653e2e
 				/* Move along one */
b653e2e
 				size = e->next_offset;
b653e2e
+				if (pos + size > newinfo->size - sizeof(*e))
b653e2e
+					return 0;
b653e2e
 				e = (struct ip6t_entry *)
b653e2e
 					(entry0 + pos + size);
af49530
 				if (pos + size >= newinfo->size)
af49530
@@ -497,6 +499,10 @@ mark_source_chains(const struct xt_table_info *newinfo,
af49530
 					if (newpos >= newinfo->size)
af49530
 						return 0;
b653e2e
 				}
b653e2e
+
b653e2e
+				if (newpos > newinfo->size - sizeof(*e))
b653e2e
+					return 0;
b653e2e
+
b653e2e
 				e = (struct ip6t_entry *)
b653e2e
 					(entry0 + newpos);
b653e2e
 				e->counters.pcnt = pos;
b653e2e
-- 
af49530
2.5.5
af49530