|
@@ -401,6 +401,13 @@ mark_source_chains(struct xt_table_info *newinfo,
|
|
|
&& unconditional(&e->ip)) {
|
|
|
unsigned int oldpos, size;
|
|
|
|
|
|
+ if (t->verdict < -NF_MAX_VERDICT - 1) {
|
|
|
+ duprintf("mark_source_chains: bad "
|
|
|
+ "negative verdict (%i)\n",
|
|
|
+ t->verdict);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
/* Return: backtrack through the last
|
|
|
big jump. */
|
|
|
do {
|
|
@@ -438,6 +445,13 @@ mark_source_chains(struct xt_table_info *newinfo,
|
|
|
if (strcmp(t->target.u.user.name,
|
|
|
IPT_STANDARD_TARGET) == 0
|
|
|
&& newpos >= 0) {
|
|
|
+ if (newpos > newinfo->size -
|
|
|
+ sizeof(struct ipt_entry)) {
|
|
|
+ duprintf("mark_source_chains: "
|
|
|
+ "bad verdict (%i)\n",
|
|
|
+ newpos);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
/* This a jump; chase it. */
|
|
|
duprintf("Jump rule %u -> %u\n",
|
|
|
pos, newpos);
|
|
@@ -469,27 +483,6 @@ cleanup_match(struct ipt_entry_match *m, unsigned int *i)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static inline int
|
|
|
-standard_check(const struct ipt_entry_target *t,
|
|
|
- unsigned int max_offset)
|
|
|
-{
|
|
|
- struct ipt_standard_target *targ = (void *)t;
|
|
|
-
|
|
|
- /* Check standard info. */
|
|
|
- if (targ->verdict >= 0
|
|
|
- && targ->verdict > max_offset - sizeof(struct ipt_entry)) {
|
|
|
- duprintf("ipt_standard_check: bad verdict (%i)\n",
|
|
|
- targ->verdict);
|
|
|
- return 0;
|
|
|
- }
|
|
|
- if (targ->verdict < -NF_MAX_VERDICT - 1) {
|
|
|
- duprintf("ipt_standard_check: bad negative verdict (%i)\n",
|
|
|
- targ->verdict);
|
|
|
- return 0;
|
|
|
- }
|
|
|
- return 1;
|
|
|
-}
|
|
|
-
|
|
|
static inline int
|
|
|
check_match(struct ipt_entry_match *m,
|
|
|
const char *name,
|
|
@@ -576,12 +569,7 @@ check_entry(struct ipt_entry *e, const char *name, unsigned int size,
|
|
|
if (ret)
|
|
|
goto err;
|
|
|
|
|
|
- if (t->u.kernel.target == &ipt_standard_target) {
|
|
|
- if (!standard_check(t, size)) {
|
|
|
- ret = -EINVAL;
|
|
|
- goto err;
|
|
|
- }
|
|
|
- } else if (t->u.kernel.target->checkentry
|
|
|
+ if (t->u.kernel.target->checkentry
|
|
|
&& !t->u.kernel.target->checkentry(name, e, target, t->data,
|
|
|
e->comefrom)) {
|
|
|
duprintf("ip_tables: check failed for `%s'.\n",
|
|
@@ -718,17 +706,19 @@ translate_table(const char *name,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (!mark_source_chains(newinfo, valid_hooks, entry0))
|
|
|
+ return -ELOOP;
|
|
|
+
|
|
|
/* Finally, each sanity check must pass */
|
|
|
i = 0;
|
|
|
ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
|
|
|
check_entry, name, size, &i);
|
|
|
|
|
|
- if (ret != 0)
|
|
|
- goto cleanup;
|
|
|
-
|
|
|
- ret = -ELOOP;
|
|
|
- if (!mark_source_chains(newinfo, valid_hooks, entry0))
|
|
|
- goto cleanup;
|
|
|
+ if (ret != 0) {
|
|
|
+ IPT_ENTRY_ITERATE(entry0, newinfo->size,
|
|
|
+ cleanup_entry, &i);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
|
|
|
/* And one copy for every other CPU */
|
|
|
for_each_possible_cpu(i) {
|
|
@@ -736,9 +726,6 @@ translate_table(const char *name,
|
|
|
memcpy(newinfo->entries[i], entry0, newinfo->size);
|
|
|
}
|
|
|
|
|
|
- return 0;
|
|
|
-cleanup:
|
|
|
- IPT_ENTRY_ITERATE(entry0, newinfo->size, cleanup_entry, &i);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -1591,18 +1578,13 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
|
|
|
if (ret)
|
|
|
goto err;
|
|
|
|
|
|
- ret = -EINVAL;
|
|
|
- if (t->u.kernel.target == &ipt_standard_target) {
|
|
|
- if (!standard_check(t, *size))
|
|
|
- goto err;
|
|
|
- } else if (t->u.kernel.target->checkentry
|
|
|
+ if (t->u.kernel.target->checkentry
|
|
|
&& !t->u.kernel.target->checkentry(name, de, target,
|
|
|
t->data, de->comefrom)) {
|
|
|
duprintf("ip_tables: compat: check failed for `%s'.\n",
|
|
|
t->u.kernel.target->name);
|
|
|
- goto err;
|
|
|
+ ret = -EINVAL;
|
|
|
}
|
|
|
- ret = 0;
|
|
|
err:
|
|
|
return ret;
|
|
|
}
|