Commit 8163327a authored by Florian Westphal's avatar Florian Westphal Committed by Sasha Levin

netfilter: x_tables: validate targets of jumps

[ Upstream commit 36472341 ]

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 avatarSasha Levin <sasha.levin@oracle.com>
parent cf756388
...@@ -362,6 +362,18 @@ static inline bool unconditional(const struct arpt_entry *e) ...@@ -362,6 +362,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.
*/ */
...@@ -455,6 +467,10 @@ static int mark_source_chains(const struct xt_table_info *newinfo, ...@@ -455,6 +467,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;
......
...@@ -438,6 +438,18 @@ ipt_do_table(struct sk_buff *skb, ...@@ -438,6 +438,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
...@@ -535,6 +547,10 @@ mark_source_chains(const struct xt_table_info *newinfo, ...@@ -535,6 +547,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;
......
...@@ -451,6 +451,18 @@ ip6t_do_table(struct sk_buff *skb, ...@@ -451,6 +451,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
...@@ -548,6 +560,10 @@ mark_source_chains(const struct xt_table_info *newinfo, ...@@ -548,6 +560,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