|
@@ -402,23 +402,12 @@ ip6t_do_table(struct sk_buff *skb,
|
|
|
else return verdict;
|
|
|
}
|
|
|
|
|
|
-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
|
|
|
there are loops. Puts hook bitmask in comefrom. */
|
|
|
static int
|
|
|
mark_source_chains(const struct xt_table_info *newinfo,
|
|
|
- unsigned int valid_hooks, void *entry0)
|
|
|
+ unsigned int valid_hooks, void *entry0,
|
|
|
+ unsigned int *offsets)
|
|
|
{
|
|
|
unsigned int hook;
|
|
|
|
|
@@ -487,10 +476,11 @@ mark_source_chains(const struct xt_table_info *newinfo,
|
|
|
XT_STANDARD_TARGET) == 0 &&
|
|
|
newpos >= 0) {
|
|
|
/* This a jump; chase it. */
|
|
|
+ if (!xt_find_jump_offset(offsets, newpos,
|
|
|
+ newinfo->number))
|
|
|
+ return 0;
|
|
|
e = (struct ip6t_entry *)
|
|
|
(entry0 + newpos);
|
|
|
- if (!find_jump_target(newinfo, e))
|
|
|
- return 0;
|
|
|
} else {
|
|
|
/* ... this is a fallthru */
|
|
|
newpos = pos + e->next_offset;
|
|
@@ -724,6 +714,7 @@ translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0,
|
|
|
const struct ip6t_replace *repl)
|
|
|
{
|
|
|
struct ip6t_entry *iter;
|
|
|
+ unsigned int *offsets;
|
|
|
unsigned int i;
|
|
|
int ret = 0;
|
|
|
|
|
@@ -736,6 +727,9 @@ translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0,
|
|
|
newinfo->underflow[i] = 0xFFFFFFFF;
|
|
|
}
|
|
|
|
|
|
+ offsets = xt_alloc_entry_offsets(newinfo->number);
|
|
|
+ if (!offsets)
|
|
|
+ return -ENOMEM;
|
|
|
i = 0;
|
|
|
/* Walk through entries, checking offsets. */
|
|
|
xt_entry_foreach(iter, entry0, newinfo->size) {
|
|
@@ -745,15 +739,18 @@ translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0,
|
|
|
repl->underflow,
|
|
|
repl->valid_hooks);
|
|
|
if (ret != 0)
|
|
|
- return ret;
|
|
|
+ goto out_free;
|
|
|
+ if (i < repl->num_entries)
|
|
|
+ offsets[i] = (void *)iter - entry0;
|
|
|
++i;
|
|
|
if (strcmp(ip6t_get_target(iter)->u.user.name,
|
|
|
XT_ERROR_TARGET) == 0)
|
|
|
++newinfo->stacksize;
|
|
|
}
|
|
|
|
|
|
+ ret = -EINVAL;
|
|
|
if (i != repl->num_entries)
|
|
|
- return -EINVAL;
|
|
|
+ goto out_free;
|
|
|
|
|
|
/* Check hooks all assigned */
|
|
|
for (i = 0; i < NF_INET_NUMHOOKS; i++) {
|
|
@@ -761,13 +758,16 @@ translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0,
|
|
|
if (!(repl->valid_hooks & (1 << i)))
|
|
|
continue;
|
|
|
if (newinfo->hook_entry[i] == 0xFFFFFFFF)
|
|
|
- return -EINVAL;
|
|
|
+ goto out_free;
|
|
|
if (newinfo->underflow[i] == 0xFFFFFFFF)
|
|
|
- return -EINVAL;
|
|
|
+ goto out_free;
|
|
|
}
|
|
|
|
|
|
- if (!mark_source_chains(newinfo, repl->valid_hooks, entry0))
|
|
|
- return -ELOOP;
|
|
|
+ if (!mark_source_chains(newinfo, repl->valid_hooks, entry0, offsets)) {
|
|
|
+ ret = -ELOOP;
|
|
|
+ goto out_free;
|
|
|
+ }
|
|
|
+ kvfree(offsets);
|
|
|
|
|
|
/* Finally, each sanity check must pass */
|
|
|
i = 0;
|
|
@@ -787,6 +787,9 @@ translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+ return ret;
|
|
|
+ out_free:
|
|
|
+ kvfree(offsets);
|
|
|
return ret;
|
|
|
}
|
|
|
|