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