Blame view

net/bridge/netfilter/ebtables.c 61.4 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  /*
   *  ebtables
   *
   *  Author:
   *  Bart De Schuymer		<bdschuym@pandora.be>
   *
   *  ebtables.c,v 2.0, July, 2002
   *
   *  This code is stongly inspired on the iptables code which is
   *  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.
   */
ff67e4e42   Jan Engelhardt   netfilter: xt ext...
17
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
  #include <linux/kmod.h>
  #include <linux/module.h>
  #include <linux/vmalloc.h>
18219d3f7   Jan Engelhardt   netfilter: ebtabl...
21
  #include <linux/netfilter/x_tables.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
  #include <linux/netfilter_bridge/ebtables.h>
  #include <linux/spinlock.h>
df0933dcb   Patrick McHardy   [NETFILTER]: kill...
24
  #include <linux/mutex.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
25
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
  #include <asm/uaccess.h>
  #include <linux/smp.h>
c8923c6b8   David S. Miller   [NETFILTER]: Fix ...
28
  #include <linux/cpumask.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
  #include <net/sock.h>
  /* needed for logical [in,out]-dev filtering */
  #include "../br_private.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
  #define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\
9d6f229fc   YOSHIFUJI Hideaki   [NET] BRIDGE: Fix...
33
  					 "report to author: "format, ## args)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  /* #define BUGPRINT(format, args...) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
38
39
40
41
42
43
44
45
46
47
  
  /*
   * Each cpu has its own set of counters, so there is no need for write_lock in
   * 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) + \
     COUNTER_OFFSET(n) * cpu))
57b47a53e   Ingo Molnar   [NET]: sem2mutex ...
48
  static DEFINE_MUTEX(ebt_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49

81e675c22   Florian Westphal   netfilter: ebtabl...
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  #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
043ef46c7   Jan Engelhardt   netfilter: move E...
69
  static struct xt_target ebt_standard_target = {
001a18d36   Jan Engelhardt   netfilter: add du...
70
71
72
  	.name       = "standard",
  	.revision   = 0,
  	.family     = NFPROTO_BRIDGE,
043ef46c7   Jan Engelhardt   netfilter: move E...
73
  	.targetsize = sizeof(int),
81e675c22   Florian Westphal   netfilter: ebtabl...
74
75
76
77
78
  #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
18219d3f7   Jan Engelhardt   netfilter: ebtabl...
79
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80

7eb355865   Jan Engelhardt   netfilter: xtable...
81
82
  static inline int
  ebt_do_watcher(const struct ebt_entry_watcher *w, struct sk_buff *skb,
de74c1699   Jan Engelhardt   netfilter: xtable...
83
  	       struct xt_action_param *par)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
  {
7eb355865   Jan Engelhardt   netfilter: xtable...
85
86
87
  	par->target   = w->u.watcher;
  	par->targinfo = w->data;
  	w->u.watcher->target(skb, par);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
89
90
  	/* watchers don't give a verdict */
  	return 0;
  }
de74c1699   Jan Engelhardt   netfilter: xtable...
91
92
93
  static inline int
  ebt_do_match(struct ebt_entry_match *m, const struct sk_buff *skb,
  	     struct xt_action_param *par)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
  {
f7108a20d   Jan Engelhardt   netfilter: xtable...
95
96
  	par->match     = m->u.match;
  	par->matchinfo = m->data;
d61ba9fd5   Jan Engelhardt   netfilter 05/09: ...
97
  	return m->u.match->match(skb, par) ? EBT_MATCH : EBT_NOMATCH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  }
d5d1baa15   Jan Engelhardt   netfilter: xtable...
99
100
  static inline int
  ebt_dev_check(const char *entry, const struct net_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
  {
  	int i = 0;
f3d8b2e46   Julia Lawall   net/bridge/netfil...
103
  	const char *devname;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
106
107
108
  
  	if (*entry == '\0')
  		return 0;
  	if (!device)
  		return 1;
f3d8b2e46   Julia Lawall   net/bridge/netfil...
109
  	devname = device->name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
113
114
115
116
117
  	/* 1 is the wildcard token */
  	while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i])
  		i++;
  	return (devname[i] != entry[i] && entry[i] != 1);
  }
  
  #define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
  /* process standard matches */
d5d1baa15   Jan Engelhardt   netfilter: xtable...
118
  static inline int
13937911f   Jesse Gross   ebtables: Allow f...
119
  ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb,
d5d1baa15   Jan Engelhardt   netfilter: xtable...
120
                  const struct net_device *in, const struct net_device *out)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
  {
13937911f   Jesse Gross   ebtables: Allow f...
122
  	const struct ethhdr *h = eth_hdr(skb);
b5ed54e94   stephen hemminger   bridge: fix RCU r...
123
  	const struct net_bridge_port *p;
13937911f   Jesse Gross   ebtables: Allow f...
124
  	__be16 ethproto;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
  	int verdict, i;
13937911f   Jesse Gross   ebtables: Allow f...
126
127
128
129
  	if (vlan_tx_tag_present(skb))
  		ethproto = htons(ETH_P_8021Q);
  	else
  		ethproto = h->h_proto;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
  	if (e->bitmask & EBT_802_3) {
13937911f   Jesse Gross   ebtables: Allow f...
131
  		if (FWINV2(ntohs(ethproto) >= 1536, EBT_IPROTO))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
  			return 1;
  	} else if (!(e->bitmask & EBT_NOPROTO) &&
13937911f   Jesse Gross   ebtables: Allow f...
134
  	   FWINV2(e->ethproto != ethproto, EBT_IPROTO))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
136
137
138
139
140
  		return 1;
  
  	if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
  		return 1;
  	if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
  		return 1;
f350a0a87   Jiri Pirko   bridge: use rx_ha...
141
  	/* rcu_read_lock()ed by nf_hook_slow */
b5ed54e94   stephen hemminger   bridge: fix RCU r...
142
143
  	if (in && (p = br_port_get_rcu(in)) != NULL &&
  	    FWINV2(ebt_dev_check(e->logical_in, p->br->dev), EBT_ILOGICALIN))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  		return 1;
b5ed54e94   stephen hemminger   bridge: fix RCU r...
145
146
  	if (out && (p = br_port_get_rcu(out)) != NULL &&
  	    FWINV2(ebt_dev_check(e->logical_out, p->br->dev), EBT_ILOGICALOUT))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
  		return 1;
  
  	if (e->bitmask & EBT_SOURCEMAC) {
  		verdict = 0;
  		for (i = 0; i < 6; i++)
  			verdict |= (h->h_source[i] ^ e->sourcemac[i]) &
  			   e->sourcemsk[i];
  		if (FWINV2(verdict != 0, EBT_ISOURCE) )
  			return 1;
  	}
  	if (e->bitmask & EBT_DESTMAC) {
  		verdict = 0;
  		for (i = 0; i < 6; i++)
  			verdict |= (h->h_dest[i] ^ e->destmac[i]) &
  			   e->destmsk[i];
  		if (FWINV2(verdict != 0, EBT_IDEST) )
  			return 1;
  	}
  	return 0;
  }
98e864031   Jan Engelhardt   netfilter: xtable...
167
168
169
170
171
  static inline __pure
  struct ebt_entry *ebt_next_entry(const struct ebt_entry *entry)
  {
  	return (void *)entry + entry->next_offset;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
  /* Do some firewalling */
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
173
  unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
176
177
178
179
     const struct net_device *in, const struct net_device *out,
     struct ebt_table *table)
  {
  	int i, nentries;
  	struct ebt_entry *point;
  	struct ebt_counter *counter_base, *cb_base;
d5d1baa15   Jan Engelhardt   netfilter: xtable...
180
  	const struct ebt_entry_target *t;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
  	int verdict, sp = 0;
  	struct ebt_chainstack *cs;
  	struct ebt_entries *chaininfo;
d5d1baa15   Jan Engelhardt   netfilter: xtable...
184
185
  	const char *base;
  	const struct ebt_table_info *private;
de74c1699   Jan Engelhardt   netfilter: xtable...
186
  	struct xt_action_param acpar;
f7108a20d   Jan Engelhardt   netfilter: xtable...
187

de74c1699   Jan Engelhardt   netfilter: xtable...
188
189
190
  	acpar.family  = NFPROTO_BRIDGE;
  	acpar.in      = in;
  	acpar.out     = out;
b4ba26119   Jan Engelhardt   netfilter: xtable...
191
  	acpar.hotdrop = false;
de74c1699   Jan Engelhardt   netfilter: xtable...
192
  	acpar.hooknum = hook;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
  
  	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) {
13937911f   Jesse Gross   ebtables: Allow f...
210
  		if (ebt_basic_match(point, skb, in, out))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
  			goto letscontinue;
de74c1699   Jan Engelhardt   netfilter: xtable...
212
  		if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, &acpar) != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
  			goto letscontinue;
b4ba26119   Jan Engelhardt   netfilter: xtable...
214
  		if (acpar.hotdrop) {
5365f8022   Jan Engelhardt   netfilter: implem...
215
216
217
  			read_unlock_bh(&table->lock);
  			return NF_DROP;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
220
  
  		/* increase counter */
  		(*(counter_base + i)).pcnt++;
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
221
  		(*(counter_base + i)).bcnt += skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
223
224
  
  		/* these should only watch: not modify, nor tell us
  		   what to do with the packet */
de74c1699   Jan Engelhardt   netfilter: xtable...
225
  		EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, &acpar);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
230
231
  
  		t = (struct ebt_entry_target *)
  		   (((char *)point) + point->target_offset);
  		/* standard target */
  		if (!t->u.target->target)
  			verdict = ((struct ebt_standard_target *)t)->verdict;
7eb355865   Jan Engelhardt   netfilter: xtable...
232
  		else {
de74c1699   Jan Engelhardt   netfilter: xtable...
233
234
235
  			acpar.target   = t->u.target;
  			acpar.targinfo = t->data;
  			verdict = t->u.target->target(skb, &acpar);
7eb355865   Jan Engelhardt   netfilter: xtable...
236
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
  		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:
  #ifdef CONFIG_NETFILTER_DEBUG
  			if (sp == 0) {
  				BUGPRINT("RETURN on base chain");
  				/* act like this is EBT_CONTINUE */
  				goto letscontinue;
  			}
  #endif
  			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;
  #ifdef CONFIG_NETFILTER_DEBUG
  		if (verdict < 0) {
  			BUGPRINT("bogus standard verdict
  ");
  			read_unlock_bh(&table->lock);
  			return NF_DROP;
  		}
  #endif
  		/* jump to a udc */
  		cs[sp].n = i + 1;
  		cs[sp].chaininfo = chaininfo;
98e864031   Jan Engelhardt   netfilter: xtable...
277
  		cs[sp].e = ebt_next_entry(point);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
  		i = 0;
  		chaininfo = (struct ebt_entries *) (base + verdict);
  #ifdef CONFIG_NETFILTER_DEBUG
  		if (chaininfo->distinguisher) {
  			BUGPRINT("jump to non-chain
  ");
  			read_unlock_bh(&table->lock);
  			return NF_DROP;
  		}
  #endif
  		nentries = chaininfo->nentries;
  		point = (struct ebt_entry *)chaininfo->data;
  		counter_base = cb_base + chaininfo->counter_offset;
  		sp++;
  		continue;
  letscontinue:
98e864031   Jan Engelhardt   netfilter: xtable...
294
  		point = ebt_next_entry(point);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
  		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,
57b47a53e   Ingo Molnar   [NET]: sem2mutex ...
312
     struct mutex *mutex)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
  {
df0933dcb   Patrick McHardy   [NETFILTER]: kill...
314
315
316
317
  	struct {
  		struct list_head list;
  		char name[EBT_FUNCTION_MAXNAMELEN];
  	} *e;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318

57b47a53e   Ingo Molnar   [NET]: sem2mutex ...
319
  	*error = mutex_lock_interruptible(mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
321
  	if (*error != 0)
  		return NULL;
df0933dcb   Patrick McHardy   [NETFILTER]: kill...
322
323
324
  	list_for_each_entry(e, head, list) {
  		if (strcmp(e->name, name) == 0)
  			return e;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
  	}
df0933dcb   Patrick McHardy   [NETFILTER]: kill...
326
327
328
  	*error = -ENOENT;
  	mutex_unlock(mutex);
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
331
  static void *
  find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
57b47a53e   Ingo Molnar   [NET]: sem2mutex ...
332
     int *error, struct mutex *mutex)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
  {
95a5afca4   Johannes Berg   net: Remove CONFI...
334
335
336
  	return try_then_request_module(
  			find_inlist_lock_noload(head, name, error, mutex),
  			"%s%s", prefix, name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
339
  
  static inline struct ebt_table *
511061e2d   Alexey Dobriyan   netfilter: netns ...
340
341
  find_table_lock(struct net *net, const char *name, int *error,
  		struct mutex *mutex)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
  {
511061e2d   Alexey Dobriyan   netfilter: netns ...
343
344
  	return find_inlist_lock(&net->xt.tables[NFPROTO_BRIDGE], name,
  				"ebtable_", error, mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
  static inline int
9b4fce7a3   Jan Engelhardt   netfilter: xtable...
347
348
  ebt_check_match(struct ebt_entry_match *m, struct xt_mtchk_param *par,
  		unsigned int *cnt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
  {
9b4fce7a3   Jan Engelhardt   netfilter: xtable...
350
  	const struct ebt_entry *e = par->entryinfo;
043ef46c7   Jan Engelhardt   netfilter: move E...
351
  	struct xt_match *match;
14197d544   Al Viro   [EBTABLES]: Preve...
352
  	size_t left = ((char *)e + e->watchers_offset) - (char *)m;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
  	int ret;
14197d544   Al Viro   [EBTABLES]: Preve...
354
355
  	if (left < sizeof(struct ebt_entry_match) ||
  	    left - sizeof(struct ebt_entry_match) < m->match_size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
  		return -EINVAL;
043ef46c7   Jan Engelhardt   netfilter: move E...
357

fd0ec0e62   Jan Engelhardt   netfilter: xtable...
358
  	match = xt_request_find_match(NFPROTO_BRIDGE, m->u.name, 0);
043ef46c7   Jan Engelhardt   netfilter: move E...
359
360
  	if (IS_ERR(match))
  		return PTR_ERR(match);
043ef46c7   Jan Engelhardt   netfilter: move E...
361
  	m->u.match = match;
9b4fce7a3   Jan Engelhardt   netfilter: xtable...
362
363
  	par->match     = match;
  	par->matchinfo = m->data;
916a917df   Jan Engelhardt   netfilter: xtable...
364
  	ret = xt_check_match(par, m->match_size,
9b4fce7a3   Jan Engelhardt   netfilter: xtable...
365
  	      e->ethproto, e->invflags & EBT_IPROTO);
043ef46c7   Jan Engelhardt   netfilter: move E...
366
367
368
  	if (ret < 0) {
  		module_put(match->me);
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  	}
043ef46c7   Jan Engelhardt   netfilter: move E...
370

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
372
373
374
375
  	(*cnt)++;
  	return 0;
  }
  
  static inline int
af5d6dc20   Jan Engelhardt   netfilter: xtable...
376
377
  ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
  		  unsigned int *cnt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
  {
af5d6dc20   Jan Engelhardt   netfilter: xtable...
379
  	const struct ebt_entry *e = par->entryinfo;
043ef46c7   Jan Engelhardt   netfilter: move E...
380
  	struct xt_target *watcher;
14197d544   Al Viro   [EBTABLES]: Preve...
381
  	size_t left = ((char *)e + e->target_offset) - (char *)w;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382
  	int ret;
14197d544   Al Viro   [EBTABLES]: Preve...
383
384
  	if (left < sizeof(struct ebt_entry_watcher) ||
  	   left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
  		return -EINVAL;
043ef46c7   Jan Engelhardt   netfilter: move E...
386

d2a7b6bad   Jan Engelhardt   netfilter: xtable...
387
  	watcher = xt_request_find_target(NFPROTO_BRIDGE, w->u.name, 0);
043ef46c7   Jan Engelhardt   netfilter: move E...
388
389
  	if (IS_ERR(watcher))
  		return PTR_ERR(watcher);
043ef46c7   Jan Engelhardt   netfilter: move E...
390
  	w->u.watcher = watcher;
af5d6dc20   Jan Engelhardt   netfilter: xtable...
391
392
  	par->target   = watcher;
  	par->targinfo = w->data;
916a917df   Jan Engelhardt   netfilter: xtable...
393
  	ret = xt_check_target(par, w->watcher_size,
af5d6dc20   Jan Engelhardt   netfilter: xtable...
394
  	      e->ethproto, e->invflags & EBT_IPROTO);
043ef46c7   Jan Engelhardt   netfilter: move E...
395
396
397
  	if (ret < 0) {
  		module_put(watcher->me);
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
  	}
043ef46c7   Jan Engelhardt   netfilter: move E...
399

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
401
402
  	(*cnt)++;
  	return 0;
  }
d5d1baa15   Jan Engelhardt   netfilter: xtable...
403
  static int ebt_verify_pointers(const struct ebt_replace *repl,
70fe9af47   Al Viro   [EBTABLES]: Pull ...
404
  			       struct ebt_table_info *newinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
  {
70fe9af47   Al Viro   [EBTABLES]: Pull ...
406
407
408
  	unsigned int limit = repl->entries_size;
  	unsigned int valid_hooks = repl->valid_hooks;
  	unsigned int offset = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
  	int i;
e4fd77dea   Al Viro   [EBTABLES]: Move ...
410
411
412
413
414
  	for (i = 0; i < NF_BR_NUMHOOKS; i++)
  		newinfo->hook_entry[i] = NULL;
  
  	newinfo->entries_size = repl->entries_size;
  	newinfo->nentries = repl->nentries;
70fe9af47   Al Viro   [EBTABLES]: Pull ...
415
416
417
  	while (offset < limit) {
  		size_t left = limit - offset;
  		struct ebt_entry *e = (void *)newinfo->entries + offset;
bb2ef25c2   Al Viro   [EBTABLES]: Fix w...
418

70fe9af47   Al Viro   [EBTABLES]: Pull ...
419
  		if (left < sizeof(unsigned int))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
  			break;
70fe9af47   Al Viro   [EBTABLES]: Pull ...
421
422
423
424
  
  		for (i = 0; i < NF_BR_NUMHOOKS; i++) {
  			if ((valid_hooks & (1 << i)) == 0)
  				continue;
1e419cd99   Al Viro   [EBTABLES]: Split...
425
426
  			if ((char __user *)repl->hook_entry[i] ==
  			     repl->entries + offset)
70fe9af47   Al Viro   [EBTABLES]: Pull ...
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
  				break;
  		}
  
  		if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
  			if (e->bitmask != 0) {
  				/* we make userspace set this right,
  				   so there is no misunderstanding */
  				BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
  					 "in distinguisher
  ");
  				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;
1756de262   Florian Westphal   netfilter: ebtabl...
449
450
  			if (e->next_offset < sizeof(struct ebt_entry))
  				return -EINVAL;
70fe9af47   Al Viro   [EBTABLES]: Pull ...
451
  			offset += e->next_offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
  		}
22b440bf9   Al Viro   [EBTABLES]: Split...
453
  	}
70fe9af47   Al Viro   [EBTABLES]: Pull ...
454
455
456
457
458
  	if (offset != limit) {
  		BUGPRINT("entries_size too small
  ");
  		return -EINVAL;
  	}
e4fd77dea   Al Viro   [EBTABLES]: Move ...
459
460
461
462
463
464
465
466
467
468
  
  	/* check if all valid hooks have a chain */
  	for (i = 0; i < NF_BR_NUMHOOKS; i++) {
  		if (!newinfo->hook_entry[i] &&
  		   (valid_hooks & (1 << i))) {
  			BUGPRINT("Valid hook without chain
  ");
  			return -EINVAL;
  		}
  	}
22b440bf9   Al Viro   [EBTABLES]: Split...
469
  	return 0;
22b440bf9   Al Viro   [EBTABLES]: Split...
470
471
472
473
474
475
476
  }
  
  /*
   * this one is very careful, as it is the first function
   * to parse the userspace data
   */
  static inline int
d5d1baa15   Jan Engelhardt   netfilter: xtable...
477
478
  ebt_check_entry_size_and_hooks(const struct ebt_entry *e,
     const struct ebt_table_info *newinfo,
0e795531c   Al Viro   [EBTABLES]: Switc...
479
480
     unsigned int *n, unsigned int *cnt,
     unsigned int *totalcnt, unsigned int *udc_cnt)
22b440bf9   Al Viro   [EBTABLES]: Split...
481
  {
22b440bf9   Al Viro   [EBTABLES]: Split...
482
483
484
  	int i;
  
  	for (i = 0; i < NF_BR_NUMHOOKS; i++) {
0e795531c   Al Viro   [EBTABLES]: Switc...
485
  		if ((void *)e == (void *)newinfo->hook_entry[i])
22b440bf9   Al Viro   [EBTABLES]: Split...
486
487
488
489
490
  			break;
  	}
  	/* beginning of a new chain
  	   if i == NF_BR_NUMHOOKS it must be a user defined chain */
  	if (i != NF_BR_NUMHOOKS || !e->bitmask) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
492
493
494
  		/* this checks if the previous chain has as many entries
  		   as it said it has */
  		if (*n != *cnt) {
  			BUGPRINT("nentries does not equal the nr of entries "
9d6f229fc   YOSHIFUJI Hideaki   [NET] BRIDGE: Fix...
495
496
  				 "in the chain
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
  			return -EINVAL;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
500
501
502
503
504
505
506
507
508
509
510
  		if (((struct ebt_entries *)e)->policy != EBT_DROP &&
  		   ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
  			/* only RETURN from udc */
  			if (i != NF_BR_NUMHOOKS ||
  			   ((struct ebt_entries *)e)->policy != EBT_RETURN) {
  				BUGPRINT("bad policy
  ");
  				return -EINVAL;
  			}
  		}
  		if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
  			(*udc_cnt)++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
  		if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
  			BUGPRINT("counter_offset != totalcnt");
  			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 ||
  	   e->target_offset >= e->next_offset) {
  		BUGPRINT("entry offsets not in right order
  ");
  		return -EINVAL;
  	}
  	/* this is not checked anywhere else */
  	if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
  		BUGPRINT("target size too small
  ");
  		return -EINVAL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
  	(*cnt)++;
  	(*totalcnt)++;
  	return 0;
  }
  
  struct ebt_cl_stack
  {
  	struct ebt_chainstack cs;
  	int from;
  	unsigned int hookmask;
  };
  
  /*
   * we need these positions to check that the jumps to a different part of the
   * 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,
177abc348   Al Viro   [EBTABLES]: Clean...
551
     unsigned int *n, struct ebt_cl_stack *udc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552
553
554
555
  {
  	int i;
  
  	/* we're only interested in chain starts */
40642f95f   Al Viro   [EBTABLES]: Verif...
556
  	if (e->bitmask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
558
  		return 0;
  	for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
  		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
f54e9367f   Alexey Dobriyan   netfilter: xtable...
576
  ebt_cleanup_match(struct ebt_entry_match *m, struct net *net, unsigned int *i)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
  {
6be3d8598   Jan Engelhardt   netfilter: xtable...
578
  	struct xt_mtdtor_param par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
580
  	if (i && (*i)-- == 0)
  		return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
581

f54e9367f   Alexey Dobriyan   netfilter: xtable...
582
  	par.net       = net;
6be3d8598   Jan Engelhardt   netfilter: xtable...
583
584
  	par.match     = m->u.match;
  	par.matchinfo = m->data;
916a917df   Jan Engelhardt   netfilter: xtable...
585
  	par.family    = NFPROTO_BRIDGE;
6be3d8598   Jan Engelhardt   netfilter: xtable...
586
587
588
  	if (par.match->destroy != NULL)
  		par.match->destroy(&par);
  	module_put(par.match->me);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
590
591
592
  	return 0;
  }
  
  static inline int
add674612   Patrick McHardy   netfilter: add st...
593
  ebt_cleanup_watcher(struct ebt_entry_watcher *w, struct net *net, unsigned int *i)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
  {
a2df1648b   Jan Engelhardt   netfilter: xtable...
595
  	struct xt_tgdtor_param par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596
597
  	if (i && (*i)-- == 0)
  		return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598

add674612   Patrick McHardy   netfilter: add st...
599
  	par.net      = net;
a2df1648b   Jan Engelhardt   netfilter: xtable...
600
601
  	par.target   = w->u.watcher;
  	par.targinfo = w->data;
916a917df   Jan Engelhardt   netfilter: xtable...
602
  	par.family   = NFPROTO_BRIDGE;
a2df1648b   Jan Engelhardt   netfilter: xtable...
603
604
605
  	if (par.target->destroy != NULL)
  		par.target->destroy(&par);
  	module_put(par.target->me);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
607
608
609
  	return 0;
  }
  
  static inline int
f54e9367f   Alexey Dobriyan   netfilter: xtable...
610
  ebt_cleanup_entry(struct ebt_entry *e, struct net *net, unsigned int *cnt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
  {
a2df1648b   Jan Engelhardt   netfilter: xtable...
612
  	struct xt_tgdtor_param par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
  	struct ebt_entry_target *t;
40642f95f   Al Viro   [EBTABLES]: Verif...
614
  	if (e->bitmask == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615
616
617
618
  		return 0;
  	/* we're done */
  	if (cnt && (*cnt)-- == 0)
  		return 1;
add674612   Patrick McHardy   netfilter: add st...
619
  	EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, net, NULL);
f54e9367f   Alexey Dobriyan   netfilter: xtable...
620
  	EBT_MATCH_ITERATE(e, ebt_cleanup_match, net, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
  	t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
622

add674612   Patrick McHardy   netfilter: add st...
623
  	par.net      = net;
a2df1648b   Jan Engelhardt   netfilter: xtable...
624
625
  	par.target   = t->u.target;
  	par.targinfo = t->data;
916a917df   Jan Engelhardt   netfilter: xtable...
626
  	par.family   = NFPROTO_BRIDGE;
a2df1648b   Jan Engelhardt   netfilter: xtable...
627
628
629
  	if (par.target->destroy != NULL)
  		par.target->destroy(&par);
  	module_put(par.target->me);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
631
632
633
  	return 0;
  }
  
  static inline int
d5d1baa15   Jan Engelhardt   netfilter: xtable...
634
635
  ebt_check_entry(struct ebt_entry *e, struct net *net,
     const struct ebt_table_info *newinfo,
f7da79d99   Al Viro   [EBTABLES]: ebt_c...
636
     const char *name, unsigned int *cnt,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
638
639
     struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
  {
  	struct ebt_entry_target *t;
043ef46c7   Jan Engelhardt   netfilter: move E...
640
  	struct xt_target *target;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
  	unsigned int i, j, hook = 0, hookmask = 0;
44f9a2fdc   Chuck Ebbert   [NETFILTER]: ebta...
642
  	size_t gap;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643
  	int ret;
6be3d8598   Jan Engelhardt   netfilter: xtable...
644
  	struct xt_mtchk_param mtpar;
af5d6dc20   Jan Engelhardt   netfilter: xtable...
645
  	struct xt_tgchk_param tgpar;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
647
  
  	/* don't mess with the struct ebt_entries */
40642f95f   Al Viro   [EBTABLES]: Verif...
648
  	if (e->bitmask == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
  		return 0;
  
  	if (e->bitmask & ~EBT_F_MASK) {
  		BUGPRINT("Unknown flag for bitmask
  ");
  		return -EINVAL;
  	}
  	if (e->invflags & ~EBT_INV_MASK) {
  		BUGPRINT("Unknown flag for inv bitmask
  ");
  		return -EINVAL;
  	}
  	if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
  		BUGPRINT("NOPROTO & 802_3 not allowed
  ");
  		return -EINVAL;
  	}
  	/* what hook do we belong to? */
  	for (i = 0; i < NF_BR_NUMHOOKS; i++) {
f7da79d99   Al Viro   [EBTABLES]: ebt_c...
668
  		if (!newinfo->hook_entry[i])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
  			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
  	   a base chain */
  	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;
9b4fce7a3   Jan Engelhardt   netfilter: xtable...
689

add674612   Patrick McHardy   netfilter: add st...
690
  	mtpar.net	= tgpar.net       = net;
af5d6dc20   Jan Engelhardt   netfilter: xtable...
691
692
693
  	mtpar.table     = tgpar.table     = name;
  	mtpar.entryinfo = tgpar.entryinfo = e;
  	mtpar.hook_mask = tgpar.hook_mask = hookmask;
916a917df   Jan Engelhardt   netfilter: xtable...
694
  	mtpar.family    = tgpar.family    = NFPROTO_BRIDGE;
6be3d8598   Jan Engelhardt   netfilter: xtable...
695
  	ret = EBT_MATCH_ITERATE(e, ebt_check_match, &mtpar, &i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
697
698
  	if (ret != 0)
  		goto cleanup_matches;
  	j = 0;
af5d6dc20   Jan Engelhardt   netfilter: xtable...
699
  	ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, &tgpar, &j);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
701
702
  	if (ret != 0)
  		goto cleanup_watchers;
  	t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
44f9a2fdc   Chuck Ebbert   [NETFILTER]: ebta...
703
  	gap = e->next_offset - e->target_offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704

d2a7b6bad   Jan Engelhardt   netfilter: xtable...
705
  	target = xt_request_find_target(NFPROTO_BRIDGE, t->u.name, 0);
043ef46c7   Jan Engelhardt   netfilter: move E...
706
707
  	if (IS_ERR(target)) {
  		ret = PTR_ERR(target);
001a18d36   Jan Engelhardt   netfilter: add du...
708
  		goto cleanup_watchers;
001a18d36   Jan Engelhardt   netfilter: add du...
709
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
710
711
  	t->u.target = target;
  	if (t->u.target == &ebt_standard_target) {
14197d544   Al Viro   [EBTABLES]: Preve...
712
  		if (gap < sizeof(struct ebt_standard_target)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
714
715
716
717
718
719
720
721
722
723
724
  			BUGPRINT("Standard target size too big
  ");
  			ret = -EFAULT;
  			goto cleanup_watchers;
  		}
  		if (((struct ebt_standard_target *)t)->verdict <
  		   -NUM_STANDARD_TARGETS) {
  			BUGPRINT("Invalid standard target
  ");
  			ret = -EFAULT;
  			goto cleanup_watchers;
  		}
18219d3f7   Jan Engelhardt   netfilter: ebtabl...
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;
043ef46c7   Jan Engelhardt   netfilter: move E...
729
  	}
af5d6dc20   Jan Engelhardt   netfilter: xtable...
730
731
  	tgpar.target   = target;
  	tgpar.targinfo = t->data;
916a917df   Jan Engelhardt   netfilter: xtable...
732
  	ret = xt_check_target(&tgpar, t->target_size,
af5d6dc20   Jan Engelhardt   netfilter: xtable...
733
  	      e->ethproto, e->invflags & EBT_IPROTO);
043ef46c7   Jan Engelhardt   netfilter: move E...
734
735
  	if (ret < 0) {
  		module_put(target->me);
18219d3f7   Jan Engelhardt   netfilter: ebtabl...
736
  		goto cleanup_watchers;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737
738
739
740
  	}
  	(*cnt)++;
  	return 0;
  cleanup_watchers:
add674612   Patrick McHardy   netfilter: add st...
741
  	EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, net, &j);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
  cleanup_matches:
f54e9367f   Alexey Dobriyan   netfilter: xtable...
743
  	EBT_MATCH_ITERATE(e, ebt_cleanup_match, net, &i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
745
746
747
748
749
750
751
  	return ret;
  }
  
  /*
   * checks for loops and sets the hook mask for udc
   * 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
   */
d5d1baa15   Jan Engelhardt   netfilter: xtable...
752
  static int check_chainloops(const struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
755
     unsigned int udc_cnt, unsigned int hooknr, char *base)
  {
  	int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
d5d1baa15   Jan Engelhardt   netfilter: xtable...
756
757
  	const struct ebt_entry *e = (struct ebt_entry *)chain->data;
  	const struct ebt_entry_target *t;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
  
  	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) >
  		   e->next_offset) {
  			BUGPRINT("Standard target size too big
  ");
  			return -1;
  		}
  		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 */
  			if (i == udc_cnt) {
  				BUGPRINT("bad destination
  ");
  				return -1;
  			}
  			if (cl_s[i].cs.n) {
  				BUGPRINT("loop
  ");
  				return -1;
  			}
98a0824a0   Al Viro   [EBTABLES]: Deal ...
804
805
806
  			if (cl_s[i].hookmask & (1 << hooknr))
  				goto letscontinue;
  			/* this can't be 0, so the loop test is correct */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
808
  			cl_s[i].cs.n = pos + 1;
  			pos = 0;
98e864031   Jan Engelhardt   netfilter: xtable...
809
  			cl_s[i].cs.e = ebt_next_entry(e);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
811
812
813
814
815
816
817
818
  			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:
98e864031   Jan Engelhardt   netfilter: xtable...
819
  		e = ebt_next_entry(e);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820
821
822
823
824
825
  		pos++;
  	}
  	return 0;
  }
  
  /* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
d5d1baa15   Jan Engelhardt   netfilter: xtable...
826
  static int translate_table(struct net *net, const char *name,
a83d8e8d0   Alexey Dobriyan   netfilter: xtable...
827
  			   struct ebt_table_info *newinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828
829
830
831
832
833
  {
  	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;
1f072c96f   Al Viro   [EBTABLES]: trans...
834
  	while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
836
837
838
839
840
  		i++;
  	if (i == NF_BR_NUMHOOKS) {
  		BUGPRINT("No valid hooks specified
  ");
  		return -EINVAL;
  	}
1f072c96f   Al Viro   [EBTABLES]: trans...
841
  	if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
842
843
844
845
846
847
848
  		BUGPRINT("Chains don't start at beginning
  ");
  		return -EINVAL;
  	}
  	/* make sure chains are ordered after each other in same order
  	   as their corresponding hooks */
  	for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
1f072c96f   Al Viro   [EBTABLES]: trans...
849
  		if (!newinfo->hook_entry[j])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850
  			continue;
1f072c96f   Al Viro   [EBTABLES]: trans...
851
  		if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
853
854
855
856
857
  			BUGPRINT("Hook order must be followed
  ");
  			return -EINVAL;
  		}
  		i = j;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858
859
860
861
  	/* 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
9d6f229fc   YOSHIFUJI Hideaki   [NET] BRIDGE: Fix...
862
  		  newinfo->nentries afterwards */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
864
  	udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
  	ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
0e795531c   Al Viro   [EBTABLES]: Switc...
865
866
  	   ebt_check_entry_size_and_hooks, newinfo,
  	   &i, &j, &k, &udc_cnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
868
869
870
871
872
  
  	if (ret != 0)
  		return ret;
  
  	if (i != j) {
  		BUGPRINT("nentries does not equal the nr of entries in the "
9d6f229fc   YOSHIFUJI Hideaki   [NET] BRIDGE: Fix...
873
874
  			 "(last) chain
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875
876
877
878
879
880
881
  		return -EINVAL;
  	}
  	if (k != newinfo->nentries) {
  		BUGPRINT("Total nentries is wrong
  ");
  		return -EINVAL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882
883
884
885
886
  	/* get the location of the udc, put them in an array
  	   while we're at it, allocate the chainstack */
  	if (udc_cnt) {
  		/* this will get free'd in do_replace()/ebt_register_table()
  		   if an error occurs */
7ad4d2f69   Jayachandran C   [BRIDGE] ebtables...
887
  		newinfo->chainstack =
53b8a315b   Christoph Lameter   [PATCH] Convert h...
888
  			vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889
890
  		if (!newinfo->chainstack)
  			return -ENOMEM;
6f9120422   KAMEZAWA Hiroyuki   [PATCH] for_each_...
891
  		for_each_possible_cpu(i) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892
  			newinfo->chainstack[i] =
18bc89aa2   Jayachandran C   [EBTABLES]: Clean...
893
  			  vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
895
896
897
898
899
900
901
  			if (!newinfo->chainstack[i]) {
  				while (i)
  					vfree(newinfo->chainstack[--i]);
  				vfree(newinfo->chainstack);
  				newinfo->chainstack = NULL;
  				return -ENOMEM;
  			}
  		}
18bc89aa2   Jayachandran C   [EBTABLES]: Clean...
902
  		cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903
904
905
906
  		if (!cl_s)
  			return -ENOMEM;
  		i = 0; /* the i'th udc */
  		EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
177abc348   Al Viro   [EBTABLES]: Clean...
907
  		   ebt_get_udc_positions, newinfo, &i, cl_s);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
909
910
911
912
913
914
915
916
917
918
  		/* sanity check */
  		if (i != udc_cnt) {
  			BUGPRINT("i != udc_cnt
  ");
  			vfree(cl_s);
  			return -EFAULT;
  		}
  	}
  
  	/* Check for loops */
  	for (i = 0; i < NF_BR_NUMHOOKS; i++)
1f072c96f   Al Viro   [EBTABLES]: trans...
919
  		if (newinfo->hook_entry[i])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
920
921
  			if (check_chainloops(newinfo->hook_entry[i],
  			   cl_s, udc_cnt, i, newinfo->entries)) {
68d318720   James Lamanna   [EBTABLES]: vfree...
922
  				vfree(cl_s);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
923
924
  				return -EINVAL;
  			}
96de0e252   Jan Engelhardt   Convert files to ...
925
  	/* we now know the following (along with E=mc²):
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
926
927
928
929
930
931
932
933
934
935
936
937
  	   - 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. */
  
  	/* used to know what we need to clean up if something goes wrong */
  	i = 0;
  	ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
a83d8e8d0   Alexey Dobriyan   netfilter: xtable...
938
  	   ebt_check_entry, net, newinfo, name, &i, cl_s, udc_cnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
940
  	if (ret != 0) {
  		EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
f54e9367f   Alexey Dobriyan   netfilter: xtable...
941
  				  ebt_cleanup_entry, net, &i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
942
  	}
68d318720   James Lamanna   [EBTABLES]: vfree...
943
  	vfree(cl_s);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944
945
946
947
  	return ret;
  }
  
  /* called under write_lock */
d5d1baa15   Jan Engelhardt   netfilter: xtable...
948
  static void get_counters(const struct ebt_counter *oldcounters,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949
950
951
952
953
954
955
     struct ebt_counter *counters, unsigned int nentries)
  {
  	int i, cpu;
  	struct ebt_counter *counter_base;
  
  	/* counters of cpu 0 */
  	memcpy(counters, oldcounters,
c8923c6b8   David S. Miller   [NETFILTER]: Fix ...
956
  	       sizeof(struct ebt_counter) * nentries);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957
  	/* add other counters to those of cpu 0 */
6f9120422   KAMEZAWA Hiroyuki   [PATCH] for_each_...
958
  	for_each_possible_cpu(cpu) {
c8923c6b8   David S. Miller   [NETFILTER]: Fix ...
959
960
  		if (cpu == 0)
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
961
962
963
964
965
966
967
  		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;
  		}
  	}
  }
e788759f4   Florian Westphal   netfilter: ebtabl...
968
969
  static int do_replace_finish(struct net *net, struct ebt_replace *repl,
  			      struct ebt_table_info *newinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
970
  {
e788759f4   Florian Westphal   netfilter: ebtabl...
971
  	int ret, i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
972
973
974
  	struct ebt_counter *counterstmp = NULL;
  	/* used to be able to unlock earlier */
  	struct ebt_table_info *table;
e788759f4   Florian Westphal   netfilter: ebtabl...
975
  	struct ebt_table *t;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976
977
978
  
  	/* the user wants counters back
  	   the check on the size is done later, when we have the lock */
e788759f4   Florian Westphal   netfilter: ebtabl...
979
980
981
982
983
  	if (repl->num_counters) {
  		unsigned long size = repl->num_counters * sizeof(*counterstmp);
  		counterstmp = vmalloc(size);
  		if (!counterstmp)
  			return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
984
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
985

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
986
  	newinfo->chainstack = NULL;
e788759f4   Florian Westphal   netfilter: ebtabl...
987
  	ret = ebt_verify_pointers(repl, newinfo);
1bc2326cb   Al Viro   [EBTABLES]: Move ...
988
989
  	if (ret != 0)
  		goto free_counterstmp;
e788759f4   Florian Westphal   netfilter: ebtabl...
990
  	ret = translate_table(net, repl->name, newinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
991
992
993
  
  	if (ret != 0)
  		goto free_counterstmp;
e788759f4   Florian Westphal   netfilter: ebtabl...
994
  	t = find_table_lock(net, repl->name, &ret, &ebt_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
996
997
998
999
1000
  	if (!t) {
  		ret = -ENOENT;
  		goto free_iterate;
  	}
  
  	/* the table doesn't like it */
e788759f4   Florian Westphal   netfilter: ebtabl...
1001
  	if (t->check && (ret = t->check(newinfo, repl->valid_hooks)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1002
  		goto free_unlock;
e788759f4   Florian Westphal   netfilter: ebtabl...
1003
  	if (repl->num_counters && repl->num_counters != t->private->nentries) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
  		BUGPRINT("Wrong nr. of counters requested
  ");
  		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);
e788759f4   Florian Westphal   netfilter: ebtabl...
1020
  	if (repl->num_counters)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1021
1022
1023
1024
1025
  		get_counters(t->private->counters, counterstmp,
  		   t->private->nentries);
  
  	t->private = newinfo;
  	write_unlock_bh(&t->lock);
57b47a53e   Ingo Molnar   [NET]: sem2mutex ...
1026
  	mutex_unlock(&ebt_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1027
1028
1029
1030
  	/* 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. */
e788759f4   Florian Westphal   netfilter: ebtabl...
1031
1032
1033
  	if (repl->num_counters &&
  	   copy_to_user(repl->counters, counterstmp,
  	   repl->num_counters * sizeof(struct ebt_counter))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1034
1035
1036
1037
1038
1039
1040
  		ret = -EFAULT;
  	}
  	else
  		ret = 0;
  
  	/* decrease module count and free resources */
  	EBT_ENTRY_ITERATE(table->entries, table->entries_size,
f54e9367f   Alexey Dobriyan   netfilter: xtable...
1041
  			  ebt_cleanup_entry, net, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1042
1043
1044
  
  	vfree(table->entries);
  	if (table->chainstack) {
6f9120422   KAMEZAWA Hiroyuki   [PATCH] for_each_...
1045
  		for_each_possible_cpu(i)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1046
1047
1048
1049
  			vfree(table->chainstack[i]);
  		vfree(table->chainstack);
  	}
  	vfree(table);
68d318720   James Lamanna   [EBTABLES]: vfree...
1050
  	vfree(counterstmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1051
1052
1053
  	return ret;
  
  free_unlock:
57b47a53e   Ingo Molnar   [NET]: sem2mutex ...
1054
  	mutex_unlock(&ebt_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1055
1056
  free_iterate:
  	EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
f54e9367f   Alexey Dobriyan   netfilter: xtable...
1057
  			  ebt_cleanup_entry, net, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1058
  free_counterstmp:
68d318720   James Lamanna   [EBTABLES]: vfree...
1059
  	vfree(counterstmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1060
1061
  	/* can be initialized in translate_table() */
  	if (newinfo->chainstack) {
6f9120422   KAMEZAWA Hiroyuki   [PATCH] for_each_...
1062
  		for_each_possible_cpu(i)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1063
1064
1065
  			vfree(newinfo->chainstack[i]);
  		vfree(newinfo->chainstack);
  	}
e788759f4   Florian Westphal   netfilter: ebtabl...
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
  	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;
  
  	if (len != sizeof(tmp) + tmp.entries_size) {
  		BUGPRINT("Wrong len argument
  ");
  		return -EINVAL;
  	}
  
  	if (tmp.entries_size == 0) {
  		BUGPRINT("Entries_size never zero
  ");
  		return -EINVAL;
  	}
  	/* 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;
d846f7119   Vasiliy Kulikov   bridge: netfilter...
1097
  	tmp.name[sizeof(tmp.name) - 1] = 0;
e788759f4   Florian Westphal   netfilter: ebtabl...
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
  	countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
  	newinfo = vmalloc(sizeof(*newinfo) + countersize);
  	if (!newinfo)
  		return -ENOMEM;
  
  	if (countersize)
  		memset(newinfo->counters, 0, countersize);
  
  	newinfo->entries = 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
  ");
  		ret = -EFAULT;
  		goto free_entries;
  	}
  
  	ret = do_replace_finish(net, &tmp, newinfo);
  	if (ret == 0)
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1122
  free_entries:
68d318720   James Lamanna   [EBTABLES]: vfree...
1123
  	vfree(newinfo->entries);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1124
  free_newinfo:
68d318720   James Lamanna   [EBTABLES]: vfree...
1125
  	vfree(newinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1126
1127
  	return ret;
  }
35aad0ffd   Jan Engelhardt   netfilter: xtable...
1128
1129
  struct ebt_table *
  ebt_register_table(struct net *net, const struct ebt_table *input_table)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1130
1131
  {
  	struct ebt_table_info *newinfo;
35aad0ffd   Jan Engelhardt   netfilter: xtable...
1132
  	struct ebt_table *t, *table;
1e419cd99   Al Viro   [EBTABLES]: Split...
1133
  	struct ebt_replace_kernel *repl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1134
  	int ret, i, countersize;
df07a81e9   Al Viro   [EBTABLES]: Clean...
1135
  	void *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1136

35aad0ffd   Jan Engelhardt   netfilter: xtable...
1137
  	if (input_table == NULL || (repl = input_table->table) == NULL ||
1a9180a20   Tomas Winkler   net/bridge: fix t...
1138
  	    repl->entries == NULL || repl->entries_size == 0 ||
35aad0ffd   Jan Engelhardt   netfilter: xtable...
1139
  	    repl->counters != NULL || input_table->private != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140
1141
  		BUGPRINT("Bad table data for ebt_register_table!!!
  ");
6beceee5a   Alexey Dobriyan   netfilter: netns ...
1142
1143
1144
1145
  		return ERR_PTR(-EINVAL);
  	}
  
  	/* Don't add one table to multiple lists. */
35aad0ffd   Jan Engelhardt   netfilter: xtable...
1146
  	table = kmemdup(input_table, sizeof(struct ebt_table), GFP_KERNEL);
6beceee5a   Alexey Dobriyan   netfilter: netns ...
1147
1148
1149
  	if (!table) {
  		ret = -ENOMEM;
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150
  	}
53b8a315b   Christoph Lameter   [PATCH] Convert h...
1151
  	countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
18bc89aa2   Jayachandran C   [EBTABLES]: Clean...
1152
  	newinfo = vmalloc(sizeof(*newinfo) + countersize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1153
1154
  	ret = -ENOMEM;
  	if (!newinfo)
6beceee5a   Alexey Dobriyan   netfilter: netns ...
1155
  		goto free_table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1156

df07a81e9   Al Viro   [EBTABLES]: Clean...
1157
1158
  	p = vmalloc(repl->entries_size);
  	if (!p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1159
  		goto free_newinfo;
df07a81e9   Al Viro   [EBTABLES]: Clean...
1160
1161
1162
1163
1164
  	memcpy(p, repl->entries, repl->entries_size);
  	newinfo->entries = p;
  
  	newinfo->entries_size = repl->entries_size;
  	newinfo->nentries = repl->nentries;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1165
1166
1167
1168
1169
1170
  
  	if (countersize)
  		memset(newinfo->counters, 0, countersize);
  
  	/* fill in newinfo and parse the entries */
  	newinfo->chainstack = NULL;
df07a81e9   Al Viro   [EBTABLES]: Clean...
1171
1172
1173
1174
1175
1176
1177
  	for (i = 0; i < NF_BR_NUMHOOKS; i++) {
  		if ((repl->valid_hooks & (1 << i)) == 0)
  			newinfo->hook_entry[i] = NULL;
  		else
  			newinfo->hook_entry[i] = p +
  				((char *)repl->hook_entry[i] - repl->entries);
  	}
a83d8e8d0   Alexey Dobriyan   netfilter: xtable...
1178
  	ret = translate_table(net, repl->name, newinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1179
1180
1181
1182
1183
1184
1185
1186
1187
  	if (ret != 0) {
  		BUGPRINT("Translate_table failed
  ");
  		goto free_chainstack;
  	}
  
  	if (table->check && table->check(newinfo, table->valid_hooks)) {
  		BUGPRINT("The table doesn't like its own initial data, lol
  ");
5189054dd   Julia Lawall   net/bridge/netfil...
1188
1189
  		ret = -EINVAL;
  		goto free_chainstack;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1190
1191
1192
1193
  	}
  
  	table->private = newinfo;
  	rwlock_init(&table->lock);
57b47a53e   Ingo Molnar   [NET]: sem2mutex ...
1194
  	ret = mutex_lock_interruptible(&ebt_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1195
1196
  	if (ret != 0)
  		goto free_chainstack;
511061e2d   Alexey Dobriyan   netfilter: netns ...
1197
  	list_for_each_entry(t, &net->xt.tables[NFPROTO_BRIDGE], list) {
df0933dcb   Patrick McHardy   [NETFILTER]: kill...
1198
1199
1200
1201
1202
1203
  		if (strcmp(t->name, table->name) == 0) {
  			ret = -EEXIST;
  			BUGPRINT("Table name already exists
  ");
  			goto free_unlock;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1204
1205
1206
1207
1208
1209
1210
  	}
  
  	/* Hold a reference count if the chains aren't empty */
  	if (newinfo->nentries && !try_module_get(table->me)) {
  		ret = -ENOENT;
  		goto free_unlock;
  	}
511061e2d   Alexey Dobriyan   netfilter: netns ...
1211
  	list_add(&table->list, &net->xt.tables[NFPROTO_BRIDGE]);
57b47a53e   Ingo Molnar   [NET]: sem2mutex ...
1212
  	mutex_unlock(&ebt_mutex);
6beceee5a   Alexey Dobriyan   netfilter: netns ...
1213
  	return table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1214
  free_unlock:
57b47a53e   Ingo Molnar   [NET]: sem2mutex ...
1215
  	mutex_unlock(&ebt_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1216
1217
  free_chainstack:
  	if (newinfo->chainstack) {
6f9120422   KAMEZAWA Hiroyuki   [PATCH] for_each_...
1218
  		for_each_possible_cpu(i)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1219
1220
1221
1222
1223
1224
  			vfree(newinfo->chainstack[i]);
  		vfree(newinfo->chainstack);
  	}
  	vfree(newinfo->entries);
  free_newinfo:
  	vfree(newinfo);
6beceee5a   Alexey Dobriyan   netfilter: netns ...
1225
1226
1227
1228
  free_table:
  	kfree(table);
  out:
  	return ERR_PTR(ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1229
  }
f54e9367f   Alexey Dobriyan   netfilter: xtable...
1230
  void ebt_unregister_table(struct net *net, struct ebt_table *table)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1231
1232
1233
1234
1235
1236
1237
1238
  {
  	int i;
  
  	if (!table) {
  		BUGPRINT("Request to unregister NULL table!!!
  ");
  		return;
  	}
57b47a53e   Ingo Molnar   [NET]: sem2mutex ...
1239
  	mutex_lock(&ebt_mutex);
df0933dcb   Patrick McHardy   [NETFILTER]: kill...
1240
  	list_del(&table->list);
57b47a53e   Ingo Molnar   [NET]: sem2mutex ...
1241
  	mutex_unlock(&ebt_mutex);
dbcdf85a2   Alexey Dobriyan   netfilter: netns ...
1242
  	EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size,
f54e9367f   Alexey Dobriyan   netfilter: xtable...
1243
  			  ebt_cleanup_entry, net, NULL);
dbcdf85a2   Alexey Dobriyan   netfilter: netns ...
1244
1245
  	if (table->private->nentries)
  		module_put(table->me);
68d318720   James Lamanna   [EBTABLES]: vfree...
1246
  	vfree(table->private->entries);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1247
  	if (table->private->chainstack) {
6f9120422   KAMEZAWA Hiroyuki   [PATCH] for_each_...
1248
  		for_each_possible_cpu(i)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1249
1250
1251
1252
  			vfree(table->private->chainstack[i]);
  		vfree(table->private->chainstack);
  	}
  	vfree(table->private);
6beceee5a   Alexey Dobriyan   netfilter: netns ...
1253
  	kfree(table);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1254
1255
1256
  }
  
  /* userspace just supplied us with counters */
49facff9f   Florian Westphal   netfilter: ebtabl...
1257
1258
1259
1260
  static int do_update_counters(struct net *net, const char *name,
  				struct ebt_counter __user *counters,
  				unsigned int num_counters,
  				const void __user *user, unsigned int len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1261
1262
1263
  {
  	int i, ret;
  	struct ebt_counter *tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1264
  	struct ebt_table *t;
49facff9f   Florian Westphal   netfilter: ebtabl...
1265
  	if (num_counters == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1266
  		return -EINVAL;
49facff9f   Florian Westphal   netfilter: ebtabl...
1267
1268
  	tmp = vmalloc(num_counters * sizeof(*tmp));
  	if (!tmp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1269
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1270

49facff9f   Florian Westphal   netfilter: ebtabl...
1271
  	t = find_table_lock(net, name, &ret, &ebt_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1272
1273
  	if (!t)
  		goto free_tmp;
49facff9f   Florian Westphal   netfilter: ebtabl...
1274
  	if (num_counters != t->private->nentries) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1275
1276
1277
1278
1279
  		BUGPRINT("Wrong nr of counters
  ");
  		ret = -EINVAL;
  		goto unlock_mutex;
  	}
49facff9f   Florian Westphal   netfilter: ebtabl...
1280
  	if (copy_from_user(tmp, counters, num_counters * sizeof(*counters))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1281
1282
1283
1284
1285
1286
1287
1288
  		ret = -EFAULT;
  		goto unlock_mutex;
  	}
  
  	/* we want an atomic add of the counters */
  	write_lock_bh(&t->lock);
  
  	/* we add to the counters of the first cpu */
49facff9f   Florian Westphal   netfilter: ebtabl...
1289
  	for (i = 0; i < num_counters; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1290
1291
1292
1293
1294
1295
1296
  		t->private->counters[i].pcnt += tmp[i].pcnt;
  		t->private->counters[i].bcnt += tmp[i].bcnt;
  	}
  
  	write_unlock_bh(&t->lock);
  	ret = 0;
  unlock_mutex:
57b47a53e   Ingo Molnar   [NET]: sem2mutex ...
1297
  	mutex_unlock(&ebt_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1298
1299
1300
1301
  free_tmp:
  	vfree(tmp);
  	return ret;
  }
49facff9f   Florian Westphal   netfilter: ebtabl...
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
  static int update_counters(struct net *net, const void __user *user,
  			    unsigned int len)
  {
  	struct ebt_replace hlp;
  
  	if (copy_from_user(&hlp, user, sizeof(hlp)))
  		return -EFAULT;
  
  	if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
  		return -EINVAL;
  
  	return do_update_counters(net, hlp.name, hlp.counters,
  				hlp.num_counters, user, len);
  }
d5d1baa15   Jan Engelhardt   netfilter: xtable...
1316
1317
  static inline int ebt_make_matchname(const struct ebt_entry_match *m,
      const char *base, char __user *ubase)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1318
  {
1e419cd99   Al Viro   [EBTABLES]: Split...
1319
  	char __user *hlp = ubase + ((char *)m - base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1320
1321
1322
1323
  	if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
  		return -EFAULT;
  	return 0;
  }
d5d1baa15   Jan Engelhardt   netfilter: xtable...
1324
1325
  static inline int ebt_make_watchername(const struct ebt_entry_watcher *w,
      const char *base, char __user *ubase)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1326
  {
1e419cd99   Al Viro   [EBTABLES]: Split...
1327
  	char __user *hlp = ubase + ((char *)w - base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1328
1329
1330
1331
  	if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
  		return -EFAULT;
  	return 0;
  }
d5d1baa15   Jan Engelhardt   netfilter: xtable...
1332
1333
  static inline int
  ebt_make_names(struct ebt_entry *e, const char *base, char __user *ubase)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1334
1335
  {
  	int ret;
1e419cd99   Al Viro   [EBTABLES]: Split...
1336
  	char __user *hlp;
d5d1baa15   Jan Engelhardt   netfilter: xtable...
1337
  	const struct ebt_entry_target *t;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1338

40642f95f   Al Viro   [EBTABLES]: Verif...
1339
  	if (e->bitmask == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1340
  		return 0;
1e419cd99   Al Viro   [EBTABLES]: Split...
1341
  	hlp = ubase + (((char *)e + e->target_offset) - base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1342
  	t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
9d6f229fc   YOSHIFUJI Hideaki   [NET] BRIDGE: Fix...
1343

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
  	ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
  	if (ret != 0)
  		return ret;
  	ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
  	if (ret != 0)
  		return ret;
  	if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
  		return -EFAULT;
  	return 0;
  }
837395aa8   Florian Westphal   netfilter: ebtabl...
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
  static int copy_counters_to_user(struct ebt_table *t,
  				  const struct ebt_counter *oldcounters,
  				  void __user *user, unsigned int num_counters,
  				  unsigned int nentries)
  {
  	struct ebt_counter *counterstmp;
  	int ret = 0;
  
  	/* userspace might not need the counters */
  	if (num_counters == 0)
  		return 0;
  
  	if (num_counters != nentries) {
  		BUGPRINT("Num_counters wrong
  ");
  		return -EINVAL;
  	}
  
  	counterstmp = vmalloc(nentries * sizeof(*counterstmp));
  	if (!counterstmp)
  		return -ENOMEM;
  
  	write_lock_bh(&t->lock);
  	get_counters(oldcounters, counterstmp, nentries);
  	write_unlock_bh(&t->lock);
  
  	if (copy_to_user(user, counterstmp,
  	   nentries * sizeof(struct ebt_counter)))
  		ret = -EFAULT;
  	vfree(counterstmp);
  	return ret;
  }
57b47a53e   Ingo Molnar   [NET]: sem2mutex ...
1386
  /* called with ebt_mutex locked */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1387
  static int copy_everything_to_user(struct ebt_table *t, void __user *user,
d5d1baa15   Jan Engelhardt   netfilter: xtable...
1388
      const int *len, int cmd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1389
1390
  {
  	struct ebt_replace tmp;
d5d1baa15   Jan Engelhardt   netfilter: xtable...
1391
  	const struct ebt_counter *oldcounters;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1392
  	unsigned int entries_size, nentries;
837395aa8   Florian Westphal   netfilter: ebtabl...
1393
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
  	char *entries;
  
  	if (cmd == EBT_SO_GET_ENTRIES) {
  		entries_size = t->private->entries_size;
  		nentries = t->private->nentries;
  		entries = t->private->entries;
  		oldcounters = t->private->counters;
  	} else {
  		entries_size = t->table->entries_size;
  		nentries = t->table->nentries;
  		entries = t->table->entries;
  		oldcounters = t->table->counters;
  	}
90b89af7e   Florian Westphal   netfilter: ebtabl...
1407
  	if (copy_from_user(&tmp, user, sizeof(tmp)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1408
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1409
1410
  
  	if (*len != sizeof(struct ebt_replace) + entries_size +
90b89af7e   Florian Westphal   netfilter: ebtabl...
1411
  	   (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1412
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
  
  	if (tmp.nentries != nentries) {
  		BUGPRINT("Nentries wrong
  ");
  		return -EINVAL;
  	}
  
  	if (tmp.entries_size != entries_size) {
  		BUGPRINT("Wrong size
  ");
  		return -EINVAL;
  	}
837395aa8   Florian Westphal   netfilter: ebtabl...
1425
1426
1427
1428
  	ret = copy_counters_to_user(t, oldcounters, tmp.counters,
  					tmp.num_counters, nentries);
  	if (ret)
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
  
  	if (copy_to_user(tmp.entries, entries, entries_size)) {
  		BUGPRINT("Couldn't copy entries to userspace
  ");
  		return -EFAULT;
  	}
  	/* set the match/watcher/target names right */
  	return EBT_ENTRY_ITERATE(entries, entries_size,
  	   ebt_make_names, entries, tmp.entries);
  }
  
  static int do_ebt_set_ctl(struct sock *sk,
  	int cmd, void __user *user, unsigned int len)
  {
  	int ret;
dce766af5   Florian Westphal   netfilter: ebtabl...
1444
1445
  	if (!capable(CAP_NET_ADMIN))
  		return -EPERM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1446
1447
  	switch(cmd) {
  	case EBT_SO_SET_ENTRIES:
511061e2d   Alexey Dobriyan   netfilter: netns ...
1448
  		ret = do_replace(sock_net(sk), user, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1449
1450
  		break;
  	case EBT_SO_SET_COUNTERS:
511061e2d   Alexey Dobriyan   netfilter: netns ...
1451
  		ret = update_counters(sock_net(sk), user, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1452
1453
1454
  		break;
  	default:
  		ret = -EINVAL;
81e675c22   Florian Westphal   netfilter: ebtabl...
1455
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1456
1457
1458
1459
1460
1461
1462
1463
  	return ret;
  }
  
  static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
  {
  	int ret;
  	struct ebt_replace tmp;
  	struct ebt_table *t;
dce766af5   Florian Westphal   netfilter: ebtabl...
1464
1465
  	if (!capable(CAP_NET_ADMIN))
  		return -EPERM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1466
1467
  	if (copy_from_user(&tmp, user, sizeof(tmp)))
  		return -EFAULT;
511061e2d   Alexey Dobriyan   netfilter: netns ...
1468
  	t = find_table_lock(sock_net(sk), tmp.name, &ret, &ebt_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1469
1470
1471
1472
1473
1474
1475
1476
  	if (!t)
  		return ret;
  
  	switch(cmd) {
  	case EBT_SO_GET_INFO:
  	case EBT_SO_GET_INIT_INFO:
  		if (*len != sizeof(struct ebt_replace)){
  			ret = -EINVAL;
57b47a53e   Ingo Molnar   [NET]: sem2mutex ...
1477
  			mutex_unlock(&ebt_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
  			break;
  		}
  		if (cmd == EBT_SO_GET_INFO) {
  			tmp.nentries = t->private->nentries;
  			tmp.entries_size = t->private->entries_size;
  			tmp.valid_hooks = t->valid_hooks;
  		} else {
  			tmp.nentries = t->table->nentries;
  			tmp.entries_size = t->table->entries_size;
  			tmp.valid_hooks = t->table->valid_hooks;
  		}
57b47a53e   Ingo Molnar   [NET]: sem2mutex ...
1489
  		mutex_unlock(&ebt_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
  		if (copy_to_user(user, &tmp, *len) != 0){
  			BUGPRINT("c2u Didn't work
  ");
  			ret = -EFAULT;
  			break;
  		}
  		ret = 0;
  		break;
  
  	case EBT_SO_GET_ENTRIES:
  	case EBT_SO_GET_INIT_ENTRIES:
  		ret = copy_everything_to_user(t, user, len, cmd);
57b47a53e   Ingo Molnar   [NET]: sem2mutex ...
1502
  		mutex_unlock(&ebt_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1503
1504
1505
  		break;
  
  	default:
57b47a53e   Ingo Molnar   [NET]: sem2mutex ...
1506
  		mutex_unlock(&ebt_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1507
1508
1509
1510
1511
  		ret = -EINVAL;
  	}
  
  	return ret;
  }
81e675c22   Florian Westphal   netfilter: ebtabl...
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
  #ifdef CONFIG_COMPAT
  /* 32 bit-userspace compatibility definitions. */
  struct compat_ebt_replace {
  	char name[EBT_TABLE_MAXNAMELEN];
  	compat_uint_t valid_hooks;
  	compat_uint_t nentries;
  	compat_uint_t entries_size;
  	/* start of the chains */
  	compat_uptr_t hook_entry[NF_BR_NUMHOOKS];
  	/* nr of counters userspace expects back */
  	compat_uint_t num_counters;
  	/* where the kernel will put the old counters. */
  	compat_uptr_t counters;
  	compat_uptr_t entries;
  };
  
  /* struct ebt_entry_match, _target and _watcher have same layout */
  struct compat_ebt_entry_mwt {
  	union {
  		char name[EBT_FUNCTION_MAXNAMELEN];
  		compat_uptr_t ptr;
  	} u;
  	compat_uint_t match_size;
  	compat_uint_t data[0];
  };
  
  /* account for possible padding between match_size and ->data */
  static int ebt_compat_entry_padsize(void)
  {
  	BUILD_BUG_ON(XT_ALIGN(sizeof(struct ebt_entry_match)) <
  			COMPAT_XT_ALIGN(sizeof(struct compat_ebt_entry_mwt)));
  	return (int) XT_ALIGN(sizeof(struct ebt_entry_match)) -
  			COMPAT_XT_ALIGN(sizeof(struct compat_ebt_entry_mwt));
  }
  
  static int ebt_compat_match_offset(const struct xt_match *match,
  				   unsigned int userlen)
  {
  	/*
  	 * ebt_among needs special handling. The kernel .matchsize is
  	 * set to -1 at registration time; at runtime an EBT_ALIGN()ed
  	 * value is expected.
  	 * Example: userspace sends 4500, ebt_among.c wants 4504.
  	 */
  	if (unlikely(match->matchsize == -1))
  		return XT_ALIGN(userlen) - COMPAT_XT_ALIGN(userlen);
  	return xt_compat_match_offset(match);
  }
  
  static int compat_match_to_user(struct ebt_entry_match *m, void __user **dstptr,
  				unsigned int *size)
  {
  	const struct xt_match *match = m->u.match;
  	struct compat_ebt_entry_mwt __user *cm = *dstptr;
  	int off = ebt_compat_match_offset(match, m->match_size);
  	compat_uint_t msize = m->match_size - off;
  
  	BUG_ON(off >= m->match_size);
  
  	if (copy_to_user(cm->u.name, match->name,
  	    strlen(match->name) + 1) || put_user(msize, &cm->match_size))
  		return -EFAULT;
  
  	if (match->compat_to_user) {
  		if (match->compat_to_user(cm->data, m->data))
  			return -EFAULT;
  	} else if (copy_to_user(cm->data, m->data, msize))
  			return -EFAULT;
  
  	*size -= ebt_compat_entry_padsize() + off;
  	*dstptr = cm->data;
  	*dstptr += msize;
  	return 0;
  }
  
  static int compat_target_to_user(struct ebt_entry_target *t,
  				 void __user **dstptr,
  				 unsigned int *size)
  {
  	const struct xt_target *target = t->u.target;
  	struct compat_ebt_entry_mwt __user *cm = *dstptr;
  	int off = xt_compat_target_offset(target);
  	compat_uint_t tsize = t->target_size - off;
  
  	BUG_ON(off >= t->target_size);
  
  	if (copy_to_user(cm->u.name, target->name,
  	    strlen(target->name) + 1) || put_user(tsize, &cm->match_size))
  		return -EFAULT;
  
  	if (target->compat_to_user) {
  		if (target->compat_to_user(cm->data, t->data))
  			return -EFAULT;
  	} else if (copy_to_user(cm->data, t->data, tsize))
  		return -EFAULT;
  
  	*size -= ebt_compat_entry_padsize() + off;
  	*dstptr = cm->data;
  	*dstptr += tsize;
  	return 0;
  }
  
  static int compat_watcher_to_user(struct ebt_entry_watcher *w,
  				  void __user **dstptr,
  				  unsigned int *size)
  {
  	return compat_target_to_user((struct ebt_entry_target *)w,
  							dstptr, size);
  }
  
  static int compat_copy_entry_to_user(struct ebt_entry *e, void __user **dstptr,
  				unsigned int *size)
  {
  	struct ebt_entry_target *t;
  	struct ebt_entry __user *ce;
  	u32 watchers_offset, target_offset, next_offset;
  	compat_uint_t origsize;
  	int ret;
  
  	if (e->bitmask == 0) {
  		if (*size < sizeof(struct ebt_entries))
  			return -EINVAL;
  		if (copy_to_user(*dstptr, e, sizeof(struct ebt_entries)))
  			return -EFAULT;
  
  		*dstptr += sizeof(struct ebt_entries);
  		*size -= sizeof(struct ebt_entries);
  		return 0;
  	}
  
  	if (*size < sizeof(*ce))
  		return -EINVAL;
  
  	ce = (struct ebt_entry __user *)*dstptr;
  	if (copy_to_user(ce, e, sizeof(*ce)))
  		return -EFAULT;
  
  	origsize = *size;
  	*dstptr += sizeof(*ce);
  
  	ret = EBT_MATCH_ITERATE(e, compat_match_to_user, dstptr, size);
  	if (ret)
  		return ret;
  	watchers_offset = e->watchers_offset - (origsize - *size);
  
  	ret = EBT_WATCHER_ITERATE(e, compat_watcher_to_user, dstptr, size);
  	if (ret)
  		return ret;
  	target_offset = e->target_offset - (origsize - *size);
  
  	t = (struct ebt_entry_target *) ((char *) e + e->target_offset);
  
  	ret = compat_target_to_user(t, dstptr, size);
  	if (ret)
  		return ret;
  	next_offset = e->next_offset - (origsize - *size);
  
  	if (put_user(watchers_offset, &ce->watchers_offset) ||
  	    put_user(target_offset, &ce->target_offset) ||
  	    put_user(next_offset, &ce->next_offset))
  		return -EFAULT;
  
  	*size -= sizeof(*ce);
  	return 0;
  }
  
  static int compat_calc_match(struct ebt_entry_match *m, int *off)
  {
  	*off += ebt_compat_match_offset(m->u.match, m->match_size);
  	*off += ebt_compat_entry_padsize();
  	return 0;
  }
  
  static int compat_calc_watcher(struct ebt_entry_watcher *w, int *off)
  {
  	*off += xt_compat_target_offset(w->u.watcher);
  	*off += ebt_compat_entry_padsize();
  	return 0;
  }
  
  static int compat_calc_entry(const struct ebt_entry *e,
  			     const struct ebt_table_info *info,
  			     const void *base,
  			     struct compat_ebt_replace *newinfo)
  {
  	const struct ebt_entry_target *t;
  	unsigned int entry_offset;
  	int off, ret, i;
  
  	if (e->bitmask == 0)
  		return 0;
  
  	off = 0;
  	entry_offset = (void *)e - base;
  
  	EBT_MATCH_ITERATE(e, compat_calc_match, &off);
  	EBT_WATCHER_ITERATE(e, compat_calc_watcher, &off);
  
  	t = (const struct ebt_entry_target *) ((char *) e + e->target_offset);
  
  	off += xt_compat_target_offset(t->u.target);
  	off += ebt_compat_entry_padsize();
  
  	newinfo->entries_size -= off;
  
  	ret = xt_compat_add_offset(NFPROTO_BRIDGE, entry_offset, off);
  	if (ret)
  		return ret;
  
  	for (i = 0; i < NF_BR_NUMHOOKS; i++) {
  		const void *hookptr = info->hook_entry[i];
  		if (info->hook_entry[i] &&
  		    (e < (struct ebt_entry *)(base - hookptr))) {
  			newinfo->hook_entry[i] -= off;
  			pr_debug("0x%08X -> 0x%08X
  ",
  					newinfo->hook_entry[i] + off,
  					newinfo->hook_entry[i]);
  		}
  	}
  
  	return 0;
  }
  
  
  static int compat_table_info(const struct ebt_table_info *info,
  			     struct compat_ebt_replace *newinfo)
  {
  	unsigned int size = info->entries_size;
  	const void *entries = info->entries;
  
  	newinfo->entries_size = size;
5a6351eec   Eric Dumazet   netfilter: fix eb...
1744
  	xt_compat_init_offsets(NFPROTO_BRIDGE, info->nentries);
81e675c22   Florian Westphal   netfilter: ebtabl...
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
  	return EBT_ENTRY_ITERATE(entries, size, compat_calc_entry, info,
  							entries, newinfo);
  }
  
  static int compat_copy_everything_to_user(struct ebt_table *t,
  					  void __user *user, int *len, int cmd)
  {
  	struct compat_ebt_replace repl, tmp;
  	struct ebt_counter *oldcounters;
  	struct ebt_table_info tinfo;
  	int ret;
  	void __user *pos;
  
  	memset(&tinfo, 0, sizeof(tinfo));
  
  	if (cmd == EBT_SO_GET_ENTRIES) {
  		tinfo.entries_size = t->private->entries_size;
  		tinfo.nentries = t->private->nentries;
  		tinfo.entries = t->private->entries;
  		oldcounters = t->private->counters;
  	} else {
  		tinfo.entries_size = t->table->entries_size;
  		tinfo.nentries = t->table->nentries;
  		tinfo.entries = t->table->entries;
  		oldcounters = t->table->counters;
  	}
  
  	if (copy_from_user(&tmp, user, sizeof(tmp)))
  		return -EFAULT;
  
  	if (tmp.nentries != tinfo.nentries ||
  	   (tmp.num_counters && tmp.num_counters != tinfo.nentries))
  		return -EINVAL;
  
  	memcpy(&repl, &tmp, sizeof(repl));
  	if (cmd == EBT_SO_GET_ENTRIES)
  		ret = compat_table_info(t->private, &repl);
  	else
  		ret = compat_table_info(&tinfo, &repl);
  	if (ret)
  		return ret;
  
  	if (*len != sizeof(tmp) + repl.entries_size +
  	   (tmp.num_counters? tinfo.nentries * sizeof(struct ebt_counter): 0)) {
  		pr_err("wrong size: *len %d, entries_size %u, replsz %d
  ",
  				*len, tinfo.entries_size, repl.entries_size);
  		return -EINVAL;
  	}
  
  	/* userspace might not need the counters */
  	ret = copy_counters_to_user(t, oldcounters, compat_ptr(tmp.counters),
  					tmp.num_counters, tinfo.nentries);
  	if (ret)
  		return ret;
  
  	pos = compat_ptr(tmp.entries);
  	return EBT_ENTRY_ITERATE(tinfo.entries, tinfo.entries_size,
  			compat_copy_entry_to_user, &pos, &tmp.entries_size);
  }
  
  struct ebt_entries_buf_state {
  	char *buf_kern_start;	/* kernel buffer to copy (translated) data to */
  	u32 buf_kern_len;	/* total size of kernel buffer */
  	u32 buf_kern_offset;	/* amount of data copied so far */
  	u32 buf_user_offset;	/* read position in userspace buffer */
  };
  
  static int ebt_buf_count(struct ebt_entries_buf_state *state, unsigned int sz)
  {
  	state->buf_kern_offset += sz;
  	return state->buf_kern_offset >= sz ? 0 : -EINVAL;
  }
  
  static int ebt_buf_add(struct ebt_entries_buf_state *state,
  		       void *data, unsigned int sz)
  {
  	if (state->buf_kern_start == NULL)
  		goto count_only;
  
  	BUG_ON(state->buf_kern_offset + sz > state->buf_kern_len);
  
  	memcpy(state->buf_kern_start + state->buf_kern_offset, data, sz);
  
   count_only:
  	state->buf_user_offset += sz;
  	return ebt_buf_count(state, sz);
  }
  
  static int ebt_buf_add_pad(struct ebt_entries_buf_state *state, unsigned int sz)
  {
  	char *b = state->buf_kern_start;
  
  	BUG_ON(b && state->buf_kern_offset > state->buf_kern_len);
  
  	if (b != NULL && sz > 0)
  		memset(b + state->buf_kern_offset, 0, sz);
  	/* do not adjust ->buf_user_offset here, we added kernel-side padding */
  	return ebt_buf_count(state, sz);
  }
  
  enum compat_mwt {
  	EBT_COMPAT_MATCH,
  	EBT_COMPAT_WATCHER,
  	EBT_COMPAT_TARGET,
  };
  
  static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt,
  				enum compat_mwt compat_mwt,
  				struct ebt_entries_buf_state *state,
  				const unsigned char *base)
  {
  	char name[EBT_FUNCTION_MAXNAMELEN];
  	struct xt_match *match;
  	struct xt_target *wt;
  	void *dst = NULL;
103a9778e   Florian Westphal   netfilter: ebtabl...
1861
  	int off, pad = 0;
97242c85a   David Miller   netfilter: Fix se...
1862
  	unsigned int size_kern, match_size = mwt->match_size;
81e675c22   Florian Westphal   netfilter: ebtabl...
1863
1864
1865
1866
1867
  
  	strlcpy(name, mwt->u.name, sizeof(name));
  
  	if (state->buf_kern_start)
  		dst = state->buf_kern_start + state->buf_kern_offset;
81e675c22   Florian Westphal   netfilter: ebtabl...
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
  	switch (compat_mwt) {
  	case EBT_COMPAT_MATCH:
  		match = try_then_request_module(xt_find_match(NFPROTO_BRIDGE,
  						name, 0), "ebt_%s", name);
  		if (match == NULL)
  			return -ENOENT;
  		if (IS_ERR(match))
  			return PTR_ERR(match);
  
  		off = ebt_compat_match_offset(match, match_size);
  		if (dst) {
  			if (match->compat_from_user)
  				match->compat_from_user(dst, mwt->data);
  			else
  				memcpy(dst, mwt->data, match_size);
  		}
  
  		size_kern = match->matchsize;
  		if (unlikely(size_kern == -1))
  			size_kern = match_size;
  		module_put(match->me);
  		break;
  	case EBT_COMPAT_WATCHER: /* fallthrough */
  	case EBT_COMPAT_TARGET:
  		wt = try_then_request_module(xt_find_target(NFPROTO_BRIDGE,
  						name, 0), "ebt_%s", name);
  		if (wt == NULL)
  			return -ENOENT;
  		if (IS_ERR(wt))
  			return PTR_ERR(wt);
  		off = xt_compat_target_offset(wt);
  
  		if (dst) {
  			if (wt->compat_from_user)
  				wt->compat_from_user(dst, mwt->data);
  			else
  				memcpy(dst, mwt->data, match_size);
  		}
  
  		size_kern = wt->targetsize;
  		module_put(wt->me);
  		break;
97242c85a   David Miller   netfilter: Fix se...
1910
1911
1912
  
  	default:
  		return -EINVAL;
81e675c22   Florian Westphal   netfilter: ebtabl...
1913
  	}
81e675c22   Florian Westphal   netfilter: ebtabl...
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
  	state->buf_kern_offset += match_size + off;
  	state->buf_user_offset += match_size;
  	pad = XT_ALIGN(size_kern) - size_kern;
  
  	if (pad > 0 && dst) {
  		BUG_ON(state->buf_kern_len <= pad);
  		BUG_ON(state->buf_kern_offset - (match_size + off) + size_kern > state->buf_kern_len - pad);
  		memset(dst + size_kern, 0, pad);
  	}
  	return off + match_size;
  }
  
  /*
   * return size of all matches, watchers or target, including necessary
   * alignment and padding.
   */
  static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32,
  			unsigned int size_left, enum compat_mwt type,
  			struct ebt_entries_buf_state *state, const void *base)
  {
  	int growth = 0;
  	char *buf;
  
  	if (size_left == 0)
  		return 0;
  
  	buf = (char *) match32;
  
  	while (size_left >= sizeof(*match32)) {
  		struct ebt_entry_match *match_kern;
  		int ret;
  
  		match_kern = (struct ebt_entry_match *) state->buf_kern_start;
  		if (match_kern) {
  			char *tmp;
  			tmp = state->buf_kern_start + state->buf_kern_offset;
  			match_kern = (struct ebt_entry_match *) tmp;
  		}
  		ret = ebt_buf_add(state, buf, sizeof(*match32));
  		if (ret < 0)
  			return ret;
  		size_left -= sizeof(*match32);
  
  		/* add padding before match->data (if any) */
  		ret = ebt_buf_add_pad(state, ebt_compat_entry_padsize());
  		if (ret < 0)
  			return ret;
  
  		if (match32->match_size > size_left)
  			return -EINVAL;
  
  		size_left -= match32->match_size;
  
  		ret = compat_mtw_from_user(match32, type, state, base);
  		if (ret < 0)
  			return ret;
  
  		BUG_ON(ret < match32->match_size);
  		growth += ret - match32->match_size;
  		growth += ebt_compat_entry_padsize();
  
  		buf += sizeof(*match32);
  		buf += match32->match_size;
  
  		if (match_kern)
  			match_kern->match_size = ret;
  
  		WARN_ON(type == EBT_COMPAT_TARGET && size_left);
  		match32 = (struct compat_ebt_entry_mwt *) buf;
  	}
  
  	return growth;
  }
81e675c22   Florian Westphal   netfilter: ebtabl...
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
  /* called for all ebt_entry structures. */
  static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base,
  			  unsigned int *total,
  			  struct ebt_entries_buf_state *state)
  {
  	unsigned int i, j, startoff, new_offset = 0;
  	/* stores match/watchers/targets & offset of next struct ebt_entry: */
  	unsigned int offsets[4];
  	unsigned int *offsets_update = NULL;
  	int ret;
  	char *buf_start;
  
  	if (*total < sizeof(struct ebt_entries))
  		return -EINVAL;
  
  	if (!entry->bitmask) {
  		*total -= sizeof(struct ebt_entries);
  		return ebt_buf_add(state, entry, sizeof(struct ebt_entries));
  	}
  	if (*total < sizeof(*entry) || entry->next_offset < sizeof(*entry))
  		return -EINVAL;
  
  	startoff = state->buf_user_offset;
  	/* pull in most part of ebt_entry, it does not need to be changed. */
  	ret = ebt_buf_add(state, entry,
  			offsetof(struct ebt_entry, watchers_offset));
  	if (ret < 0)
  		return ret;
  
  	offsets[0] = sizeof(struct ebt_entry); /* matches come first */
  	memcpy(&offsets[1], &entry->watchers_offset,
  			sizeof(offsets) - sizeof(offsets[0]));
  
  	if (state->buf_kern_start) {
  		buf_start = state->buf_kern_start + state->buf_kern_offset;
  		offsets_update = (unsigned int *) buf_start;
  	}
  	ret = ebt_buf_add(state, &offsets[1],
  			sizeof(offsets) - sizeof(offsets[0]));
  	if (ret < 0)
  		return ret;
  	buf_start = (char *) entry;
  	/*
  	 * 0: matches offset, always follows ebt_entry.
  	 * 1: watchers offset, from ebt_entry structure
  	 * 2: target offset, from ebt_entry structure
  	 * 3: next ebt_entry offset, from ebt_entry structure
  	 *
  	 * offsets are relative to beginning of struct ebt_entry (i.e., 0).
  	 */
  	for (i = 0, j = 1 ; j < 4 ; j++, i++) {
  		struct compat_ebt_entry_mwt *match32;
  		unsigned int size;
  		char *buf = buf_start;
  
  		buf = buf_start + offsets[i];
  		if (offsets[i] > offsets[j])
  			return -EINVAL;
  
  		match32 = (struct compat_ebt_entry_mwt *) buf;
  		size = offsets[j] - offsets[i];
  		ret = ebt_size_mwt(match32, size, i, state, base);
  		if (ret < 0)
  			return ret;
  		new_offset += ret;
  		if (offsets_update && new_offset) {
ff67e4e42   Jan Engelhardt   netfilter: xt ext...
2053
2054
  			pr_debug("change offset %d to %d
  ",
81e675c22   Florian Westphal   netfilter: ebtabl...
2055
2056
2057
2058
  				offsets_update[i], offsets[j] + new_offset);
  			offsets_update[i] = offsets[j] + new_offset;
  		}
  	}
103a9778e   Florian Westphal   netfilter: ebtabl...
2059
2060
2061
2062
2063
2064
2065
  	if (state->buf_kern_start == NULL) {
  		unsigned int offset = buf_start - (char *) base;
  
  		ret = xt_compat_add_offset(NFPROTO_BRIDGE, offset, new_offset);
  		if (ret < 0)
  			return ret;
  	}
81e675c22   Florian Westphal   netfilter: ebtabl...
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
  	startoff = state->buf_user_offset - startoff;
  
  	BUG_ON(*total < startoff);
  	*total -= startoff;
  	return 0;
  }
  
  /*
   * repl->entries_size is the size of the ebt_entry blob in userspace.
   * It might need more memory when copied to a 64 bit kernel in case
   * userspace is 32-bit. So, first task: find out how much memory is needed.
   *
   * Called before validation is performed.
   */
  static int compat_copy_entries(unsigned char *data, unsigned int size_user,
  				struct ebt_entries_buf_state *state)
  {
  	unsigned int size_remaining = size_user;
  	int ret;
  
  	ret = EBT_ENTRY_ITERATE(data, size_user, size_entry_mwt, data,
  					&size_remaining, state);
  	if (ret < 0)
  		return ret;
  
  	WARN_ON(size_remaining);
  	return state->buf_kern_offset;
  }
  
  
  static int compat_copy_ebt_replace_from_user(struct ebt_replace *repl,
  					    void __user *user, unsigned int len)
  {
  	struct compat_ebt_replace tmp;
  	int i;
  
  	if (len < sizeof(tmp))
  		return -EINVAL;
  
  	if (copy_from_user(&tmp, user, sizeof(tmp)))
  		return -EFAULT;
  
  	if (len != sizeof(tmp) + tmp.entries_size)
  		return -EINVAL;
  
  	if (tmp.entries_size == 0)
  		return -EINVAL;
  
  	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;
  
  	memcpy(repl, &tmp, offsetof(struct ebt_replace, hook_entry));
  
  	/* starting with hook_entry, 32 vs. 64 bit structures are different */
  	for (i = 0; i < NF_BR_NUMHOOKS; i++)
  		repl->hook_entry[i] = compat_ptr(tmp.hook_entry[i]);
  
  	repl->num_counters = tmp.num_counters;
  	repl->counters = compat_ptr(tmp.counters);
  	repl->entries = compat_ptr(tmp.entries);
  	return 0;
  }
  
  static int compat_do_replace(struct net *net, void __user *user,
  			     unsigned int len)
  {
  	int ret, i, countersize, size64;
  	struct ebt_table_info *newinfo;
  	struct ebt_replace tmp;
  	struct ebt_entries_buf_state state;
  	void *entries_tmp;
  
  	ret = compat_copy_ebt_replace_from_user(&tmp, user, len);
90b89af7e   Florian Westphal   netfilter: ebtabl...
2142
2143
2144
2145
  	if (ret) {
  		/* try real handler in case userland supplied needed padding */
  		if (ret == -EINVAL && do_replace(net, user, len) == 0)
  			ret = 0;
81e675c22   Florian Westphal   netfilter: ebtabl...
2146
  		return ret;
90b89af7e   Florian Westphal   netfilter: ebtabl...
2147
  	}
81e675c22   Florian Westphal   netfilter: ebtabl...
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
  
  	countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
  	newinfo = vmalloc(sizeof(*newinfo) + countersize);
  	if (!newinfo)
  		return -ENOMEM;
  
  	if (countersize)
  		memset(newinfo->counters, 0, countersize);
  
  	memset(&state, 0, sizeof(state));
  
  	newinfo->entries = vmalloc(tmp.entries_size);
  	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;
  	}
  
  	entries_tmp = newinfo->entries;
  
  	xt_compat_lock(NFPROTO_BRIDGE);
5a6351eec   Eric Dumazet   netfilter: fix eb...
2173
  	xt_compat_init_offsets(NFPROTO_BRIDGE, tmp.nentries);
81e675c22   Florian Westphal   netfilter: ebtabl...
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
  	ret = compat_copy_entries(entries_tmp, tmp.entries_size, &state);
  	if (ret < 0)
  		goto out_unlock;
  
  	pr_debug("tmp.entries_size %d, kern off %d, user off %d delta %d
  ",
  		tmp.entries_size, state.buf_kern_offset, state.buf_user_offset,
  		xt_compat_calc_jump(NFPROTO_BRIDGE, tmp.entries_size));
  
  	size64 = ret;
  	newinfo->entries = vmalloc(size64);
  	if (!newinfo->entries) {
  		vfree(entries_tmp);
  		ret = -ENOMEM;
  		goto out_unlock;
  	}
  
  	memset(&state, 0, sizeof(state));
  	state.buf_kern_start = newinfo->entries;
  	state.buf_kern_len = size64;
  
  	ret = compat_copy_entries(entries_tmp, tmp.entries_size, &state);
  	BUG_ON(ret < 0);	/* parses same data again */
  
  	vfree(entries_tmp);
  	tmp.entries_size = size64;
  
  	for (i = 0; i < NF_BR_NUMHOOKS; i++) {
  		char __user *usrptr;
  		if (tmp.hook_entry[i]) {
  			unsigned int delta;
  			usrptr = (char __user *) tmp.hook_entry[i];
  			delta = usrptr - tmp.entries;
  			usrptr += xt_compat_calc_jump(NFPROTO_BRIDGE, delta);
  			tmp.hook_entry[i] = (struct ebt_entries __user *)usrptr;
  		}
  	}
  
  	xt_compat_flush_offsets(NFPROTO_BRIDGE);
  	xt_compat_unlock(NFPROTO_BRIDGE);
  
  	ret = do_replace_finish(net, &tmp, newinfo);
  	if (ret == 0)
  		return ret;
  free_entries:
  	vfree(newinfo->entries);
  free_newinfo:
  	vfree(newinfo);
  	return ret;
  out_unlock:
  	xt_compat_flush_offsets(NFPROTO_BRIDGE);
  	xt_compat_unlock(NFPROTO_BRIDGE);
  	goto free_entries;
  }
  
  static int compat_update_counters(struct net *net, void __user *user,
  				  unsigned int len)
  {
  	struct compat_ebt_replace hlp;
  
  	if (copy_from_user(&hlp, user, sizeof(hlp)))
  		return -EFAULT;
90b89af7e   Florian Westphal   netfilter: ebtabl...
2236
  	/* try real handler in case userland supplied needed padding */
81e675c22   Florian Westphal   netfilter: ebtabl...
2237
  	if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
90b89af7e   Florian Westphal   netfilter: ebtabl...
2238
  		return update_counters(net, user, len);
81e675c22   Florian Westphal   netfilter: ebtabl...
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
  
  	return do_update_counters(net, hlp.name, compat_ptr(hlp.counters),
  					hlp.num_counters, user, len);
  }
  
  static int compat_do_ebt_set_ctl(struct sock *sk,
  		int cmd, void __user *user, unsigned int len)
  {
  	int ret;
  
  	if (!capable(CAP_NET_ADMIN))
  		return -EPERM;
  
  	switch (cmd) {
  	case EBT_SO_SET_ENTRIES:
  		ret = compat_do_replace(sock_net(sk), user, len);
  		break;
  	case EBT_SO_SET_COUNTERS:
  		ret = compat_update_counters(sock_net(sk), user, len);
  		break;
  	default:
  		ret = -EINVAL;
    }
  	return ret;
  }
  
  static int compat_do_ebt_get_ctl(struct sock *sk, int cmd,
  		void __user *user, int *len)
  {
  	int ret;
  	struct compat_ebt_replace tmp;
  	struct ebt_table *t;
  
  	if (!capable(CAP_NET_ADMIN))
  		return -EPERM;
90b89af7e   Florian Westphal   netfilter: ebtabl...
2274
  	/* try real handler in case userland supplied needed padding */
81e675c22   Florian Westphal   netfilter: ebtabl...
2275
2276
  	if ((cmd == EBT_SO_GET_INFO ||
  	     cmd == EBT_SO_GET_INIT_INFO) && *len != sizeof(tmp))
90b89af7e   Florian Westphal   netfilter: ebtabl...
2277
  			return do_ebt_get_ctl(sk, cmd, user, len);
81e675c22   Florian Westphal   netfilter: ebtabl...
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
  
  	if (copy_from_user(&tmp, user, sizeof(tmp)))
  		return -EFAULT;
  
  	t = find_table_lock(sock_net(sk), tmp.name, &ret, &ebt_mutex);
  	if (!t)
  		return ret;
  
  	xt_compat_lock(NFPROTO_BRIDGE);
  	switch (cmd) {
  	case EBT_SO_GET_INFO:
  		tmp.nentries = t->private->nentries;
  		ret = compat_table_info(t->private, &tmp);
  		if (ret)
  			goto out;
  		tmp.valid_hooks = t->valid_hooks;
  
  		if (copy_to_user(user, &tmp, *len) != 0) {
  			ret = -EFAULT;
  			break;
  		}
  		ret = 0;
  		break;
  	case EBT_SO_GET_INIT_INFO:
  		tmp.nentries = t->table->nentries;
  		tmp.entries_size = t->table->entries_size;
  		tmp.valid_hooks = t->table->valid_hooks;
  
  		if (copy_to_user(user, &tmp, *len) != 0) {
  			ret = -EFAULT;
  			break;
  		}
  		ret = 0;
  		break;
  	case EBT_SO_GET_ENTRIES:
  	case EBT_SO_GET_INIT_ENTRIES:
90b89af7e   Florian Westphal   netfilter: ebtabl...
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
  		/*
  		 * try real handler first in case of userland-side padding.
  		 * in case we are dealing with an 'ordinary' 32 bit binary
  		 * without 64bit compatibility padding, this will fail right
  		 * after copy_from_user when the *len argument is validated.
  		 *
  		 * the compat_ variant needs to do one pass over the kernel
  		 * data set to adjust for size differences before it the check.
  		 */
  		if (copy_everything_to_user(t, user, len, cmd) == 0)
  			ret = 0;
  		else
  			ret = compat_copy_everything_to_user(t, user, len, cmd);
81e675c22   Florian Westphal   netfilter: ebtabl...
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
  		break;
  	default:
  		ret = -EINVAL;
  	}
   out:
  	xt_compat_flush_offsets(NFPROTO_BRIDGE);
  	xt_compat_unlock(NFPROTO_BRIDGE);
  	mutex_unlock(&ebt_mutex);
  	return ret;
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2338
  static struct nf_sockopt_ops ebt_sockopts =
74ca4e5ac   Andrew Morton   [BRIDGE] ebtables...
2339
2340
2341
2342
2343
  {
  	.pf		= PF_INET,
  	.set_optmin	= EBT_BASE_CTL,
  	.set_optmax	= EBT_SO_SET_MAX + 1,
  	.set		= do_ebt_set_ctl,
81e675c22   Florian Westphal   netfilter: ebtabl...
2344
2345
2346
  #ifdef CONFIG_COMPAT
  	.compat_set	= compat_do_ebt_set_ctl,
  #endif
74ca4e5ac   Andrew Morton   [BRIDGE] ebtables...
2347
2348
2349
  	.get_optmin	= EBT_BASE_CTL,
  	.get_optmax	= EBT_SO_GET_MAX + 1,
  	.get		= do_ebt_get_ctl,
81e675c22   Florian Westphal   netfilter: ebtabl...
2350
2351
2352
  #ifdef CONFIG_COMPAT
  	.compat_get	= compat_do_ebt_get_ctl,
  #endif
16fcec35e   Neil Horman   [NETFILTER]: Fix/...
2353
  	.owner		= THIS_MODULE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2354
  };
65b4b4e81   Andrew Morton   [NETFILTER]: Rena...
2355
  static int __init ebtables_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2356
2357
  {
  	int ret;
043ef46c7   Jan Engelhardt   netfilter: move E...
2358
2359
  	ret = xt_register_target(&ebt_standard_target);
  	if (ret < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2360
  		return ret;
043ef46c7   Jan Engelhardt   netfilter: move E...
2361
2362
2363
2364
2365
  	ret = nf_register_sockopt(&ebt_sockopts);
  	if (ret < 0) {
  		xt_unregister_target(&ebt_standard_target);
  		return ret;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2366

a887c1c14   Patrick McHardy   [NETFILTER]: Lowe...
2367
2368
  	printk(KERN_INFO "Ebtables v2.0 registered
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2369
2370
  	return 0;
  }
65b4b4e81   Andrew Morton   [NETFILTER]: Rena...
2371
  static void __exit ebtables_fini(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2372
2373
  {
  	nf_unregister_sockopt(&ebt_sockopts);
043ef46c7   Jan Engelhardt   netfilter: move E...
2374
  	xt_unregister_target(&ebt_standard_target);
a887c1c14   Patrick McHardy   [NETFILTER]: Lowe...
2375
2376
  	printk(KERN_INFO "Ebtables v2.0 unregistered
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2377
2378
2379
2380
  }
  
  EXPORT_SYMBOL(ebt_register_table);
  EXPORT_SYMBOL(ebt_unregister_table);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2381
  EXPORT_SYMBOL(ebt_do_table);
65b4b4e81   Andrew Morton   [NETFILTER]: Rena...
2382
2383
  module_init(ebtables_init);
  module_exit(ebtables_fini);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2384
  MODULE_LICENSE("GPL");