Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f173c8a1 authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller
Browse files

[NETFILTER]: ip6_tables: move entry, match and target checks to seperate functions



Resync with ip_tables.c as preparation for compat support.

Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 72f36ec1
Loading
Loading
Loading
Loading
+82 −47
Original line number Diff line number Diff line
@@ -607,7 +607,51 @@ cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
}

static inline int
check_match(struct ip6t_entry_match *m,
check_entry(struct ip6t_entry *e, const char *name)
{
	struct ip6t_entry_target *t;

	if (!ip6_checkentry(&e->ipv6)) {
		duprintf("ip_tables: ip check failed %p %s.\n", e, name);
		return -EINVAL;
	}

	if (e->target_offset + sizeof(struct ip6t_entry_target) >
	    e->next_offset)
		return -EINVAL;

	t = ip6t_get_target(e);
	if (e->target_offset + t->u.target_size > e->next_offset)
		return -EINVAL;

	return 0;
}

static inline int check_match(struct ip6t_entry_match *m, const char *name,
			      const struct ip6t_ip6 *ipv6,
			      unsigned int hookmask, unsigned int *i)
{
	struct xt_match *match;
	int ret;

	match = m->u.kernel.match;
	ret = xt_check_match(match, AF_INET6, m->u.match_size - sizeof(*m),
			     name, hookmask, ipv6->proto,
			     ipv6->invflags & IP6T_INV_PROTO);
	if (!ret && m->u.kernel.match->checkentry
	    && !m->u.kernel.match->checkentry(name, ipv6, match, m->data,
					      hookmask)) {
		duprintf("ip_tables: check failed for `%s'.\n",
			 m->u.kernel.match->name);
		ret = -EINVAL;
	}
	if (!ret)
		(*i)++;
	return ret;
}

static inline int
find_check_match(struct ip6t_entry_match *m,
		 const char *name,
		 const struct ip6t_ip6 *ipv6,
		 unsigned int hookmask,
@@ -620,35 +664,44 @@ check_match(struct ip6t_entry_match *m,
					m->u.user.revision),
					"ip6t_%s", m->u.user.name);
	if (IS_ERR(match) || !match) {
		duprintf("check_match: `%s' not found\n", m->u.user.name);
		duprintf("find_check_match: `%s' not found\n", m->u.user.name);
		return match ? PTR_ERR(match) : -ENOENT;
	}
	m->u.kernel.match = match;

	ret = xt_check_match(match, AF_INET6, m->u.match_size - sizeof(*m),
			     name, hookmask, ipv6->proto,
			     ipv6->invflags & IP6T_INV_PROTO);
	ret = check_match(m, name, ipv6, hookmask, i);
	if (ret)
		goto err;

	if (m->u.kernel.match->checkentry
	    && !m->u.kernel.match->checkentry(name, ipv6, match,  m->data,
					      hookmask)) {
		duprintf("ip_tables: check failed for `%s'.\n",
			 m->u.kernel.match->name);
		ret = -EINVAL;
		goto err;
	}

	(*i)++;
	return 0;
err:
	module_put(m->u.kernel.match->me);
	return ret;
}

static inline int check_target(struct ip6t_entry *e, const char *name)
{
	struct ip6t_entry_target *t;
	struct xt_target *target;
	int ret;

	t = ip6t_get_target(e);
	target = t->u.kernel.target;
	ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t),
			      name, e->comefrom, e->ipv6.proto,
			      e->ipv6.invflags & IP6T_INV_PROTO);
	if (!ret && 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",
			 t->u.kernel.target->name);
		ret = -EINVAL;
	}
	return ret;
}

static inline int
check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
find_check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
		 unsigned int *i)
{
	struct ip6t_entry_target *t;
@@ -656,50 +709,32 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
	int ret;
	unsigned int j;

	if (!ip6_checkentry(&e->ipv6)) {
		duprintf("ip_tables: ip check failed %p %s.\n", e, name);
		return -EINVAL;
	}

	if (e->target_offset + sizeof(struct ip6t_entry_target) >
								e->next_offset)
		return -EINVAL;
	ret = check_entry(e, name);
	if (ret)
		return ret;

	j = 0;
	ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
	ret = IP6T_MATCH_ITERATE(e, find_check_match, name, &e->ipv6,
				 e->comefrom, &j);
	if (ret != 0)
		goto cleanup_matches;

	t = ip6t_get_target(e);
	ret = -EINVAL;
	if (e->target_offset + t->u.target_size > e->next_offset)
			goto cleanup_matches;
	target = try_then_request_module(xt_find_target(AF_INET6,
							t->u.user.name,
							t->u.user.revision),
					 "ip6t_%s", t->u.user.name);
	if (IS_ERR(target) || !target) {
		duprintf("check_entry: `%s' not found\n", t->u.user.name);
		duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
		ret = target ? PTR_ERR(target) : -ENOENT;
		goto cleanup_matches;
	}
	t->u.kernel.target = target;

	ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t),
			      name, e->comefrom, e->ipv6.proto,
			      e->ipv6.invflags & IP6T_INV_PROTO);
	ret = check_target(e, name);
	if (ret)
		goto err;

	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",
			 t->u.kernel.target->name);
		ret = -EINVAL;
		goto err;
	}

	(*i)++;
	return 0;
 err:
@@ -834,7 +869,7 @@ translate_table(const char *name,
	/* Finally, each sanity check must pass */
	i = 0;
	ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
				check_entry, name, size, &i);
				find_check_entry, name, size, &i);

	if (ret != 0) {
		IP6T_ENTRY_ITERATE(entry0, newinfo->size,