|
@@ -1516,25 +1516,8 @@ static inline int compat_copy_match_from_user(struct ipt_entry_match *m,
|
|
void **dstptr, compat_uint_t *size, const char *name,
|
|
void **dstptr, compat_uint_t *size, const char *name,
|
|
const struct ipt_ip *ip, unsigned int hookmask)
|
|
const struct ipt_ip *ip, unsigned int hookmask)
|
|
{
|
|
{
|
|
- struct ipt_entry_match *dm;
|
|
|
|
- struct ipt_match *match;
|
|
|
|
- int ret;
|
|
|
|
-
|
|
|
|
- dm = (struct ipt_entry_match *)*dstptr;
|
|
|
|
- match = m->u.kernel.match;
|
|
|
|
xt_compat_match_from_user(m, dstptr, size);
|
|
xt_compat_match_from_user(m, dstptr, size);
|
|
-
|
|
|
|
- ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm),
|
|
|
|
- name, hookmask, ip->proto,
|
|
|
|
- ip->invflags & IPT_INV_PROTO);
|
|
|
|
- if (!ret && m->u.kernel.match->checkentry
|
|
|
|
- && !m->u.kernel.match->checkentry(name, ip, match, dm->data,
|
|
|
|
- hookmask)) {
|
|
|
|
- duprintf("ip_tables: check failed for `%s'.\n",
|
|
|
|
- m->u.kernel.match->name);
|
|
|
|
- ret = -EINVAL;
|
|
|
|
- }
|
|
|
|
- return ret;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
|
|
static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
|
|
@@ -1556,7 +1539,7 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
|
|
ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size,
|
|
ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size,
|
|
name, &de->ip, de->comefrom);
|
|
name, &de->ip, de->comefrom);
|
|
if (ret)
|
|
if (ret)
|
|
- goto err;
|
|
|
|
|
|
+ return ret;
|
|
de->target_offset = e->target_offset - (origsize - *size);
|
|
de->target_offset = e->target_offset - (origsize - *size);
|
|
t = ipt_get_target(e);
|
|
t = ipt_get_target(e);
|
|
target = t->u.kernel.target;
|
|
target = t->u.kernel.target;
|
|
@@ -1569,26 +1552,62 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
|
|
if ((unsigned char *)de - base < newinfo->underflow[h])
|
|
if ((unsigned char *)de - base < newinfo->underflow[h])
|
|
newinfo->underflow[h] -= origsize - *size;
|
|
newinfo->underflow[h] -= origsize - *size;
|
|
}
|
|
}
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static inline int compat_check_match(struct ipt_entry_match *m, const char *name,
|
|
|
|
+ const struct ipt_ip *ip, unsigned int hookmask)
|
|
|
|
+{
|
|
|
|
+ struct ipt_match *match;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ match = m->u.kernel.match;
|
|
|
|
+ ret = xt_check_match(match, AF_INET, m->u.match_size - sizeof(*m),
|
|
|
|
+ name, hookmask, ip->proto,
|
|
|
|
+ ip->invflags & IPT_INV_PROTO);
|
|
|
|
+ if (!ret && m->u.kernel.match->checkentry
|
|
|
|
+ && !m->u.kernel.match->checkentry(name, ip, match, m->data,
|
|
|
|
+ hookmask)) {
|
|
|
|
+ duprintf("ip_tables: compat: check failed for `%s'.\n",
|
|
|
|
+ m->u.kernel.match->name);
|
|
|
|
+ ret = -EINVAL;
|
|
|
|
+ }
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static inline int compat_check_target(struct ipt_entry *e, const char *name)
|
|
|
|
+{
|
|
|
|
+ struct ipt_entry_target *t;
|
|
|
|
+ struct ipt_target *target;
|
|
|
|
+ int ret;
|
|
|
|
|
|
- t = ipt_get_target(de);
|
|
|
|
|
|
+ t = ipt_get_target(e);
|
|
target = t->u.kernel.target;
|
|
target = t->u.kernel.target;
|
|
ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
|
|
ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
|
|
name, e->comefrom, e->ip.proto,
|
|
name, e->comefrom, e->ip.proto,
|
|
e->ip.invflags & IPT_INV_PROTO);
|
|
e->ip.invflags & IPT_INV_PROTO);
|
|
- if (ret)
|
|
|
|
- goto err;
|
|
|
|
-
|
|
|
|
- if (t->u.kernel.target->checkentry
|
|
|
|
- && !t->u.kernel.target->checkentry(name, de, target,
|
|
|
|
- t->data, de->comefrom)) {
|
|
|
|
|
|
+ if (!ret && t->u.kernel.target->checkentry
|
|
|
|
+ && !t->u.kernel.target->checkentry(name, e, target,
|
|
|
|
+ t->data, e->comefrom)) {
|
|
duprintf("ip_tables: compat: check failed for `%s'.\n",
|
|
duprintf("ip_tables: compat: check failed for `%s'.\n",
|
|
t->u.kernel.target->name);
|
|
t->u.kernel.target->name);
|
|
ret = -EINVAL;
|
|
ret = -EINVAL;
|
|
}
|
|
}
|
|
-err:
|
|
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static inline int compat_check_entry(struct ipt_entry *e, const char *name)
|
|
|
|
+{
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ ret = IPT_MATCH_ITERATE(e, compat_check_match, name, &e->ip,
|
|
|
|
+ e->comefrom);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ return compat_check_target(e, name);
|
|
|
|
+}
|
|
|
|
+
|
|
static int
|
|
static int
|
|
translate_compat_table(const char *name,
|
|
translate_compat_table(const char *name,
|
|
unsigned int valid_hooks,
|
|
unsigned int valid_hooks,
|
|
@@ -1677,6 +1696,11 @@ translate_compat_table(const char *name,
|
|
if (!mark_source_chains(newinfo, valid_hooks, entry1))
|
|
if (!mark_source_chains(newinfo, valid_hooks, entry1))
|
|
goto free_newinfo;
|
|
goto free_newinfo;
|
|
|
|
|
|
|
|
+ ret = IPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry,
|
|
|
|
+ name);
|
|
|
|
+ if (ret)
|
|
|
|
+ goto free_newinfo;
|
|
|
|
+
|
|
/* And one copy for every other CPU */
|
|
/* And one copy for every other CPU */
|
|
for_each_possible_cpu(i)
|
|
for_each_possible_cpu(i)
|
|
if (newinfo->entries[i] && newinfo->entries[i] != entry1)
|
|
if (newinfo->entries[i] && newinfo->entries[i] != entry1)
|