Commit 36472341 authored by Florian Westphal's avatar Florian Westphal Committed by Pablo Neira Ayuso

netfilter: x_tables: validate targets of jumps

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>
parent f24e230d
...@@ -367,6 +367,18 @@ static inline bool unconditional(const struct arpt_entry *e) ...@@ -367,6 +367,18 @@ 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 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 /* 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.
*/ */
...@@ -460,6 +472,10 @@ static int mark_source_chains(const struct xt_table_info *newinfo, ...@@ -460,6 +472,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, e))
return 0;
} else { } else {
/* ... this is a fallthru */ /* ... this is a fallthru */
newpos = pos + e->next_offset; newpos = pos + e->next_offset;
......
...@@ -443,6 +443,18 @@ ipt_do_table(struct sk_buff *skb, ...@@ -443,6 +443,18 @@ ipt_do_table(struct sk_buff *skb,
#endif #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 /* 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
...@@ -540,6 +552,10 @@ mark_source_chains(const struct xt_table_info *newinfo, ...@@ -540,6 +552,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, e))
return 0;
} else { } else {
/* ... this is a fallthru */ /* ... this is a fallthru */
newpos = pos + e->next_offset; newpos = pos + e->next_offset;
......
...@@ -455,6 +455,18 @@ ip6t_do_table(struct sk_buff *skb, ...@@ -455,6 +455,18 @@ ip6t_do_table(struct sk_buff *skb,
#endif #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 /* 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
...@@ -552,6 +564,10 @@ mark_source_chains(const struct xt_table_info *newinfo, ...@@ -552,6 +564,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, 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