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

Commit 54831a83 authored by David S. Miller's avatar David S. Miller
Browse files
parents fb977e2c 0f234214
Loading
Loading
Loading
Loading
+17 −0
Original line number Original line Diff line number Diff line
@@ -120,6 +120,7 @@ struct xt_counters_info {


#define XT_INV_PROTO		0x40	/* Invert the sense of PROTO. */
#define XT_INV_PROTO		0x40	/* Invert the sense of PROTO. */


#ifndef __KERNEL__
/* fn returns 0 to continue iteration */
/* fn returns 0 to continue iteration */
#define XT_MATCH_ITERATE(type, e, fn, args...)			\
#define XT_MATCH_ITERATE(type, e, fn, args...)			\
({								\
({								\
@@ -163,6 +164,22 @@ struct xt_counters_info {
#define XT_ENTRY_ITERATE(type, entries, size, fn, args...) \
#define XT_ENTRY_ITERATE(type, entries, size, fn, args...) \
	XT_ENTRY_ITERATE_CONTINUE(type, entries, size, 0, fn, args)
	XT_ENTRY_ITERATE_CONTINUE(type, entries, size, 0, fn, args)


#endif /* !__KERNEL__ */

/* pos is normally a struct ipt_entry/ip6t_entry/etc. */
#define xt_entry_foreach(pos, ehead, esize) \
	for ((pos) = (typeof(pos))(ehead); \
	     (pos) < (typeof(pos))((char *)(ehead) + (esize)); \
	     (pos) = (typeof(pos))((char *)(pos) + (pos)->next_offset))

/* can only be xt_entry_match, so no use of typeof here */
#define xt_ematch_foreach(pos, entry) \
	for ((pos) = (struct xt_entry_match *)entry->elems; \
	     (pos) < (struct xt_entry_match *)((char *)(entry) + \
	             (entry)->target_offset); \
	     (pos) = (struct xt_entry_match *)((char *)(pos) + \
	             (pos)->u.match_size))

#ifdef __KERNEL__
#ifdef __KERNEL__


#include <linux/netdevice.h>
#include <linux/netdevice.h>
+2 −8
Original line number Original line Diff line number Diff line
@@ -211,9 +211,11 @@ static __inline__ struct arpt_entry_target *arpt_get_target(struct arpt_entry *e
	return (void *)e + e->target_offset;
	return (void *)e + e->target_offset;
}
}


#ifndef __KERNEL__
/* fn returns 0 to continue iteration */
/* fn returns 0 to continue iteration */
#define ARPT_ENTRY_ITERATE(entries, size, fn, args...) \
#define ARPT_ENTRY_ITERATE(entries, size, fn, args...) \
	XT_ENTRY_ITERATE(struct arpt_entry, entries, size, fn, ## args)
	XT_ENTRY_ITERATE(struct arpt_entry, entries, size, fn, ## args)
#endif


/*
/*
 *	Main firewall chains definitions and global var's definitions.
 *	Main firewall chains definitions and global var's definitions.
@@ -291,14 +293,6 @@ compat_arpt_get_target(struct compat_arpt_entry *e)


#define COMPAT_ARPT_ALIGN(s)	COMPAT_XT_ALIGN(s)
#define COMPAT_ARPT_ALIGN(s)	COMPAT_XT_ALIGN(s)


/* fn returns 0 to continue iteration */
#define COMPAT_ARPT_ENTRY_ITERATE(entries, size, fn, args...) \
	XT_ENTRY_ITERATE(struct compat_arpt_entry, entries, size, fn, ## args)

#define COMPAT_ARPT_ENTRY_ITERATE_CONTINUE(entries, size, n, fn, args...) \
	XT_ENTRY_ITERATE_CONTINUE(struct compat_arpt_entry, entries, size, n, \
				  fn, ## args)

#endif /* CONFIG_COMPAT */
#endif /* CONFIG_COMPAT */
#endif /*__KERNEL__*/
#endif /*__KERNEL__*/
#endif /* _ARPTABLES_H */
#endif /* _ARPTABLES_H */
+2 −13
Original line number Original line Diff line number Diff line
@@ -223,6 +223,7 @@ ipt_get_target(struct ipt_entry *e)
	return (void *)e + e->target_offset;
	return (void *)e + e->target_offset;
}
}


#ifndef __KERNEL__
/* fn returns 0 to continue iteration */
/* fn returns 0 to continue iteration */
#define IPT_MATCH_ITERATE(e, fn, args...) \
#define IPT_MATCH_ITERATE(e, fn, args...) \
	XT_MATCH_ITERATE(struct ipt_entry, e, fn, ## args)
	XT_MATCH_ITERATE(struct ipt_entry, e, fn, ## args)
@@ -230,6 +231,7 @@ ipt_get_target(struct ipt_entry *e)
/* fn returns 0 to continue iteration */
/* fn returns 0 to continue iteration */
#define IPT_ENTRY_ITERATE(entries, size, fn, args...) \
#define IPT_ENTRY_ITERATE(entries, size, fn, args...) \
	XT_ENTRY_ITERATE(struct ipt_entry, entries, size, fn, ## args)
	XT_ENTRY_ITERATE(struct ipt_entry, entries, size, fn, ## args)
#endif


/*
/*
 *	Main firewall chains definitions and global var's definitions.
 *	Main firewall chains definitions and global var's definitions.
@@ -313,19 +315,6 @@ compat_ipt_get_target(struct compat_ipt_entry *e)


#define COMPAT_IPT_ALIGN(s) 	COMPAT_XT_ALIGN(s)
#define COMPAT_IPT_ALIGN(s) 	COMPAT_XT_ALIGN(s)


/* fn returns 0 to continue iteration */
#define COMPAT_IPT_MATCH_ITERATE(e, fn, args...) \
	XT_MATCH_ITERATE(struct compat_ipt_entry, e, fn, ## args)

/* fn returns 0 to continue iteration */
#define COMPAT_IPT_ENTRY_ITERATE(entries, size, fn, args...) \
	XT_ENTRY_ITERATE(struct compat_ipt_entry, entries, size, fn, ## args)

/* fn returns 0 to continue iteration */
#define COMPAT_IPT_ENTRY_ITERATE_CONTINUE(entries, size, n, fn, args...) \
	XT_ENTRY_ITERATE_CONTINUE(struct compat_ipt_entry, entries, size, n, \
				  fn, ## args)

#endif /* CONFIG_COMPAT */
#endif /* CONFIG_COMPAT */
#endif /*__KERNEL__*/
#endif /*__KERNEL__*/
#endif /* _IPTABLES_H */
#endif /* _IPTABLES_H */
+2 −12
Original line number Original line Diff line number Diff line
@@ -280,6 +280,7 @@ ip6t_get_target(struct ip6t_entry *e)
	return (void *)e + e->target_offset;
	return (void *)e + e->target_offset;
}
}


#ifndef __KERNEL__
/* fn returns 0 to continue iteration */
/* fn returns 0 to continue iteration */
#define IP6T_MATCH_ITERATE(e, fn, args...) \
#define IP6T_MATCH_ITERATE(e, fn, args...) \
	XT_MATCH_ITERATE(struct ip6t_entry, e, fn, ## args)
	XT_MATCH_ITERATE(struct ip6t_entry, e, fn, ## args)
@@ -287,6 +288,7 @@ ip6t_get_target(struct ip6t_entry *e)
/* fn returns 0 to continue iteration */
/* fn returns 0 to continue iteration */
#define IP6T_ENTRY_ITERATE(entries, size, fn, args...) \
#define IP6T_ENTRY_ITERATE(entries, size, fn, args...) \
	XT_ENTRY_ITERATE(struct ip6t_entry, entries, size, fn, ## args)
	XT_ENTRY_ITERATE(struct ip6t_entry, entries, size, fn, ## args)
#endif


/*
/*
 *	Main firewall chains definitions and global var's definitions.
 *	Main firewall chains definitions and global var's definitions.
@@ -341,18 +343,6 @@ compat_ip6t_get_target(struct compat_ip6t_entry *e)


#define COMPAT_IP6T_ALIGN(s)	COMPAT_XT_ALIGN(s)
#define COMPAT_IP6T_ALIGN(s)	COMPAT_XT_ALIGN(s)


/* fn returns 0 to continue iteration */
#define COMPAT_IP6T_MATCH_ITERATE(e, fn, args...) \
	XT_MATCH_ITERATE(struct compat_ip6t_entry, e, fn, ## args)

/* fn returns 0 to continue iteration */
#define COMPAT_IP6T_ENTRY_ITERATE(entries, size, fn, args...) \
	XT_ENTRY_ITERATE(struct compat_ip6t_entry, entries, size, fn, ## args)

#define COMPAT_IP6T_ENTRY_ITERATE_CONTINUE(entries, size, n, fn, args...) \
	XT_ENTRY_ITERATE_CONTINUE(struct compat_ip6t_entry, entries, size, n, \
				  fn, ## args)

#endif /* CONFIG_COMPAT */
#endif /* CONFIG_COMPAT */
#endif /*__KERNEL__*/
#endif /*__KERNEL__*/
#endif /* _IP6_TABLES_H */
#endif /* _IP6_TABLES_H */
+135 −166
Original line number Original line Diff line number Diff line
@@ -512,8 +512,7 @@ static inline int check_target(struct arpt_entry *e, const char *name)
}
}


static inline int
static inline int
find_check_entry(struct arpt_entry *e, const char *name, unsigned int size,
find_check_entry(struct arpt_entry *e, const char *name, unsigned int size)
		 unsigned int *i)
{
{
	struct arpt_entry_target *t;
	struct arpt_entry_target *t;
	struct xt_target *target;
	struct xt_target *target;
@@ -538,8 +537,6 @@ find_check_entry(struct arpt_entry *e, const char *name, unsigned int size,
	ret = check_target(e, name);
	ret = check_target(e, name);
	if (ret)
	if (ret)
		goto err;
		goto err;

	(*i)++;
	return 0;
	return 0;
err:
err:
	module_put(t->u.kernel.target->me);
	module_put(t->u.kernel.target->me);
@@ -568,8 +565,7 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e,
					     const unsigned char *limit,
					     const unsigned char *limit,
					     const unsigned int *hook_entries,
					     const unsigned int *hook_entries,
					     const unsigned int *underflows,
					     const unsigned int *underflows,
					     unsigned int valid_hooks,
					     unsigned int valid_hooks)
					     unsigned int *i)
{
{
	unsigned int h;
	unsigned int h;


@@ -606,19 +602,14 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e,
	/* Clear counters and comefrom */
	/* Clear counters and comefrom */
	e->counters = ((struct xt_counters) { 0, 0 });
	e->counters = ((struct xt_counters) { 0, 0 });
	e->comefrom = 0;
	e->comefrom = 0;

	(*i)++;
	return 0;
	return 0;
}
}


static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i)
static inline void cleanup_entry(struct arpt_entry *e)
{
{
	struct xt_tgdtor_param par;
	struct xt_tgdtor_param par;
	struct arpt_entry_target *t;
	struct arpt_entry_target *t;


	if (i && (*i)-- == 0)
		return 1;

	t = arpt_get_target(e);
	t = arpt_get_target(e);
	par.target   = t->u.kernel.target;
	par.target   = t->u.kernel.target;
	par.targinfo = t->data;
	par.targinfo = t->data;
@@ -626,26 +617,20 @@ static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i)
	if (par.target->destroy != NULL)
	if (par.target->destroy != NULL)
		par.target->destroy(&par);
		par.target->destroy(&par);
	module_put(par.target->me);
	module_put(par.target->me);
	return 0;
}
}


/* Checks and translates the user-supplied table segment (held in
/* Checks and translates the user-supplied table segment (held in
 * newinfo).
 * newinfo).
 */
 */
static int translate_table(const char *name,
static int translate_table(struct xt_table_info *newinfo, void *entry0,
			   unsigned int valid_hooks,
                           const struct arpt_replace *repl)
			   struct xt_table_info *newinfo,
			   void *entry0,
			   unsigned int size,
			   unsigned int number,
			   const unsigned int *hook_entries,
			   const unsigned int *underflows)
{
{
	struct arpt_entry *iter;
	unsigned int i;
	unsigned int i;
	int ret;
	int ret = 0;


	newinfo->size = size;
	newinfo->size = repl->size;
	newinfo->number = number;
	newinfo->number = repl->num_entries;


	/* Init all hooks to impossible value. */
	/* Init all hooks to impossible value. */
	for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
	for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
@@ -657,52 +642,61 @@ static int translate_table(const char *name,
	i = 0;
	i = 0;


	/* Walk through entries, checking offsets. */
	/* Walk through entries, checking offsets. */
	ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size,
	xt_entry_foreach(iter, entry0, newinfo->size) {
				 check_entry_size_and_hooks,
		ret = check_entry_size_and_hooks(iter, newinfo, entry0,
				 newinfo,
		      entry0 + repl->size, repl->hook_entry, repl->underflow,
				 entry0,
		      repl->valid_hooks);
				 entry0 + size,
		if (ret != 0)
				 hook_entries, underflows, valid_hooks, &i);
			break;
		++i;
	}
	duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret);
	duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret);
	if (ret != 0)
	if (ret != 0)
		return ret;
		return ret;


	if (i != number) {
	if (i != repl->num_entries) {
		duprintf("translate_table: %u not %u entries\n",
		duprintf("translate_table: %u not %u entries\n",
			 i, number);
			 i, repl->num_entries);
		return -EINVAL;
		return -EINVAL;
	}
	}


	/* Check hooks all assigned */
	/* Check hooks all assigned */
	for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
	for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
		/* Only hooks which are valid */
		/* Only hooks which are valid */
		if (!(valid_hooks & (1 << i)))
		if (!(repl->valid_hooks & (1 << i)))
			continue;
			continue;
		if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
		if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
			duprintf("Invalid hook entry %u %u\n",
			duprintf("Invalid hook entry %u %u\n",
				 i, hook_entries[i]);
				 i, repl->hook_entry[i]);
			return -EINVAL;
			return -EINVAL;
		}
		}
		if (newinfo->underflow[i] == 0xFFFFFFFF) {
		if (newinfo->underflow[i] == 0xFFFFFFFF) {
			duprintf("Invalid underflow %u %u\n",
			duprintf("Invalid underflow %u %u\n",
				 i, underflows[i]);
				 i, repl->underflow[i]);
			return -EINVAL;
			return -EINVAL;
		}
		}
	}
	}


	if (!mark_source_chains(newinfo, valid_hooks, entry0)) {
	if (!mark_source_chains(newinfo, repl->valid_hooks, entry0)) {
		duprintf("Looping hook\n");
		duprintf("Looping hook\n");
		return -ELOOP;
		return -ELOOP;
	}
	}


	/* Finally, each sanity check must pass */
	/* Finally, each sanity check must pass */
	i = 0;
	i = 0;
	ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size,
	xt_entry_foreach(iter, entry0, newinfo->size) {
				 find_check_entry, name, size, &i);
		ret = find_check_entry(iter, repl->name, repl->size);
		if (ret != 0)
			break;
		++i;
	}


	if (ret != 0) {
	if (ret != 0) {
		ARPT_ENTRY_ITERATE(entry0, newinfo->size,
		xt_entry_foreach(iter, entry0, newinfo->size) {
				cleanup_entry, &i);
			if (i-- == 0)
				break;
			cleanup_entry(iter);
		}
		return ret;
		return ret;
	}
	}


@@ -715,30 +709,10 @@ static int translate_table(const char *name,
	return ret;
	return ret;
}
}


/* Gets counters. */
static inline int add_entry_to_counter(const struct arpt_entry *e,
				       struct xt_counters total[],
				       unsigned int *i)
{
	ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);

	(*i)++;
	return 0;
}

static inline int set_entry_to_counter(const struct arpt_entry *e,
				       struct xt_counters total[],
				       unsigned int *i)
{
	SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);

	(*i)++;
	return 0;
}

static void get_counters(const struct xt_table_info *t,
static void get_counters(const struct xt_table_info *t,
			 struct xt_counters counters[])
			 struct xt_counters counters[])
{
{
	struct arpt_entry *iter;
	unsigned int cpu;
	unsigned int cpu;
	unsigned int i;
	unsigned int i;
	unsigned int curcpu;
	unsigned int curcpu;
@@ -754,22 +728,22 @@ static void get_counters(const struct xt_table_info *t,
	curcpu = smp_processor_id();
	curcpu = smp_processor_id();


	i = 0;
	i = 0;
	ARPT_ENTRY_ITERATE(t->entries[curcpu],
	xt_entry_foreach(iter, t->entries[curcpu], t->size) {
			   t->size,
		SET_COUNTER(counters[i], iter->counters.bcnt,
			   set_entry_to_counter,
			iter->counters.pcnt);
			   counters,
		++i;
			   &i);
	}


	for_each_possible_cpu(cpu) {
	for_each_possible_cpu(cpu) {
		if (cpu == curcpu)
		if (cpu == curcpu)
			continue;
			continue;
		i = 0;
		i = 0;
		xt_info_wrlock(cpu);
		xt_info_wrlock(cpu);
		ARPT_ENTRY_ITERATE(t->entries[cpu],
		xt_entry_foreach(iter, t->entries[cpu], t->size) {
				   t->size,
			ADD_COUNTER(counters[i], iter->counters.bcnt,
				   add_entry_to_counter,
				iter->counters.pcnt);
				   counters,
			++i;
				   &i);
		}
		xt_info_wrunlock(cpu);
		xt_info_wrunlock(cpu);
	}
	}
	local_bh_enable();
	local_bh_enable();
@@ -899,7 +873,9 @@ static int compat_calc_entry(const struct arpt_entry *e,
static int compat_table_info(const struct xt_table_info *info,
static int compat_table_info(const struct xt_table_info *info,
			     struct xt_table_info *newinfo)
			     struct xt_table_info *newinfo)
{
{
	struct arpt_entry *iter;
	void *loc_cpu_entry;
	void *loc_cpu_entry;
	int ret;


	if (!newinfo || !info)
	if (!newinfo || !info)
		return -EINVAL;
		return -EINVAL;
@@ -908,9 +884,12 @@ static int compat_table_info(const struct xt_table_info *info,
	memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
	memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
	newinfo->initial_entries = 0;
	newinfo->initial_entries = 0;
	loc_cpu_entry = info->entries[raw_smp_processor_id()];
	loc_cpu_entry = info->entries[raw_smp_processor_id()];
	return ARPT_ENTRY_ITERATE(loc_cpu_entry, info->size,
	xt_entry_foreach(iter, loc_cpu_entry, info->size) {
				  compat_calc_entry, info, loc_cpu_entry,
		ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo);
				  newinfo);
		if (ret != 0)
			return ret;
	}
	return 0;
}
}
#endif
#endif


@@ -1025,6 +1004,7 @@ static int __do_replace(struct net *net, const char *name,
	struct xt_table_info *oldinfo;
	struct xt_table_info *oldinfo;
	struct xt_counters *counters;
	struct xt_counters *counters;
	void *loc_cpu_old_entry;
	void *loc_cpu_old_entry;
	struct arpt_entry *iter;


	ret = 0;
	ret = 0;
	counters = vmalloc_node(num_counters * sizeof(struct xt_counters),
	counters = vmalloc_node(num_counters * sizeof(struct xt_counters),
@@ -1068,8 +1048,8 @@ static int __do_replace(struct net *net, const char *name,


	/* Decrease module usage counts and free resource */
	/* Decrease module usage counts and free resource */
	loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
	loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
	ARPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,
	xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size)
			   NULL);
		cleanup_entry(iter);


	xt_free_table_info(oldinfo);
	xt_free_table_info(oldinfo);
	if (copy_to_user(counters_ptr, counters,
	if (copy_to_user(counters_ptr, counters,
@@ -1095,6 +1075,7 @@ static int do_replace(struct net *net, const void __user *user,
	struct arpt_replace tmp;
	struct arpt_replace tmp;
	struct xt_table_info *newinfo;
	struct xt_table_info *newinfo;
	void *loc_cpu_entry;
	void *loc_cpu_entry;
	struct arpt_entry *iter;


	if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
	if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
		return -EFAULT;
		return -EFAULT;
@@ -1115,9 +1096,7 @@ static int do_replace(struct net *net, const void __user *user,
		goto free_newinfo;
		goto free_newinfo;
	}
	}


	ret = translate_table(tmp.name, tmp.valid_hooks,
	ret = translate_table(newinfo, loc_cpu_entry, &tmp);
			      newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
			      tmp.hook_entry, tmp.underflow);
	if (ret != 0)
	if (ret != 0)
		goto free_newinfo;
		goto free_newinfo;


@@ -1130,25 +1109,13 @@ static int do_replace(struct net *net, const void __user *user,
	return 0;
	return 0;


 free_newinfo_untrans:
 free_newinfo_untrans:
	ARPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
	xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
		cleanup_entry(iter);
 free_newinfo:
 free_newinfo:
	xt_free_table_info(newinfo);
	xt_free_table_info(newinfo);
	return ret;
	return ret;
}
}


/* We're lazy, and add to the first CPU; overflow works its fey magic
 * and everything is OK. */
static int
add_counter_to_entry(struct arpt_entry *e,
		     const struct xt_counters addme[],
		     unsigned int *i)
{
	ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);

	(*i)++;
	return 0;
}

static int do_add_counters(struct net *net, const void __user *user,
static int do_add_counters(struct net *net, const void __user *user,
			   unsigned int len, int compat)
			   unsigned int len, int compat)
{
{
@@ -1163,6 +1130,7 @@ static int do_add_counters(struct net *net, const void __user *user,
	const struct xt_table_info *private;
	const struct xt_table_info *private;
	int ret = 0;
	int ret = 0;
	void *loc_cpu_entry;
	void *loc_cpu_entry;
	struct arpt_entry *iter;
#ifdef CONFIG_COMPAT
#ifdef CONFIG_COMPAT
	struct compat_xt_counters_info compat_tmp;
	struct compat_xt_counters_info compat_tmp;


@@ -1220,11 +1188,10 @@ static int do_add_counters(struct net *net, const void __user *user,
	curcpu = smp_processor_id();
	curcpu = smp_processor_id();
	loc_cpu_entry = private->entries[curcpu];
	loc_cpu_entry = private->entries[curcpu];
	xt_info_wrlock(curcpu);
	xt_info_wrlock(curcpu);
	ARPT_ENTRY_ITERATE(loc_cpu_entry,
	xt_entry_foreach(iter, loc_cpu_entry, private->size) {
			   private->size,
		ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt);
			   add_counter_to_entry,
		++i;
			   paddc,
	}
			   &i);
	xt_info_wrunlock(curcpu);
	xt_info_wrunlock(curcpu);
 unlock_up_free:
 unlock_up_free:
	local_bh_enable();
	local_bh_enable();
@@ -1237,17 +1204,12 @@ static int do_add_counters(struct net *net, const void __user *user,
}
}


#ifdef CONFIG_COMPAT
#ifdef CONFIG_COMPAT
static inline int
static inline void compat_release_entry(struct compat_arpt_entry *e)
compat_release_entry(struct compat_arpt_entry *e, unsigned int *i)
{
{
	struct arpt_entry_target *t;
	struct arpt_entry_target *t;


	if (i && (*i)-- == 0)
		return 1;

	t = compat_arpt_get_target(e);
	t = compat_arpt_get_target(e);
	module_put(t->u.kernel.target->me);
	module_put(t->u.kernel.target->me);
	return 0;
}
}


static inline int
static inline int
@@ -1258,7 +1220,6 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e,
				  const unsigned char *limit,
				  const unsigned char *limit,
				  const unsigned int *hook_entries,
				  const unsigned int *hook_entries,
				  const unsigned int *underflows,
				  const unsigned int *underflows,
				  unsigned int *i,
				  const char *name)
				  const char *name)
{
{
	struct arpt_entry_target *t;
	struct arpt_entry_target *t;
@@ -1318,8 +1279,6 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e,
	/* Clear counters and comefrom */
	/* Clear counters and comefrom */
	memset(&e->counters, 0, sizeof(e->counters));
	memset(&e->counters, 0, sizeof(e->counters));
	e->comefrom = 0;
	e->comefrom = 0;

	(*i)++;
	return 0;
	return 0;


release_target:
release_target:
@@ -1363,19 +1322,6 @@ compat_copy_entry_from_user(struct compat_arpt_entry *e, void **dstptr,
	return ret;
	return ret;
}
}


static inline int compat_check_entry(struct arpt_entry *e, const char *name,
				     unsigned int *i)
{
	int ret;

	ret = check_target(e, name);
	if (ret)
		return ret;

	(*i)++;
	return 0;
}

static int translate_compat_table(const char *name,
static int translate_compat_table(const char *name,
				  unsigned int valid_hooks,
				  unsigned int valid_hooks,
				  struct xt_table_info **pinfo,
				  struct xt_table_info **pinfo,
@@ -1388,8 +1334,10 @@ static int translate_compat_table(const char *name,
	unsigned int i, j;
	unsigned int i, j;
	struct xt_table_info *newinfo, *info;
	struct xt_table_info *newinfo, *info;
	void *pos, *entry0, *entry1;
	void *pos, *entry0, *entry1;
	struct compat_arpt_entry *iter0;
	struct arpt_entry *iter1;
	unsigned int size;
	unsigned int size;
	int ret;
	int ret = 0;


	info = *pinfo;
	info = *pinfo;
	entry0 = *pentry0;
	entry0 = *pentry0;
@@ -1406,13 +1354,14 @@ static int translate_compat_table(const char *name,
	j = 0;
	j = 0;
	xt_compat_lock(NFPROTO_ARP);
	xt_compat_lock(NFPROTO_ARP);
	/* Walk through entries, checking offsets. */
	/* Walk through entries, checking offsets. */
	ret = COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size,
	xt_entry_foreach(iter0, entry0, total_size) {
					check_compat_entry_size_and_hooks,
		ret = check_compat_entry_size_and_hooks(iter0, info, &size,
					info, &size, entry0,
		      entry0, entry0 + total_size, hook_entries, underflows,
					entry0 + total_size,
		      name);
					hook_entries, underflows, &j, name);
		if (ret != 0)
		if (ret != 0)
			goto out_unlock;
			goto out_unlock;
		++j;
	}


	ret = -EINVAL;
	ret = -EINVAL;
	if (j != number) {
	if (j != number) {
@@ -1451,9 +1400,12 @@ static int translate_compat_table(const char *name,
	entry1 = newinfo->entries[raw_smp_processor_id()];
	entry1 = newinfo->entries[raw_smp_processor_id()];
	pos = entry1;
	pos = entry1;
	size = total_size;
	size = total_size;
	ret = COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size,
	xt_entry_foreach(iter0, entry0, total_size) {
					compat_copy_entry_from_user,
		ret = compat_copy_entry_from_user(iter0, &pos,
					&pos, &size, name, newinfo, entry1);
		      &size, name, newinfo, entry1);
		if (ret != 0)
			break;
	}
	xt_compat_flush_offsets(NFPROTO_ARP);
	xt_compat_flush_offsets(NFPROTO_ARP);
	xt_compat_unlock(NFPROTO_ARP);
	xt_compat_unlock(NFPROTO_ARP);
	if (ret)
	if (ret)
@@ -1464,13 +1416,32 @@ static int translate_compat_table(const char *name,
		goto free_newinfo;
		goto free_newinfo;


	i = 0;
	i = 0;
	ret = ARPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry,
	xt_entry_foreach(iter1, entry1, newinfo->size) {
				 name, &i);
		ret = check_target(iter1, name);
		if (ret != 0)
			break;
		++i;
	}
	if (ret) {
	if (ret) {
		/*
		 * The first i matches need cleanup_entry (calls ->destroy)
		 * because they had called ->check already. The other j-i
		 * entries need only release.
		 */
		int skip = i;
		j -= i;
		j -= i;
		COMPAT_ARPT_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i,
		xt_entry_foreach(iter0, entry0, newinfo->size) {
						   compat_release_entry, &j);
			if (skip-- > 0)
		ARPT_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i);
				continue;
			if (j-- == 0)
				break;
			compat_release_entry(iter0);
		}
		xt_entry_foreach(iter1, entry1, newinfo->size) {
			if (i-- == 0)
				break;
			cleanup_entry(iter1);
		}
		xt_free_table_info(newinfo);
		xt_free_table_info(newinfo);
		return ret;
		return ret;
	}
	}
@@ -1488,7 +1459,11 @@ static int translate_compat_table(const char *name,
free_newinfo:
free_newinfo:
	xt_free_table_info(newinfo);
	xt_free_table_info(newinfo);
out:
out:
	COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j);
	xt_entry_foreach(iter0, entry0, total_size) {
		if (j-- == 0)
			break;
		compat_release_entry(iter0);
	}
	return ret;
	return ret;
out_unlock:
out_unlock:
	xt_compat_flush_offsets(NFPROTO_ARP);
	xt_compat_flush_offsets(NFPROTO_ARP);
@@ -1515,6 +1490,7 @@ static int compat_do_replace(struct net *net, void __user *user,
	struct compat_arpt_replace tmp;
	struct compat_arpt_replace tmp;
	struct xt_table_info *newinfo;
	struct xt_table_info *newinfo;
	void *loc_cpu_entry;
	void *loc_cpu_entry;
	struct arpt_entry *iter;


	if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
	if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
		return -EFAULT;
		return -EFAULT;
@@ -1552,7 +1528,8 @@ static int compat_do_replace(struct net *net, void __user *user,
	return 0;
	return 0;


 free_newinfo_untrans:
 free_newinfo_untrans:
	ARPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
	xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
		cleanup_entry(iter);
 free_newinfo:
 free_newinfo:
	xt_free_table_info(newinfo);
	xt_free_table_info(newinfo);
	return ret;
	return ret;
@@ -1586,7 +1563,7 @@ static int compat_do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user,
static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr,
static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr,
				     compat_uint_t *size,
				     compat_uint_t *size,
				     struct xt_counters *counters,
				     struct xt_counters *counters,
				     unsigned int *i)
				     unsigned int i)
{
{
	struct arpt_entry_target *t;
	struct arpt_entry_target *t;
	struct compat_arpt_entry __user *ce;
	struct compat_arpt_entry __user *ce;
@@ -1594,14 +1571,12 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr,
	compat_uint_t origsize;
	compat_uint_t origsize;
	int ret;
	int ret;


	ret = -EFAULT;
	origsize = *size;
	origsize = *size;
	ce = (struct compat_arpt_entry __user *)*dstptr;
	ce = (struct compat_arpt_entry __user *)*dstptr;
	if (copy_to_user(ce, e, sizeof(struct arpt_entry)))
	if (copy_to_user(ce, e, sizeof(struct arpt_entry)) != 0 ||
		goto out;
	    copy_to_user(&ce->counters, &counters[i],

	    sizeof(counters[i])) != 0)
	if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i])))
		return -EFAULT;
		goto out;


	*dstptr += sizeof(struct compat_arpt_entry);
	*dstptr += sizeof(struct compat_arpt_entry);
	*size -= sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry);
	*size -= sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry);
@@ -1611,18 +1586,12 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr,
	t = arpt_get_target(e);
	t = arpt_get_target(e);
	ret = xt_compat_target_to_user(t, dstptr, size);
	ret = xt_compat_target_to_user(t, dstptr, size);
	if (ret)
	if (ret)
		goto out;
		return ret;
	ret = -EFAULT;
	next_offset = e->next_offset - (origsize - *size);
	next_offset = e->next_offset - (origsize - *size);
	if (put_user(target_offset, &ce->target_offset))
	if (put_user(target_offset, &ce->target_offset) != 0 ||
		goto out;
	    put_user(next_offset, &ce->next_offset) != 0)
	if (put_user(next_offset, &ce->next_offset))
		return -EFAULT;
		goto out;

	(*i)++;
	return 0;
	return 0;
out:
	return ret;
}
}


static int compat_copy_entries_to_user(unsigned int total_size,
static int compat_copy_entries_to_user(unsigned int total_size,
@@ -1636,6 +1605,7 @@ static int compat_copy_entries_to_user(unsigned int total_size,
	int ret = 0;
	int ret = 0;
	void *loc_cpu_entry;
	void *loc_cpu_entry;
	unsigned int i = 0;
	unsigned int i = 0;
	struct arpt_entry *iter;


	counters = alloc_counters(table);
	counters = alloc_counters(table);
	if (IS_ERR(counters))
	if (IS_ERR(counters))
@@ -1645,9 +1615,12 @@ static int compat_copy_entries_to_user(unsigned int total_size,
	loc_cpu_entry = private->entries[raw_smp_processor_id()];
	loc_cpu_entry = private->entries[raw_smp_processor_id()];
	pos = userptr;
	pos = userptr;
	size = total_size;
	size = total_size;
	ret = ARPT_ENTRY_ITERATE(loc_cpu_entry, total_size,
	xt_entry_foreach(iter, loc_cpu_entry, total_size) {
				 compat_copy_entry_to_user,
		ret = compat_copy_entry_to_user(iter, &pos,
				 &pos, &size, counters, &i);
		      &size, counters, i++);
		if (ret != 0)
			break;
	}
	vfree(counters);
	vfree(counters);
	return ret;
	return ret;
}
}
@@ -1815,12 +1788,7 @@ struct xt_table *arpt_register_table(struct net *net,
	loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
	loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
	memcpy(loc_cpu_entry, repl->entries, repl->size);
	memcpy(loc_cpu_entry, repl->entries, repl->size);


	ret = translate_table(table->name, table->valid_hooks,
	ret = translate_table(newinfo, loc_cpu_entry, repl);
			      newinfo, loc_cpu_entry, repl->size,
			      repl->num_entries,
			      repl->hook_entry,
			      repl->underflow);

	duprintf("arpt_register_table: translate table gives %d\n", ret);
	duprintf("arpt_register_table: translate table gives %d\n", ret);
	if (ret != 0)
	if (ret != 0)
		goto out_free;
		goto out_free;
@@ -1843,13 +1811,14 @@ void arpt_unregister_table(struct xt_table *table)
	struct xt_table_info *private;
	struct xt_table_info *private;
	void *loc_cpu_entry;
	void *loc_cpu_entry;
	struct module *table_owner = table->me;
	struct module *table_owner = table->me;
	struct arpt_entry *iter;


	private = xt_unregister_table(table);
	private = xt_unregister_table(table);


	/* Decrease module usage counts and free resources */
	/* Decrease module usage counts and free resources */
	loc_cpu_entry = private->entries[raw_smp_processor_id()];
	loc_cpu_entry = private->entries[raw_smp_processor_id()];
	ARPT_ENTRY_ITERATE(loc_cpu_entry, private->size,
	xt_entry_foreach(iter, loc_cpu_entry, private->size)
			   cleanup_entry, NULL);
		cleanup_entry(iter);
	if (private->number > private->initial_entries)
	if (private->number > private->initial_entries)
		module_put(table_owner);
		module_put(table_owner);
	xt_free_table_info(private);
	xt_free_table_info(private);
Loading