|
|
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 |
|