Commit eb097f88 authored by Florian Westphal's avatar Florian Westphal Committed by Greg Kroah-Hartman

netfilter: x_tables: validate targets of jumps

commit 36472341 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: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a073bb0c
...@@ -363,6 +363,19 @@ static inline bool unconditional(const struct arpt_entry *e) ...@@ -363,6 +363,19 @@ static inline bool unconditional(const struct arpt_entry *e)
memcmp(&e->arp, &uncond, sizeof(uncond)) == 0; memcmp(&e->arp, &uncond, sizeof(uncond)) == 0;
} }
static bool find_jump_target(const struct xt_table_info *t,
const void *entry0,
const struct arpt_entry *target)
{
struct arpt_entry *iter;
xt_entry_foreach(iter, entry0, t->size) {
if (iter == target)
return true;
}
return false;
}
/* Figures out from what hook each rule can be called: returns 0 if /* Figures out from what hook each rule can be called: returns 0 if
* there are loops. Puts hook bitmask in comefrom. * there are loops. Puts hook bitmask in comefrom.
*/ */
...@@ -456,6 +469,10 @@ static int mark_source_chains(const struct xt_table_info *newinfo, ...@@ -456,6 +469,10 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
/* This a jump; chase it. */ /* This a jump; chase it. */
duprintf("Jump rule %u -> %u\n", duprintf("Jump rule %u -> %u\n",
pos, newpos); pos, newpos);
e = (struct arpt_entry *)
(entry0 + newpos);
if (!find_jump_target(newinfo, entry0, e))
return 0;
} else { } else {
/* ... this is a fallthru */ /* ... this is a fallthru */
newpos = pos + e->next_offset; newpos = pos + e->next_offset;
......
...@@ -439,6 +439,19 @@ ipt_do_table(struct sk_buff *skb, ...@@ -439,6 +439,19 @@ ipt_do_table(struct sk_buff *skb,
#endif #endif
} }
static bool find_jump_target(const struct xt_table_info *t,
const void *entry0,
const struct ipt_entry *target)
{
struct ipt_entry *iter;
xt_entry_foreach(iter, entry0, t->size) {
if (iter == target)
return true;
}
return false;
}
/* Figures out from what hook each rule can be called: returns 0 if /* Figures out from what hook each rule can be called: returns 0 if
there are loops. Puts hook bitmask in comefrom. */ there are loops. Puts hook bitmask in comefrom. */
static int static int
...@@ -536,6 +549,10 @@ mark_source_chains(const struct xt_table_info *newinfo, ...@@ -536,6 +549,10 @@ mark_source_chains(const struct xt_table_info *newinfo,
/* This a jump; chase it. */ /* This a jump; chase it. */
duprintf("Jump rule %u -> %u\n", duprintf("Jump rule %u -> %u\n",
pos, newpos); pos, newpos);
e = (struct ipt_entry *)
(entry0 + newpos);
if (!find_jump_target(newinfo, entry0, e))
return 0;
} else { } else {
/* ... this is a fallthru */ /* ... this is a fallthru */
newpos = pos + e->next_offset; newpos = pos + e->next_offset;
......
...@@ -449,6 +449,19 @@ ip6t_do_table(struct sk_buff *skb, ...@@ -449,6 +449,19 @@ ip6t_do_table(struct sk_buff *skb,
#endif #endif
} }
static bool find_jump_target(const struct xt_table_info *t,
const void *entry0,
const struct ip6t_entry *target)
{
struct ip6t_entry *iter;
xt_entry_foreach(iter, entry0, t->size) {
if (iter == target)
return true;
}
return false;
}
/* Figures out from what hook each rule can be called: returns 0 if /* Figures out from what hook each rule can be called: returns 0 if
there are loops. Puts hook bitmask in comefrom. */ there are loops. Puts hook bitmask in comefrom. */
static int static int
...@@ -546,6 +559,10 @@ mark_source_chains(const struct xt_table_info *newinfo, ...@@ -546,6 +559,10 @@ mark_source_chains(const struct xt_table_info *newinfo,
/* This a jump; chase it. */ /* This a jump; chase it. */
duprintf("Jump rule %u -> %u\n", duprintf("Jump rule %u -> %u\n",
pos, newpos); pos, newpos);
e = (struct ip6t_entry *)
(entry0 + newpos);
if (!find_jump_target(newinfo, entry0, e))
return 0;
} else { } else {
/* ... this is a fallthru */ /* ... this is a fallthru */
newpos = pos + e->next_offset; newpos = pos + e->next_offset;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment