ebtables.c 62.1 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8
/*
 *  ebtables
 *
 *  Author:
 *  Bart De Schuymer		<bdschuym@pandora.be>
 *
 *  ebtables.c,v 2.0, July, 2002
 *
9
 *  This code is strongly inspired by the iptables code which is
Linus Torvalds's avatar
Linus Torvalds committed
10 11 12 13 14 15 16
 *  Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version
 *  2 of the License, or (at your option) any later version.
 */
17
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
Linus Torvalds's avatar
Linus Torvalds committed
18 19 20
#include <linux/kmod.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
21
#include <linux/netfilter/x_tables.h>
Linus Torvalds's avatar
Linus Torvalds committed
22 23
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/spinlock.h>
24
#include <linux/mutex.h>
25
#include <linux/slab.h>
26
#include <linux/uaccess.h>
Linus Torvalds's avatar
Linus Torvalds committed
27
#include <linux/smp.h>
28
#include <linux/cpumask.h>
29
#include <linux/audit.h>
Linus Torvalds's avatar
Linus Torvalds committed
30 31 32 33
#include <net/sock.h>
/* needed for logical [in,out]-dev filtering */
#include "../br_private.h"

34
/* Each cpu has its own set of counters, so there is no need for write_lock in
Linus Torvalds's avatar
Linus Torvalds committed
35 36 37 38 39 40 41 42 43
 * the softirq
 * For reading or updating the counters, the user context needs to
 * get a write_lock
 */

/* The size of each set of counters is altered to get cache alignment */
#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
#define COUNTER_OFFSET(n) (SMP_ALIGN(n * sizeof(struct ebt_counter)))
#define COUNTER_BASE(c, n, cpu) ((struct ebt_counter *)(((char *)c) + \
44
				 COUNTER_OFFSET(n) * cpu))
Linus Torvalds's avatar
Linus Torvalds committed
45 46 47



Ingo Molnar's avatar
Ingo Molnar committed
48
static DEFINE_MUTEX(ebt_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
49

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
#ifdef CONFIG_COMPAT
static void ebt_standard_compat_from_user(void *dst, const void *src)
{
	int v = *(compat_int_t *)src;

	if (v >= 0)
		v += xt_compat_calc_jump(NFPROTO_BRIDGE, v);
	memcpy(dst, &v, sizeof(v));
}

static int ebt_standard_compat_to_user(void __user *dst, const void *src)
{
	compat_int_t cv = *(int *)src;

	if (cv >= 0)
		cv -= xt_compat_calc_jump(NFPROTO_BRIDGE, cv);
	return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
}
#endif


71
static struct xt_target ebt_standard_target = {
72 73 74
	.name       = "standard",
	.revision   = 0,
	.family     = NFPROTO_BRIDGE,
75
	.targetsize = sizeof(int),
76 77 78 79 80
#ifdef CONFIG_COMPAT
	.compatsize = sizeof(compat_int_t),
	.compat_from_user = ebt_standard_compat_from_user,
	.compat_to_user =  ebt_standard_compat_to_user,
#endif
81
};
Linus Torvalds's avatar
Linus Torvalds committed
82

83 84
static inline int
ebt_do_watcher(const struct ebt_entry_watcher *w, struct sk_buff *skb,
85
	       struct xt_action_param *par)
Linus Torvalds's avatar
Linus Torvalds committed
86
{
87 88 89
	par->target   = w->u.watcher;
	par->targinfo = w->data;
	w->u.watcher->target(skb, par);
Linus Torvalds's avatar
Linus Torvalds committed
90 91 92 93
	/* watchers don't give a verdict */
	return 0;
}

94 95 96
static inline int
ebt_do_match(struct ebt_entry_match *m, const struct sk_buff *skb,
	     struct xt_action_param *par)
Linus Torvalds's avatar
Linus Torvalds committed
97
{
98 99
	par->match     = m->u.match;
	par->matchinfo = m->data;
100
	return m->u.match->match(skb, par) ? EBT_MATCH : EBT_NOMATCH;
Linus Torvalds's avatar
Linus Torvalds committed
101 102
}

103 104
static inline int
ebt_dev_check(const char *entry, const struct net_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
105 106
{
	int i = 0;
107
	const char *devname;
Linus Torvalds's avatar
Linus Torvalds committed
108 109 110 111 112

	if (*entry == '\0')
		return 0;
	if (!device)
		return 1;
113
	devname = device->name;
Linus Torvalds's avatar
Linus Torvalds committed
114 115 116
	/* 1 is the wildcard token */
	while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i])
		i++;
117
	return devname[i] != entry[i] && entry[i] != 1;
Linus Torvalds's avatar
Linus Torvalds committed
118 119 120
}

/* process standard matches */
121
static inline int
122
ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb,
123
		const struct net_device *in, const struct net_device *out)
Linus Torvalds's avatar
Linus Torvalds committed
124
{
125
	const struct ethhdr *h = eth_hdr(skb);
126
	const struct net_bridge_port *p;
127
	__be16 ethproto;
Linus Torvalds's avatar
Linus Torvalds committed
128

129
	if (skb_vlan_tag_present(skb))
130 131 132 133
		ethproto = htons(ETH_P_8021Q);
	else
		ethproto = h->h_proto;

Linus Torvalds's avatar
Linus Torvalds committed
134
	if (e->bitmask & EBT_802_3) {
135
		if (NF_INVF(e, EBT_IPROTO, eth_proto_is_802_3(ethproto)))
Linus Torvalds's avatar
Linus Torvalds committed
136 137
			return 1;
	} else if (!(e->bitmask & EBT_NOPROTO) &&
138
		   NF_INVF(e, EBT_IPROTO, e->ethproto != ethproto))
Linus Torvalds's avatar
Linus Torvalds committed
139 140
		return 1;

141
	if (NF_INVF(e, EBT_IIN, ebt_dev_check(e->in, in)))
Linus Torvalds's avatar
Linus Torvalds committed
142
		return 1;
143
	if (NF_INVF(e, EBT_IOUT, ebt_dev_check(e->out, out)))
Linus Torvalds's avatar
Linus Torvalds committed
144
		return 1;
145
	/* rcu_read_lock()ed by nf_hook_thresh */
146
	if (in && (p = br_port_get_rcu(in)) != NULL &&
147 148
	    NF_INVF(e, EBT_ILOGICALIN,
		    ebt_dev_check(e->logical_in, p->br->dev)))
Linus Torvalds's avatar
Linus Torvalds committed
149
		return 1;
150
	if (out && (p = br_port_get_rcu(out)) != NULL &&
151 152
	    NF_INVF(e, EBT_ILOGICALOUT,
		    ebt_dev_check(e->logical_out, p->br->dev)))
Linus Torvalds's avatar
Linus Torvalds committed
153 154 155
		return 1;

	if (e->bitmask & EBT_SOURCEMAC) {
156 157 158
		if (NF_INVF(e, EBT_ISOURCE,
			    !ether_addr_equal_masked(h->h_source, e->sourcemac,
						     e->sourcemsk)))
Linus Torvalds's avatar
Linus Torvalds committed
159 160 161
			return 1;
	}
	if (e->bitmask & EBT_DESTMAC) {
162 163 164
		if (NF_INVF(e, EBT_IDEST,
			    !ether_addr_equal_masked(h->h_dest, e->destmac,
						     e->destmsk)))
Linus Torvalds's avatar
Linus Torvalds committed
165 166 167 168 169
			return 1;
	}
	return 0;
}

170
static inline
171 172 173 174 175
struct ebt_entry *ebt_next_entry(const struct ebt_entry *entry)
{
	return (void *)entry + entry->next_offset;
}

Linus Torvalds's avatar
Linus Torvalds committed
176
/* Do some firewalling */
177 178 179
unsigned int ebt_do_table(struct sk_buff *skb,
			  const struct nf_hook_state *state,
			  struct ebt_table *table)
Linus Torvalds's avatar
Linus Torvalds committed
180
{
181
	unsigned int hook = state->hook;
Linus Torvalds's avatar
Linus Torvalds committed
182 183 184
	int i, nentries;
	struct ebt_entry *point;
	struct ebt_counter *counter_base, *cb_base;
185
	const struct ebt_entry_target *t;
Linus Torvalds's avatar
Linus Torvalds committed
186 187 188
	int verdict, sp = 0;
	struct ebt_chainstack *cs;
	struct ebt_entries *chaininfo;
189 190
	const char *base;
	const struct ebt_table_info *private;
191
	struct xt_action_param acpar;
192

193
	acpar.state   = state;
194
	acpar.hotdrop = false;
Linus Torvalds's avatar
Linus Torvalds committed
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211

	read_lock_bh(&table->lock);
	private = table->private;
	cb_base = COUNTER_BASE(private->counters, private->nentries,
	   smp_processor_id());
	if (private->chainstack)
		cs = private->chainstack[smp_processor_id()];
	else
		cs = NULL;
	chaininfo = private->hook_entry[hook];
	nentries = private->hook_entry[hook]->nentries;
	point = (struct ebt_entry *)(private->hook_entry[hook]->data);
	counter_base = cb_base + private->hook_entry[hook]->counter_offset;
	/* base for chain jumps */
	base = private->entries;
	i = 0;
	while (i < nentries) {
212
		if (ebt_basic_match(point, skb, state->in, state->out))
Linus Torvalds's avatar
Linus Torvalds committed
213 214
			goto letscontinue;

215
		if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, &acpar) != 0)
Linus Torvalds's avatar
Linus Torvalds committed
216
			goto letscontinue;
217
		if (acpar.hotdrop) {
218 219 220
			read_unlock_bh(&table->lock);
			return NF_DROP;
		}
Linus Torvalds's avatar
Linus Torvalds committed
221 222 223

		/* increase counter */
		(*(counter_base + i)).pcnt++;
224
		(*(counter_base + i)).bcnt += skb->len;
Linus Torvalds's avatar
Linus Torvalds committed
225 226

		/* these should only watch: not modify, nor tell us
227 228
		 * what to do with the packet
		 */
229
		EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, &acpar);
Linus Torvalds's avatar
Linus Torvalds committed
230 231 232 233 234 235

		t = (struct ebt_entry_target *)
		   (((char *)point) + point->target_offset);
		/* standard target */
		if (!t->u.target->target)
			verdict = ((struct ebt_standard_target *)t)->verdict;
236
		else {
237 238 239
			acpar.target   = t->u.target;
			acpar.targinfo = t->data;
			verdict = t->u.target->target(skb, &acpar);
240
		}
Linus Torvalds's avatar
Linus Torvalds committed
241 242 243 244 245 246 247 248 249 250
		if (verdict == EBT_ACCEPT) {
			read_unlock_bh(&table->lock);
			return NF_ACCEPT;
		}
		if (verdict == EBT_DROP) {
			read_unlock_bh(&table->lock);
			return NF_DROP;
		}
		if (verdict == EBT_RETURN) {
letsreturn:
251
			if (WARN(sp == 0, "RETURN on base chain")) {
Linus Torvalds's avatar
Linus Torvalds committed
252 253 254
				/* act like this is EBT_CONTINUE */
				goto letscontinue;
			}
255

Linus Torvalds's avatar
Linus Torvalds committed
256 257 258 259 260 261 262 263 264 265 266 267
			sp--;
			/* put all the local variables right */
			i = cs[sp].n;
			chaininfo = cs[sp].chaininfo;
			nentries = chaininfo->nentries;
			point = cs[sp].e;
			counter_base = cb_base +
			   chaininfo->counter_offset;
			continue;
		}
		if (verdict == EBT_CONTINUE)
			goto letscontinue;
268 269

		if (WARN(verdict < 0, "bogus standard verdict\n")) {
Linus Torvalds's avatar
Linus Torvalds committed
270 271 272
			read_unlock_bh(&table->lock);
			return NF_DROP;
		}
273

Linus Torvalds's avatar
Linus Torvalds committed
274 275 276
		/* jump to a udc */
		cs[sp].n = i + 1;
		cs[sp].chaininfo = chaininfo;
277
		cs[sp].e = ebt_next_entry(point);
Linus Torvalds's avatar
Linus Torvalds committed
278 279
		i = 0;
		chaininfo = (struct ebt_entries *) (base + verdict);
280 281

		if (WARN(chaininfo->distinguisher, "jump to non-chain\n")) {
Linus Torvalds's avatar
Linus Torvalds committed
282 283 284
			read_unlock_bh(&table->lock);
			return NF_DROP;
		}
285

Linus Torvalds's avatar
Linus Torvalds committed
286 287 288 289 290 291
		nentries = chaininfo->nentries;
		point = (struct ebt_entry *)chaininfo->data;
		counter_base = cb_base + chaininfo->counter_offset;
		sp++;
		continue;
letscontinue:
292
		point = ebt_next_entry(point);
Linus Torvalds's avatar
Linus Torvalds committed
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
		i++;
	}

	/* I actually like this :) */
	if (chaininfo->policy == EBT_RETURN)
		goto letsreturn;
	if (chaininfo->policy == EBT_ACCEPT) {
		read_unlock_bh(&table->lock);
		return NF_ACCEPT;
	}
	read_unlock_bh(&table->lock);
	return NF_DROP;
}

/* If it succeeds, returns element and locks mutex */
static inline void *
find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
310
			struct mutex *mutex)
Linus Torvalds's avatar
Linus Torvalds committed
311
{
312 313 314 315
	struct {
		struct list_head list;
		char name[EBT_FUNCTION_MAXNAMELEN];
	} *e;
Linus Torvalds's avatar
Linus Torvalds committed
316

317
	mutex_lock(mutex);
318 319 320
	list_for_each_entry(e, head, list) {
		if (strcmp(e->name, name) == 0)
			return e;
Linus Torvalds's avatar
Linus Torvalds committed
321
	}
322 323 324
	*error = -ENOENT;
	mutex_unlock(mutex);
	return NULL;
Linus Torvalds's avatar
Linus Torvalds committed
325 326 327 328
}

static void *
find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
329
		 int *error, struct mutex *mutex)
Linus Torvalds's avatar
Linus Torvalds committed
330
{
331 332 333
	return try_then_request_module(
			find_inlist_lock_noload(head, name, error, mutex),
			"%s%s", prefix, name);
Linus Torvalds's avatar
Linus Torvalds committed
334 335 336
}

static inline struct ebt_table *
337 338
find_table_lock(struct net *net, const char *name, int *error,
		struct mutex *mutex)
Linus Torvalds's avatar
Linus Torvalds committed
339
{
340 341
	return find_inlist_lock(&net->xt.tables[NFPROTO_BRIDGE], name,
				"ebtable_", error, mutex);
Linus Torvalds's avatar
Linus Torvalds committed
342 343 344
}

static inline int
345 346
ebt_check_match(struct ebt_entry_match *m, struct xt_mtchk_param *par,
		unsigned int *cnt)
Linus Torvalds's avatar
Linus Torvalds committed
347
{
348
	const struct ebt_entry *e = par->entryinfo;
349
	struct xt_match *match;
350
	size_t left = ((char *)e + e->watchers_offset) - (char *)m;
Linus Torvalds's avatar
Linus Torvalds committed
351 352
	int ret;

353 354
	if (left < sizeof(struct ebt_entry_match) ||
	    left - sizeof(struct ebt_entry_match) < m->match_size)
Linus Torvalds's avatar
Linus Torvalds committed
355
		return -EINVAL;
356

357 358
	match = xt_find_match(NFPROTO_BRIDGE, m->u.name, 0);
	if (IS_ERR(match) || match->family != NFPROTO_BRIDGE) {
359 360
		if (!IS_ERR(match))
			module_put(match->me);
361 362 363
		request_module("ebt_%s", m->u.name);
		match = xt_find_match(NFPROTO_BRIDGE, m->u.name, 0);
	}
364 365 366 367
	if (IS_ERR(match))
		return PTR_ERR(match);
	m->u.match = match;

368 369
	par->match     = match;
	par->matchinfo = m->data;
370
	ret = xt_check_match(par, m->match_size,
371
	      e->ethproto, e->invflags & EBT_IPROTO);
372 373 374
	if (ret < 0) {
		module_put(match->me);
		return ret;
Linus Torvalds's avatar
Linus Torvalds committed
375
	}
376

Linus Torvalds's avatar
Linus Torvalds committed
377 378 379 380 381
	(*cnt)++;
	return 0;
}

static inline int
382 383
ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
		  unsigned int *cnt)
Linus Torvalds's avatar
Linus Torvalds committed
384
{
385
	const struct ebt_entry *e = par->entryinfo;
386
	struct xt_target *watcher;
387
	size_t left = ((char *)e + e->target_offset) - (char *)w;
Linus Torvalds's avatar
Linus Torvalds committed
388 389
	int ret;

390 391
	if (left < sizeof(struct ebt_entry_watcher) ||
	   left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
Linus Torvalds's avatar
Linus Torvalds committed
392
		return -EINVAL;
393

394
	watcher = xt_request_find_target(NFPROTO_BRIDGE, w->u.name, 0);
395 396
	if (IS_ERR(watcher))
		return PTR_ERR(watcher);
397 398 399 400 401 402

	if (watcher->family != NFPROTO_BRIDGE) {
		module_put(watcher->me);
		return -ENOENT;
	}

403 404
	w->u.watcher = watcher;

405 406
	par->target   = watcher;
	par->targinfo = w->data;
407
	ret = xt_check_target(par, w->watcher_size,
408
	      e->ethproto, e->invflags & EBT_IPROTO);
409 410 411
	if (ret < 0) {
		module_put(watcher->me);
		return ret;
Linus Torvalds's avatar
Linus Torvalds committed
412
	}
413

Linus Torvalds's avatar
Linus Torvalds committed
414 415 416 417
	(*cnt)++;
	return 0;
}

418
static int ebt_verify_pointers(const struct ebt_replace *repl,
419
			       struct ebt_table_info *newinfo)
Linus Torvalds's avatar
Linus Torvalds committed
420
{
421 422 423
	unsigned int limit = repl->entries_size;
	unsigned int valid_hooks = repl->valid_hooks;
	unsigned int offset = 0;
Linus Torvalds's avatar
Linus Torvalds committed
424 425
	int i;

426 427 428 429 430 431
	for (i = 0; i < NF_BR_NUMHOOKS; i++)
		newinfo->hook_entry[i] = NULL;

	newinfo->entries_size = repl->entries_size;
	newinfo->nentries = repl->nentries;

432 433 434
	while (offset < limit) {
		size_t left = limit - offset;
		struct ebt_entry *e = (void *)newinfo->entries + offset;
435

436
		if (left < sizeof(unsigned int))
Linus Torvalds's avatar
Linus Torvalds committed
437
			break;
438 439 440 441

		for (i = 0; i < NF_BR_NUMHOOKS; i++) {
			if ((valid_hooks & (1 << i)) == 0)
				continue;
442 443
			if ((char __user *)repl->hook_entry[i] ==
			     repl->entries + offset)
444 445 446 447 448 449
				break;
		}

		if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
			if (e->bitmask != 0) {
				/* we make userspace set this right,
450 451
				 * so there is no misunderstanding
				 */
452 453 454 455 456 457 458 459 460 461 462 463
				return -EINVAL;
			}
			if (i != NF_BR_NUMHOOKS)
				newinfo->hook_entry[i] = (struct ebt_entries *)e;
			if (left < sizeof(struct ebt_entries))
				break;
			offset += sizeof(struct ebt_entries);
		} else {
			if (left < sizeof(struct ebt_entry))
				break;
			if (left < e->next_offset)
				break;
464 465
			if (e->next_offset < sizeof(struct ebt_entry))
				return -EINVAL;
466
			offset += e->next_offset;
Linus Torvalds's avatar
Linus Torvalds committed
467
		}
468
	}
469
	if (offset != limit)
470
		return -EINVAL;
471 472 473 474

	/* check if all valid hooks have a chain */
	for (i = 0; i < NF_BR_NUMHOOKS; i++) {
		if (!newinfo->hook_entry[i] &&
475
		   (valid_hooks & (1 << i)))
476 477
			return -EINVAL;
	}
478 479 480
	return 0;
}

481
/* this one is very careful, as it is the first function
482 483 484
 * to parse the userspace data
 */
static inline int
485
ebt_check_entry_size_and_hooks(const struct ebt_entry *e,
486 487 488
			       const struct ebt_table_info *newinfo,
			       unsigned int *n, unsigned int *cnt,
			       unsigned int *totalcnt, unsigned int *udc_cnt)
489 490 491 492
{
	int i;

	for (i = 0; i < NF_BR_NUMHOOKS; i++) {
493
		if ((void *)e == (void *)newinfo->hook_entry[i])
494 495 496
			break;
	}
	/* beginning of a new chain
497 498
	 * if i == NF_BR_NUMHOOKS it must be a user defined chain
	 */
499
	if (i != NF_BR_NUMHOOKS || !e->bitmask) {
Linus Torvalds's avatar
Linus Torvalds committed
500
		/* this checks if the previous chain has as many entries
501 502
		 * as it said it has
		 */
503
		if (*n != *cnt)
Linus Torvalds's avatar
Linus Torvalds committed
504
			return -EINVAL;
505

Linus Torvalds's avatar
Linus Torvalds committed
506 507 508 509
		if (((struct ebt_entries *)e)->policy != EBT_DROP &&
		   ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
			/* only RETURN from udc */
			if (i != NF_BR_NUMHOOKS ||
510
			   ((struct ebt_entries *)e)->policy != EBT_RETURN)
Linus Torvalds's avatar
Linus Torvalds committed
511 512 513 514
				return -EINVAL;
		}
		if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
			(*udc_cnt)++;
515
		if (((struct ebt_entries *)e)->counter_offset != *totalcnt)
Linus Torvalds's avatar
Linus Torvalds committed
516 517 518 519 520 521 522 523
			return -EINVAL;
		*n = ((struct ebt_entries *)e)->nentries;
		*cnt = 0;
		return 0;
	}
	/* a plain old entry, heh */
	if (sizeof(struct ebt_entry) > e->watchers_offset ||
	   e->watchers_offset > e->target_offset ||
524
	   e->target_offset >= e->next_offset)
Linus Torvalds's avatar
Linus Torvalds committed
525
		return -EINVAL;
526

Linus Torvalds's avatar
Linus Torvalds committed
527
	/* this is not checked anywhere else */
528
	if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target))
Linus Torvalds's avatar
Linus Torvalds committed
529
		return -EINVAL;
530

Linus Torvalds's avatar
Linus Torvalds committed
531 532 533 534 535
	(*cnt)++;
	(*totalcnt)++;
	return 0;
}

536
struct ebt_cl_stack {
Linus Torvalds's avatar
Linus Torvalds committed
537 538 539 540 541
	struct ebt_chainstack cs;
	int from;
	unsigned int hookmask;
};

542
/* We need these positions to check that the jumps to a different part of the
Linus Torvalds's avatar
Linus Torvalds committed
543 544 545 546
 * entries is a jump to the beginning of a new chain.
 */
static inline int
ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
547
		      unsigned int *n, struct ebt_cl_stack *udc)
Linus Torvalds's avatar
Linus Torvalds committed
548 549 550 551
{
	int i;

	/* we're only interested in chain starts */
552
	if (e->bitmask)
Linus Torvalds's avatar
Linus Torvalds committed
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
		return 0;
	for (i = 0; i < NF_BR_NUMHOOKS; i++) {
		if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
			break;
	}
	/* only care about udc */
	if (i != NF_BR_NUMHOOKS)
		return 0;

	udc[*n].cs.chaininfo = (struct ebt_entries *)e;
	/* these initialisations are depended on later in check_chainloops() */
	udc[*n].cs.n = 0;
	udc[*n].hookmask = 0;

	(*n)++;
	return 0;
}

static inline int
572
ebt_cleanup_match(struct ebt_entry_match *m, struct net *net, unsigned int *i)
Linus Torvalds's avatar
Linus Torvalds committed
573
{
574 575
	struct xt_mtdtor_param par;

Linus Torvalds's avatar
Linus Torvalds committed
576 577 578
	if (i && (*i)-- == 0)
		return 1;

579
	par.net       = net;
580 581
	par.match     = m->u.match;
	par.matchinfo = m->data;
582
	par.family    = NFPROTO_BRIDGE;
583 584 585
	if (par.match->destroy != NULL)
		par.match->destroy(&par);
	module_put(par.match->me);
Linus Torvalds's avatar
Linus Torvalds committed
586 587 588 589
	return 0;
}

static inline int
590
ebt_cleanup_watcher(struct ebt_entry_watcher *w, struct net *net, unsigned int *i)
Linus Torvalds's avatar
Linus Torvalds committed
591
{
592 593
	struct xt_tgdtor_param par;

Linus Torvalds's avatar
Linus Torvalds committed
594 595 596
	if (i && (*i)-- == 0)
		return 1;

597
	par.net      = net;
598 599
	par.target   = w->u.watcher;
	par.targinfo = w->data;
600
	par.family   = NFPROTO_BRIDGE;
601 602 603
	if (par.target->destroy != NULL)
		par.target->destroy(&par);
	module_put(par.target->me);
Linus Torvalds's avatar
Linus Torvalds committed
604 605 606 607
	return 0;
}

static inline int
608
ebt_cleanup_entry(struct ebt_entry *e, struct net *net, unsigned int *cnt)
Linus Torvalds's avatar
Linus Torvalds committed
609
{
610
	struct xt_tgdtor_param par;
Linus Torvalds's avatar
Linus Torvalds committed
611 612
	struct ebt_entry_target *t;

613
	if (e->bitmask == 0)
Linus Torvalds's avatar
Linus Torvalds committed
614 615 616 617
		return 0;
	/* we're done */
	if (cnt && (*cnt)-- == 0)
		return 1;
618
	EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, net, NULL);
619
	EBT_MATCH_ITERATE(e, ebt_cleanup_match, net, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
620 621
	t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);

622
	par.net      = net;
623 624
	par.target   = t->u.target;
	par.targinfo = t->data;
625
	par.family   = NFPROTO_BRIDGE;
626 627 628
	if (par.target->destroy != NULL)
		par.target->destroy(&par);
	module_put(par.target->me);
Linus Torvalds's avatar
Linus Torvalds committed
629 630 631 632
	return 0;
}

static inline int
633
ebt_check_entry(struct ebt_entry *e, struct net *net,
634 635 636
		const struct ebt_table_info *newinfo,
		const char *name, unsigned int *cnt,
		struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
Linus Torvalds's avatar
Linus Torvalds committed
637 638
{
	struct ebt_entry_target *t;
639
	struct xt_target *target;
Linus Torvalds's avatar
Linus Torvalds committed
640
	unsigned int i, j, hook = 0, hookmask = 0;
641
	size_t gap;
Linus Torvalds's avatar
Linus Torvalds committed
642
	int ret;
643
	struct xt_mtchk_param mtpar;
644
	struct xt_tgchk_param tgpar;
Linus Torvalds's avatar
Linus Torvalds committed
645 646

	/* don't mess with the struct ebt_entries */
647
	if (e->bitmask == 0)
Linus Torvalds's avatar
Linus Torvalds committed
648 649
		return 0;

650
	if (e->bitmask & ~EBT_F_MASK)
Linus Torvalds's avatar
Linus Torvalds committed
651
		return -EINVAL;
652 653

	if (e->invflags & ~EBT_INV_MASK)
Linus Torvalds's avatar
Linus Torvalds committed
654
		return -EINVAL;
655 656

	if ((e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3))
Linus Torvalds's avatar
Linus Torvalds committed
657
		return -EINVAL;
658

Linus Torvalds's avatar
Linus Torvalds committed
659 660
	/* what hook do we belong to? */
	for (i = 0; i < NF_BR_NUMHOOKS; i++) {
661
		if (!newinfo->hook_entry[i])
Linus Torvalds's avatar
Linus Torvalds committed
662 663 664 665 666 667 668
			continue;
		if ((char *)newinfo->hook_entry[i] < (char *)e)
			hook = i;
		else
			break;
	}
	/* (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
669 670
	 * a base chain
	 */
Linus Torvalds's avatar
Linus Torvalds committed
671 672 673 674 675 676 677 678 679 680 681 682
	if (i < NF_BR_NUMHOOKS)
		hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
	else {
		for (i = 0; i < udc_cnt; i++)
			if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
				break;
		if (i == 0)
			hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
		else
			hookmask = cl_s[i - 1].hookmask;
	}
	i = 0;
683

684 685
	memset(&mtpar, 0, sizeof(mtpar));
	memset(&tgpar, 0, sizeof(tgpar));
686
	mtpar.net	= tgpar.net       = net;
687 688 689
	mtpar.table     = tgpar.table     = name;
	mtpar.entryinfo = tgpar.entryinfo = e;
	mtpar.hook_mask = tgpar.hook_mask = hookmask;
690
	mtpar.family    = tgpar.family    = NFPROTO_BRIDGE;
691
	ret = EBT_MATCH_ITERATE(e, ebt_check_match, &mtpar, &i);
Linus Torvalds's avatar
Linus Torvalds committed
692 693 694
	if (ret != 0)
		goto cleanup_matches;
	j = 0;
695
	ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, &tgpar, &j);
Linus Torvalds's avatar
Linus Torvalds committed
696 697 698
	if (ret != 0)
		goto cleanup_watchers;
	t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
699
	gap = e->next_offset - e->target_offset;
Linus Torvalds's avatar
Linus Torvalds committed
700

701
	target = xt_request_find_target(NFPROTO_BRIDGE, t->u.name, 0);
702 703
	if (IS_ERR(target)) {
		ret = PTR_ERR(target);
704 705 706
		goto cleanup_watchers;
	}

707 708 709 710 711 712 713
	/* Reject UNSPEC, xtables verdicts/return values are incompatible */
	if (target->family != NFPROTO_BRIDGE) {
		module_put(target->me);
		ret = -ENOENT;
		goto cleanup_watchers;
	}

Linus Torvalds's avatar
Linus Torvalds committed
714 715
	t->u.target = target;
	if (t->u.target == &ebt_standard_target) {
716
		if (gap < sizeof(struct ebt_standard_target)) {
Linus Torvalds's avatar
Linus Torvalds committed
717 718 719 720 721 722 723 724
			ret = -EFAULT;
			goto cleanup_watchers;
		}
		if (((struct ebt_standard_target *)t)->verdict <
		   -NUM_STANDARD_TARGETS) {
			ret = -EFAULT;
			goto cleanup_watchers;
		}
725 726 727 728
	} else if (t->target_size > gap - sizeof(struct ebt_entry_target)) {
		module_put(t->u.target->me);
		ret = -EFAULT;
		goto cleanup_watchers;
729 730
	}

731 732
	tgpar.target   = target;
	tgpar.targinfo = t->data;
733
	ret = xt_check_target(&tgpar, t->target_size,
734
	      e->ethproto, e->invflags & EBT_IPROTO);
735 736
	if (ret < 0) {
		module_put(target->me);
737
		goto cleanup_watchers;
Linus Torvalds's avatar
Linus Torvalds committed
738 739 740 741
	}
	(*cnt)++;
	return 0;
cleanup_watchers:
742
	EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, net, &j);
Linus Torvalds's avatar
Linus Torvalds committed
743
cleanup_matches:
744
	EBT_MATCH_ITERATE(e, ebt_cleanup_match, net, &i);
Linus Torvalds's avatar
Linus Torvalds committed
745 746 747
	return ret;
}

748
/* checks for loops and sets the hook mask for udc
Linus Torvalds's avatar
Linus Torvalds committed
749 750 751
 * the hook mask for udc tells us from which base chains the udc can be
 * accessed. This mask is a parameter to the check() functions of the extensions
 */
752
static int check_chainloops(const struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
753
			    unsigned int udc_cnt, unsigned int hooknr, char *base)
Linus Torvalds's avatar
Linus Torvalds committed
754 755
{
	int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
756 757
	const struct ebt_entry *e = (struct ebt_entry *)chain->data;
	const struct ebt_entry_target *t;
Linus Torvalds's avatar
Linus Torvalds committed
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780

	while (pos < nentries || chain_nr != -1) {
		/* end of udc, go back one 'recursion' step */
		if (pos == nentries) {
			/* put back values of the time when this chain was called */
			e = cl_s[chain_nr].cs.e;
			if (cl_s[chain_nr].from != -1)
				nentries =
				cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
			else
				nentries = chain->nentries;
			pos = cl_s[chain_nr].cs.n;
			/* make sure we won't see a loop that isn't one */
			cl_s[chain_nr].cs.n = 0;
			chain_nr = cl_s[chain_nr].from;
			if (pos == nentries)
				continue;
		}
		t = (struct ebt_entry_target *)
		   (((char *)e) + e->target_offset);
		if (strcmp(t->u.name, EBT_STANDARD_TARGET))
			goto letscontinue;
		if (e->target_offset + sizeof(struct ebt_standard_target) >
781
		   e->next_offset)
Linus Torvalds's avatar
Linus Torvalds committed
782
			return -1;
783

Linus Torvalds's avatar
Linus Torvalds committed
784 785 786 787 788 789 790 791
		verdict = ((struct ebt_standard_target *)t)->verdict;
		if (verdict >= 0) { /* jump to another chain */
			struct ebt_entries *hlp2 =
			   (struct ebt_entries *)(base + verdict);
			for (i = 0; i < udc_cnt; i++)
				if (hlp2 == cl_s[i].cs.chaininfo)
					break;
			/* bad destination or loop */
792
			if (i == udc_cnt)
Linus Torvalds's avatar
Linus Torvalds committed
793
				return -1;
794 795

			if (cl_s[i].cs.n)
Linus Torvalds's avatar
Linus Torvalds committed
796
				return -1;
797

798 799 800
			if (cl_s[i].hookmask & (1 << hooknr))
				goto letscontinue;
			/* this can't be 0, so the loop test is correct */
Linus Torvalds's avatar
Linus Torvalds committed
801 802
			cl_s[i].cs.n = pos + 1;
			pos = 0;
803
			cl_s[i].cs.e = ebt_next_entry(e);
Linus Torvalds's avatar
Linus Torvalds committed
804 805 806 807 808 809 810 811 812
			e = (struct ebt_entry *)(hlp2->data);
			nentries = hlp2->nentries;
			cl_s[i].from = chain_nr;
			chain_nr = i;
			/* this udc is accessible from the base chain for hooknr */
			cl_s[i].hookmask |= (1 << hooknr);
			continue;
		}
letscontinue:
813
		e = ebt_next_entry(e);
Linus Torvalds's avatar
Linus Torvalds committed
814 815 816 817 818 819
		pos++;
	}
	return 0;
}

/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
820
static int translate_table(struct net *net, const char *name,
821
			   struct ebt_table_info *newinfo)
Linus Torvalds's avatar
Linus Torvalds committed
822 823 824 825 826 827
{
	unsigned int i, j, k, udc_cnt;
	int ret;
	struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */

	i = 0;
828
	while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
Linus Torvalds's avatar
Linus Torvalds committed
829
		i++;
830
	if (i == NF_BR_NUMHOOKS)
Linus Torvalds's avatar
Linus Torvalds committed
831
		return -EINVAL;
832 833

	if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries)
Linus Torvalds's avatar
Linus Torvalds committed
834
		return -EINVAL;
835

Linus Torvalds's avatar
Linus Torvalds committed
836
	/* make sure chains are ordered after each other in same order
837 838
	 * as their corresponding hooks
	 */
Linus Torvalds's avatar
Linus Torvalds committed
839
	for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
840
		if (!newinfo->hook_entry[j])
Linus Torvalds's avatar
Linus Torvalds committed
841
			continue;
842
		if (newinfo->hook_entry[j] <= newinfo->hook_entry[i])
Linus Torvalds's avatar
Linus Torvalds committed
843
			return -EINVAL;
844

Linus Torvalds's avatar
Linus Torvalds committed
845 846 847 848 849 850 851
		i = j;
	}

	/* do some early checkings and initialize some things */
	i = 0; /* holds the expected nr. of entries for the chain */
	j = 0; /* holds the up to now counted entries for the chain */
	k = 0; /* holds the total nr. of entries, should equal
852 853
		* newinfo->nentries afterwards
		*/
Linus Torvalds's avatar
Linus Torvalds committed
854 855
	udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
	ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
856 857
	   ebt_check_entry_size_and_hooks, newinfo,
	   &i, &j, &k, &udc_cnt);
Linus Torvalds's avatar
Linus Torvalds committed
858 859 860 861

	if (ret != 0)
		return ret;

862
	if (i != j)
Linus Torvalds's avatar
Linus Torvalds committed
863
		return -EINVAL;
864 865

	if (k != newinfo->nentries)
Linus Torvalds's avatar
Linus Torvalds committed
866 867 868
		return -EINVAL;

	/* get the location of the udc, put them in an array
869 870
	 * while we're at it, allocate the chainstack
	 */
Linus Torvalds's avatar
Linus Torvalds committed
871 872
	if (udc_cnt) {
		/* this will get free'd in do_replace()/ebt_register_table()
873 874
		 * if an error occurs
		 */
875
		newinfo->chainstack =
876
			vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack)));
Linus Torvalds's avatar
Linus Torvalds committed
877 878
		if (!newinfo->chainstack)
			return -ENOMEM;
879
		for_each_possible_cpu(i) {
Linus Torvalds's avatar
Linus Torvalds committed
880
			newinfo->chainstack[i] =
881
			  vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
Linus Torvalds's avatar
Linus Torvalds committed
882 883 884 885 886 887 888 889 890
			if (!newinfo->chainstack[i]) {
				while (i)
					vfree(newinfo->chainstack[--i]);
				vfree(newinfo->chainstack);
				newinfo->chainstack = NULL;
				return -ENOMEM;
			}
		}

891
		cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
Linus Torvalds's avatar
Linus Torvalds committed
892 893 894 895
		if (!cl_s)
			return -ENOMEM;
		i = 0; /* the i'th udc */
		EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
896
		   ebt_get_udc_positions, newinfo, &i, cl_s);
Linus Torvalds's avatar
Linus Torvalds committed
897 898 899 900 901 902 903 904 905
		/* sanity check */
		if (i != udc_cnt) {
			vfree(cl_s);
			return -EFAULT;
		}
	}

	/* Check for loops */
	for (i = 0; i < NF_BR_NUMHOOKS; i++)
906
		if (newinfo->hook_entry[i])
Linus Torvalds's avatar
Linus Torvalds committed
907 908
			if (check_chainloops(newinfo->hook_entry[i],
			   cl_s, udc_cnt, i, newinfo->entries)) {
909
				vfree(cl_s);
Linus Torvalds's avatar
Linus Torvalds committed
910 911 912
				return -EINVAL;
			}

913
	/* we now know the following (along with E=mc²):
914 915 916 917 918 919 920 921 922
	 *  - the nr of entries in each chain is right
	 *  - the size of the allocated space is right
	 *  - all valid hooks have a corresponding chain
	 *  - there are no loops
	 *  - wrong data can still be on the level of a single entry
	 *  - could be there are jumps to places that are not the
	 *    beginning of a chain. This can only occur in chains that
	 *    are not accessible from any base chains, so we don't care.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
923 924 925 926

	/* used to know what we need to clean up if something goes wrong */
	i = 0;
	ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
927
	   ebt_check_entry, net, newinfo, name, &i, cl_s, udc_cnt);
Linus Torvalds's avatar
Linus Torvalds committed
928 929
	if (ret != 0) {
		EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
930
				  ebt_cleanup_entry, net, &i);
Linus Torvalds's avatar
Linus Torvalds committed
931
	}
932
	vfree(cl_s);
Linus Torvalds's avatar
Linus Torvalds committed
933 934 935 936
	return ret;
}

/* called under write_lock */
937
static void get_counters(const struct ebt_counter *oldcounters,
938
			 struct ebt_counter *counters, unsigned int nentries)
Linus Torvalds's avatar
Linus Torvalds committed
939 940 941 942 943 944
{
	int i, cpu;
	struct ebt_counter *counter_base;

	/* counters of cpu 0 */
	memcpy(counters, oldcounters,
945 946
	       sizeof(struct ebt_counter) * nentries);

Linus Torvalds's avatar
Linus Torvalds committed
947
	/* add other counters to those of cpu 0 */
948
	for_each_possible_cpu(cpu) {
949 950
		if (cpu == 0)
			continue;
Linus Torvalds's avatar
Linus Torvalds committed
951 952 953 954 955 956 957 958
		counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
		for (i = 0; i < nentries; i++) {
			counters[i].pcnt += counter_base[i].pcnt;
			counters[i].bcnt += counter_base[i].bcnt;
		}
	}
}

959 960
static int do_replace_finish(struct net *net, struct ebt_replace *repl,
			      struct ebt_table_info *newinfo)
Linus Torvalds's avatar
Linus Torvalds committed
961
{
962
	int ret, i;
Linus Torvalds's avatar
Linus Torvalds committed
963 964 965
	struct ebt_counter *counterstmp = NULL;
	/* used to be able to unlock earlier */
	struct ebt_table_info *table;
966
	struct ebt_table *t;
Linus Torvalds's avatar
Linus Torvalds committed
967 968

	/* the user wants counters back
969 970
	 * the check on the size is done later, when we have the lock
	 */
971 972 973 974 975
	if (repl->num_counters) {
		unsigned long size = repl->num_counters * sizeof(*counterstmp);
		counterstmp = vmalloc(size);
		if (!counterstmp)
			return -ENOMEM;
Linus Torvalds's avatar
Linus Torvalds committed
976 977 978
	}

	newinfo->chainstack = NULL;
979
	ret = ebt_verify_pointers(repl, newinfo);
980 981 982
	if (ret != 0)
		goto free_counterstmp;

983
	ret = translate_table(net, repl->name, newinfo);
Linus Torvalds's avatar
Linus Torvalds committed
984 985 986 987

	if (ret != 0)
		goto free_counterstmp;

988
	t = find_table_lock(net, repl->name, &ret, &ebt_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
989 990 991 992 993 994
	if (!t) {
		ret = -ENOENT;
		goto free_iterate;
	}

	/* the table doesn't like it */
995
	if (t->check && (ret = t->check(newinfo, repl->valid_hooks)))
Linus Torvalds's avatar
Linus Torvalds committed
996 997
		goto free_unlock;

998
	if (repl->num_counters && repl->num_counters != t->private->nentries) {
Linus Torvalds's avatar
Linus Torvalds committed
999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012
		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);
1013
	if (repl->num_counters)
Linus Torvalds's avatar
Linus Torvalds committed
1014 1015 1016 1017 1018
		get_counters(t->private->counters, counterstmp,
		   t->private->nentries);

	t->private = newinfo;
	write_unlock_bh(&t->lock);
Ingo Molnar's avatar
Ingo Molnar committed
1019
	mutex_unlock(&ebt_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
1020
	/* so, a user can change the chains while having messed up her counter
1021 1022 1023 1024
	 * 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.
	 */
1025 1026 1027
	if (repl->num_counters &&
	   copy_to_user(repl->counters, counterstmp,
	   repl->num_counters * sizeof(struct ebt_counter))) {
1028 1029
		/* Silent error, can't fail, new table is already in place */
		net_warn_ratelimited("ebtables: counters copy to user failed while replacing table\n");
Linus Torvalds's avatar
Linus Torvalds committed
1030 1031 1032 1033
	}

	/* decrease module count and free resources */
	EBT_ENTRY_ITERATE(table->entries, table->entries_size,
1034
			  ebt_cleanup_entry, net, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
1035 1036 1037

	vfree(table->entries);
	if (table->chainstack) {
1038
		for_each_possible_cpu(i)
Linus Torvalds's avatar
Linus Torvalds committed
1039 1040 1041 1042 1043
			vfree(table->chainstack[i]);
		vfree(table->chainstack);
	}
	vfree(table);

1044
	vfree(counterstmp);
1045 1046 1047

#ifdef CONFIG_AUDIT
	if (audit_enabled) {
Geliang Tang's avatar
Geliang Tang committed
1048 1049 1050 1051
		audit_log(current->audit_context, GFP_KERNEL,
			  AUDIT_NETFILTER_CFG,
			  "table=%s family=%u entries=%u",
			  repl->name, AF_BRIDGE, repl->nentries);
1052 1053
	}
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1054 1055 1056
	return ret;

free_unlock:
Ingo Molnar's avatar
Ingo Molnar committed
1057
	mutex_unlock(&ebt_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
1058 1059
free_iterate:
	EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
1060
			  ebt_cleanup_entry, net, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
1061
free_counterstmp:
1062
	vfree(counterstmp);
Linus Torvalds's avatar
Linus Torvalds committed
1063 1064
	/* can be initialized in translate_table() */
	if (newinfo->chainstack) {
1065
		for_each_possible_cpu(i)
Linus Torvalds's avatar
Linus Torvalds committed
1066 1067 1068
			vfree(newinfo->chainstack[i]);
		vfree(newinfo->chainstack);
	}
1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082
	return ret;
}

/* replace the table */
static int do_replace(struct net *net, const void __user *user,
		      unsigned int len)
{
	int ret, countersize;
	struct ebt_table_info *newinfo;
	struct ebt_replace tmp;

	if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
		return -EFAULT;

1083
	if (len != sizeof(tmp) + tmp.entries_size)
1084 1085
		return -EINVAL;

1086
	if (tmp.entries_size == 0)
1087
		return -EINVAL;
1088

1089 1090 1091 1092 1093 1094 1095
	/* overflow check */
	if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) /
			NR_CPUS - SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
		return -ENOMEM;
	if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
		return -ENOMEM;

1096 1097
	tmp.name[sizeof(tmp.name) - 1] = 0;

1098
	countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
1099 1100
	newinfo = __vmalloc(sizeof(*newinfo) + countersize, GFP_KERNEL_ACCOUNT,
			    PAGE_KERNEL);
1101 1102 1103 1104 1105 1106
	if (!newinfo)
		return -ENOMEM;

	if (countersize)
		memset(newinfo->counters, 0, countersize);

1107 1108
	newinfo->entries = __vmalloc(tmp.entries_size, GFP_KERNEL_ACCOUNT,
				     PAGE_KERNEL);
1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
	if (!newinfo->entries) {
		ret = -ENOMEM;
		goto free_newinfo;
	}
	if (copy_from_user(
	   newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
		ret = -EFAULT;
		goto free_entries;
	}

	ret = do_replace_finish(net, &tmp, newinfo);
	if (ret == 0)
		return ret;
Linus Torvalds's avatar
Linus Torvalds committed
1122
free_entries:
1123
	vfree(newinfo->entries);
Linus Torvalds's avatar
Linus Torvalds committed
1124
free_newinfo:
1125
	vfree(newinfo);
Linus Torvalds's avatar
Linus Torvalds committed
1126 1127 1128
	return ret;
}

1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149
static void __ebt_unregister_table(struct net *net, struct ebt_table *table)
{
	int i;

	mutex_lock(&ebt_mutex);
	list_del(&table->list);
	mutex_unlock(&ebt_mutex);
	EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size,
			  ebt_cleanup_entry, net, NULL);
	if (table->private->nentries)
		module_put(table->me);
	vfree(table->private->entries);
	if (table->private->chainstack) {
		for_each_possible_cpu(i)
			vfree(table->private->chainstack[i]);
		vfree(table->private->chainstack);
	}
	vfree(table->private);
	kfree(table);
}

1150 1151
int ebt_register_table(struct net *net, const struct ebt_table *input_table,
		       const struct nf_hook_ops *ops, struct ebt_table **res)
Linus Torvalds's avatar
Linus Torvalds committed
1152 1153
{
	struct ebt_table_info *newinfo;
1154
	struct ebt_table *t, *table;
1155
	struct ebt_replace_kernel *repl;
Linus Torvalds's avatar
Linus Torvalds committed
1156
	int ret, i, countersize;
1157
	void *p;
Linus Torvalds's avatar
Linus Torvalds committed
1158

1159
	if (input_table == NULL || (repl = input_table->table) == NULL ||