countersize = COUNTER_OFFSET(tmp.nentries) * num_possible_cpus(); 
countersize = COUNTER_OFFSET(tmp.nentries) * (highest_possible_processor_id()+1); 
static int do_replace(void __user *user, unsigned int len){	int ret, i, countersize;	struct ebt_table_info *newinfo;	struct ebt_replace tmp;	struct ebt_table *t;	struct ebt_counter *counterstmp = NULL;	/* used to be able to unlock earlier */	struct ebt_table_info *table;	if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)		return -EFAULT;	if (len != sizeof(tmp) + tmp.entries_size) {		BUGPRINT("Wrong len argument\n");		return -EINVAL;	}	if (tmp.entries_size == 0) {		BUGPRINT("Entries_size never zero\n");		return -EINVAL;	}	countersize = COUNTER_OFFSET(tmp.nentries) * num_possible_cpus();	newinfo = (struct ebt_table_info *)	   vmalloc(sizeof(struct ebt_table_info) + countersize);	if (!newinfo)		return -ENOMEM;	if (countersize)		memset(newinfo->counters, 0, countersize);	newinfo->entries = (char *)vmalloc(tmp.entries_size);	if (!newinfo->entries) {		ret = -ENOMEM;		goto free_newinfo;	}	if (copy_from_user(	   newinfo->entries, tmp.entries, tmp.entries_size) != 0) {		BUGPRINT("Couldn't copy entries from userspace\n");		ret = -EFAULT;		goto free_entries;	}	/* the user wants counters back	   the check on the size is done later, when we have the lock */	if (tmp.num_counters) {		counterstmp = (struct ebt_counter *)		   vmalloc(tmp.num_counters * sizeof(struct ebt_counter));		if (!counterstmp) {			ret = -ENOMEM;			goto free_entries;		}	}	else		counterstmp = NULL;	/* this can get initialized by translate_table() */	newinfo->chainstack = NULL;	ret = translate_table(&tmp, newinfo);	if (ret != 0)		goto free_counterstmp;	t = find_table_lock(tmp.name, &ret, &ebt_mutex);	if (!t) {		ret = -ENOENT;		goto free_iterate;	}	/* the table doesn't like it */	if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))		goto free_unlock;	if (tmp.num_counters && tmp.num_counters != t->private->nentries) {		BUGPRINT("Wrong nr. of counters requested\n");		ret = -EINVAL;		goto free_unlock;	}	/* we have the mutex lock, so no danger in reading this pointer */	table = t->private;	/* make sure the table can only be rmmod'ed if it contains no rules */	if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) {		ret = -ENOENT;		goto free_unlock;	} else if (table->nentries && !newinfo->nentries)		module_put(t->me);	/* we need an atomic snapshot of the counters */	write_lock_bh(&t->lock);	if (tmp.num_counters)		get_counters(t->private->counters, counterstmp,		   t->private->nentries);	t->private = newinfo;	write_unlock_bh(&t->lock);	up(&ebt_mutex);	/* so, a user can change the chains while having messed up her counter	   allocation. Only reason why this is done is because this way the lock	   is held only once, while this doesn't bring the kernel into a	   dangerous state. */	if (tmp.num_counters &&	   copy_to_user(tmp.counters, counterstmp,	   tmp.num_counters * sizeof(struct ebt_counter))) {		BUGPRINT("Couldn't copy counters to userspace\n");		ret = -EFAULT;	}	else		ret = 0;	/* decrease module count and free resources */	EBT_ENTRY_ITERATE(table->entries, table->entries_size,	   ebt_cleanup_entry, NULL);	vfree(table->entries);	if (table->chainstack) {		for (i = 0; i < num_possible_cpus(); i++)			vfree(table->chainstack[i]);		vfree(table->chainstack);	}	vfree(table);	vfree(counterstmp);	return ret;free_unlock:	up(&ebt_mutex);free_iterate:	EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,	   ebt_cleanup_entry, NULL);free_counterstmp:	vfree(counterstmp);	/* can be initialized in translate_table() */	if (newinfo->chainstack) {		for (i = 0; i < num_possible_cpus(); i++)			vfree(newinfo->chainstack[i]);		vfree(newinfo->chainstack);	}free_entries:	vfree(newinfo->entries);free_newinfo:	vfree(newinfo);	return ret;}
10457	/local/tlutelli/issta_data/temp/c/2005_temp/2005/10457/c8923c6b852d3a97c1faad0566e38fca330375a7/ebtables.c/buggy/net/bridge/netfilter/ebtables.c