blob: 1aa0e4c1f52d8758e57de754896aaec13e7b24cc [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * ebtables
3 *
4 * Author:
5 * Bart De Schuymer <bdschuym@pandora.be>
6 *
7 * ebtables.c,v 2.0, July, 2002
8 *
9 * This code is stongly inspired on the iptables code which is
10 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version
15 * 2 of the License, or (at your option) any later version.
16 */
17
Linus Torvalds1da177e2005-04-16 15:20:36 -070018
19#include <linux/kmod.h>
20#include <linux/module.h>
21#include <linux/vmalloc.h>
Jan Engelhardt18219d32008-10-08 11:35:13 +020022#include <linux/netfilter/x_tables.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/netfilter_bridge/ebtables.h>
24#include <linux/spinlock.h>
Patrick McHardydf0933d2006-09-20 11:57:53 -070025#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <asm/uaccess.h>
27#include <linux/smp.h>
David S. Millerc8923c62005-10-13 14:41:23 -070028#include <linux/cpumask.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <net/sock.h>
30/* needed for logical [in,out]-dev filtering */
31#include "../br_private.h"
32
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +090034 "report to author: "format, ## args)
Linus Torvalds1da177e2005-04-16 15:20:36 -070035/* #define BUGPRINT(format, args...) */
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#define MEMPRINT(format, args...) printk("kernel msg: ebtables "\
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +090037 ": out of memory: "format, ## args)
Linus Torvalds1da177e2005-04-16 15:20:36 -070038/* #define MEMPRINT(format, args...) */
39
40
41
42/*
43 * Each cpu has its own set of counters, so there is no need for write_lock in
44 * the softirq
45 * For reading or updating the counters, the user context needs to
46 * get a write_lock
47 */
48
49/* The size of each set of counters is altered to get cache alignment */
50#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
51#define COUNTER_OFFSET(n) (SMP_ALIGN(n * sizeof(struct ebt_counter)))
52#define COUNTER_BASE(c, n, cpu) ((struct ebt_counter *)(((char *)c) + \
53 COUNTER_OFFSET(n) * cpu))
54
55
56
Ingo Molnar57b47a52006-03-20 22:35:41 -080057static DEFINE_MUTEX(ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
Jan Engelhardt043ef462008-10-08 11:35:15 +020059static struct xt_target ebt_standard_target = {
Jan Engelhardt001a18d2008-10-08 11:35:14 +020060 .name = "standard",
61 .revision = 0,
62 .family = NFPROTO_BRIDGE,
Jan Engelhardt043ef462008-10-08 11:35:15 +020063 .targetsize = sizeof(int),
Jan Engelhardt18219d32008-10-08 11:35:13 +020064};
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
Jan Engelhardt7eb35582008-10-08 11:35:19 +020066static inline int
67ebt_do_watcher(const struct ebt_entry_watcher *w, struct sk_buff *skb,
68 struct xt_target_param *par)
Linus Torvalds1da177e2005-04-16 15:20:36 -070069{
Jan Engelhardt7eb35582008-10-08 11:35:19 +020070 par->target = w->u.watcher;
71 par->targinfo = w->data;
72 w->u.watcher->target(skb, par);
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 /* watchers don't give a verdict */
74 return 0;
75}
76
77static inline int ebt_do_match (struct ebt_entry_match *m,
Jan Engelhardtf7108a22008-10-08 11:35:18 +020078 const struct sk_buff *skb, struct xt_match_param *par)
Linus Torvalds1da177e2005-04-16 15:20:36 -070079{
Jan Engelhardtf7108a22008-10-08 11:35:18 +020080 par->match = m->u.match;
81 par->matchinfo = m->data;
Jan Engelhardtd61ba9f2009-01-12 00:06:06 +000082 return m->u.match->match(skb, par) ? EBT_MATCH : EBT_NOMATCH;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083}
84
85static inline int ebt_dev_check(char *entry, const struct net_device *device)
86{
87 int i = 0;
Julia Lawallf3d8b2e2009-01-09 10:22:22 +000088 const char *devname;
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90 if (*entry == '\0')
91 return 0;
92 if (!device)
93 return 1;
Julia Lawallf3d8b2e2009-01-09 10:22:22 +000094 devname = device->name;
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 /* 1 is the wildcard token */
96 while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i])
97 i++;
98 return (devname[i] != entry[i] && entry[i] != 1);
99}
100
101#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
102/* process standard matches */
103static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h,
104 const struct net_device *in, const struct net_device *out)
105{
106 int verdict, i;
107
108 if (e->bitmask & EBT_802_3) {
109 if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO))
110 return 1;
111 } else if (!(e->bitmask & EBT_NOPROTO) &&
112 FWINV2(e->ethproto != h->h_proto, EBT_IPROTO))
113 return 1;
114
115 if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
116 return 1;
117 if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
118 return 1;
119 if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check(
120 e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN))
121 return 1;
122 if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check(
123 e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT))
124 return 1;
125
126 if (e->bitmask & EBT_SOURCEMAC) {
127 verdict = 0;
128 for (i = 0; i < 6; i++)
129 verdict |= (h->h_source[i] ^ e->sourcemac[i]) &
130 e->sourcemsk[i];
131 if (FWINV2(verdict != 0, EBT_ISOURCE) )
132 return 1;
133 }
134 if (e->bitmask & EBT_DESTMAC) {
135 verdict = 0;
136 for (i = 0; i < 6; i++)
137 verdict |= (h->h_dest[i] ^ e->destmac[i]) &
138 e->destmsk[i];
139 if (FWINV2(verdict != 0, EBT_IDEST) )
140 return 1;
141 }
142 return 0;
143}
144
Jan Engelhardt98e86402009-04-15 21:06:05 +0200145static inline __pure
146struct ebt_entry *ebt_next_entry(const struct ebt_entry *entry)
147{
148 return (void *)entry + entry->next_offset;
149}
150
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151/* Do some firewalling */
Herbert Xu3db05fe2007-10-15 00:53:15 -0700152unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 const struct net_device *in, const struct net_device *out,
154 struct ebt_table *table)
155{
156 int i, nentries;
157 struct ebt_entry *point;
158 struct ebt_counter *counter_base, *cb_base;
159 struct ebt_entry_target *t;
160 int verdict, sp = 0;
161 struct ebt_chainstack *cs;
162 struct ebt_entries *chaininfo;
163 char *base;
164 struct ebt_table_info *private;
Jan Engelhardt5365f802008-10-08 11:35:16 +0200165 bool hotdrop = false;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200166 struct xt_match_param mtpar;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200167 struct xt_target_param tgpar;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200168
Jan Engelhardt916a9172008-10-08 11:35:20 +0200169 mtpar.family = tgpar.family = NFPROTO_BRIDGE;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200170 mtpar.in = tgpar.in = in;
171 mtpar.out = tgpar.out = out;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200172 mtpar.hotdrop = &hotdrop;
Evgeniy Polyakova5e78822009-06-04 16:54:42 +0200173 mtpar.hooknum = tgpar.hooknum = hook;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174
175 read_lock_bh(&table->lock);
176 private = table->private;
177 cb_base = COUNTER_BASE(private->counters, private->nentries,
178 smp_processor_id());
179 if (private->chainstack)
180 cs = private->chainstack[smp_processor_id()];
181 else
182 cs = NULL;
183 chaininfo = private->hook_entry[hook];
184 nentries = private->hook_entry[hook]->nentries;
185 point = (struct ebt_entry *)(private->hook_entry[hook]->data);
186 counter_base = cb_base + private->hook_entry[hook]->counter_offset;
187 /* base for chain jumps */
188 base = private->entries;
189 i = 0;
190 while (i < nentries) {
Herbert Xu3db05fe2007-10-15 00:53:15 -0700191 if (ebt_basic_match(point, eth_hdr(skb), in, out))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 goto letscontinue;
193
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200194 if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, &mtpar) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 goto letscontinue;
Jan Engelhardt5365f802008-10-08 11:35:16 +0200196 if (hotdrop) {
197 read_unlock_bh(&table->lock);
198 return NF_DROP;
199 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
201 /* increase counter */
202 (*(counter_base + i)).pcnt++;
Herbert Xu3db05fe2007-10-15 00:53:15 -0700203 (*(counter_base + i)).bcnt += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
205 /* these should only watch: not modify, nor tell us
206 what to do with the packet */
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200207 EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, &tgpar);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
209 t = (struct ebt_entry_target *)
210 (((char *)point) + point->target_offset);
211 /* standard target */
212 if (!t->u.target->target)
213 verdict = ((struct ebt_standard_target *)t)->verdict;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200214 else {
215 tgpar.target = t->u.target;
216 tgpar.targinfo = t->data;
217 verdict = t->u.target->target(skb, &tgpar);
218 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 if (verdict == EBT_ACCEPT) {
220 read_unlock_bh(&table->lock);
221 return NF_ACCEPT;
222 }
223 if (verdict == EBT_DROP) {
224 read_unlock_bh(&table->lock);
225 return NF_DROP;
226 }
227 if (verdict == EBT_RETURN) {
228letsreturn:
229#ifdef CONFIG_NETFILTER_DEBUG
230 if (sp == 0) {
231 BUGPRINT("RETURN on base chain");
232 /* act like this is EBT_CONTINUE */
233 goto letscontinue;
234 }
235#endif
236 sp--;
237 /* put all the local variables right */
238 i = cs[sp].n;
239 chaininfo = cs[sp].chaininfo;
240 nentries = chaininfo->nentries;
241 point = cs[sp].e;
242 counter_base = cb_base +
243 chaininfo->counter_offset;
244 continue;
245 }
246 if (verdict == EBT_CONTINUE)
247 goto letscontinue;
248#ifdef CONFIG_NETFILTER_DEBUG
249 if (verdict < 0) {
250 BUGPRINT("bogus standard verdict\n");
251 read_unlock_bh(&table->lock);
252 return NF_DROP;
253 }
254#endif
255 /* jump to a udc */
256 cs[sp].n = i + 1;
257 cs[sp].chaininfo = chaininfo;
Jan Engelhardt98e86402009-04-15 21:06:05 +0200258 cs[sp].e = ebt_next_entry(point);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 i = 0;
260 chaininfo = (struct ebt_entries *) (base + verdict);
261#ifdef CONFIG_NETFILTER_DEBUG
262 if (chaininfo->distinguisher) {
263 BUGPRINT("jump to non-chain\n");
264 read_unlock_bh(&table->lock);
265 return NF_DROP;
266 }
267#endif
268 nentries = chaininfo->nentries;
269 point = (struct ebt_entry *)chaininfo->data;
270 counter_base = cb_base + chaininfo->counter_offset;
271 sp++;
272 continue;
273letscontinue:
Jan Engelhardt98e86402009-04-15 21:06:05 +0200274 point = ebt_next_entry(point);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 i++;
276 }
277
278 /* I actually like this :) */
279 if (chaininfo->policy == EBT_RETURN)
280 goto letsreturn;
281 if (chaininfo->policy == EBT_ACCEPT) {
282 read_unlock_bh(&table->lock);
283 return NF_ACCEPT;
284 }
285 read_unlock_bh(&table->lock);
286 return NF_DROP;
287}
288
289/* If it succeeds, returns element and locks mutex */
290static inline void *
291find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800292 struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293{
Patrick McHardydf0933d2006-09-20 11:57:53 -0700294 struct {
295 struct list_head list;
296 char name[EBT_FUNCTION_MAXNAMELEN];
297 } *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
Ingo Molnar57b47a52006-03-20 22:35:41 -0800299 *error = mutex_lock_interruptible(mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 if (*error != 0)
301 return NULL;
302
Patrick McHardydf0933d2006-09-20 11:57:53 -0700303 list_for_each_entry(e, head, list) {
304 if (strcmp(e->name, name) == 0)
305 return e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 }
Patrick McHardydf0933d2006-09-20 11:57:53 -0700307 *error = -ENOENT;
308 mutex_unlock(mutex);
309 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310}
311
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312static void *
313find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800314 int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315{
Johannes Berg95a5afc2008-10-16 15:24:51 -0700316 return try_then_request_module(
317 find_inlist_lock_noload(head, name, error, mutex),
318 "%s%s", prefix, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
321static inline struct ebt_table *
Alexey Dobriyan511061e2008-11-04 14:22:55 +0100322find_table_lock(struct net *net, const char *name, int *error,
323 struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324{
Alexey Dobriyan511061e2008-11-04 14:22:55 +0100325 return find_inlist_lock(&net->xt.tables[NFPROTO_BRIDGE], name,
326 "ebtable_", error, mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327}
328
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329static inline int
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200330ebt_check_match(struct ebt_entry_match *m, struct xt_mtchk_param *par,
331 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332{
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200333 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200334 struct xt_match *match;
Al Viro14197d52006-11-30 19:25:21 -0800335 size_t left = ((char *)e + e->watchers_offset) - (char *)m;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 int ret;
337
Al Viro14197d52006-11-30 19:25:21 -0800338 if (left < sizeof(struct ebt_entry_match) ||
339 left - sizeof(struct ebt_entry_match) < m->match_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200341
342 match = try_then_request_module(xt_find_match(NFPROTO_BRIDGE,
343 m->u.name, 0), "ebt_%s", m->u.name);
344 if (IS_ERR(match))
345 return PTR_ERR(match);
346 if (match == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200348 m->u.match = match;
349
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200350 par->match = match;
351 par->matchinfo = m->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200352 ret = xt_check_match(par, m->match_size,
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200353 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200354 if (ret < 0) {
355 module_put(match->me);
356 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200358
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 (*cnt)++;
360 return 0;
361}
362
363static inline int
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200364ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
365 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366{
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200367 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200368 struct xt_target *watcher;
Al Viro14197d52006-11-30 19:25:21 -0800369 size_t left = ((char *)e + e->target_offset) - (char *)w;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 int ret;
371
Al Viro14197d52006-11-30 19:25:21 -0800372 if (left < sizeof(struct ebt_entry_watcher) ||
373 left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200375
376 watcher = try_then_request_module(
377 xt_find_target(NFPROTO_BRIDGE, w->u.name, 0),
378 "ebt_%s", w->u.name);
379 if (IS_ERR(watcher))
380 return PTR_ERR(watcher);
381 if (watcher == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200383 w->u.watcher = watcher;
384
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200385 par->target = watcher;
386 par->targinfo = w->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200387 ret = xt_check_target(par, w->watcher_size,
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200388 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200389 if (ret < 0) {
390 module_put(watcher->me);
391 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200393
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 (*cnt)++;
395 return 0;
396}
397
Al Viro70fe9af2006-11-30 19:26:14 -0800398static int ebt_verify_pointers(struct ebt_replace *repl,
399 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400{
Al Viro70fe9af2006-11-30 19:26:14 -0800401 unsigned int limit = repl->entries_size;
402 unsigned int valid_hooks = repl->valid_hooks;
403 unsigned int offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 int i;
405
Al Viroe4fd77d2006-11-30 19:26:35 -0800406 for (i = 0; i < NF_BR_NUMHOOKS; i++)
407 newinfo->hook_entry[i] = NULL;
408
409 newinfo->entries_size = repl->entries_size;
410 newinfo->nentries = repl->nentries;
411
Al Viro70fe9af2006-11-30 19:26:14 -0800412 while (offset < limit) {
413 size_t left = limit - offset;
414 struct ebt_entry *e = (void *)newinfo->entries + offset;
Al Virobb2ef252006-11-30 19:22:42 -0800415
Al Viro70fe9af2006-11-30 19:26:14 -0800416 if (left < sizeof(unsigned int))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 break;
Al Viro22b440b2006-11-30 19:25:51 -0800418
Al Viro70fe9af2006-11-30 19:26:14 -0800419 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
420 if ((valid_hooks & (1 << i)) == 0)
421 continue;
Al Viro1e419cd2006-11-30 19:28:48 -0800422 if ((char __user *)repl->hook_entry[i] ==
423 repl->entries + offset)
Al Viro70fe9af2006-11-30 19:26:14 -0800424 break;
425 }
426
427 if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
428 if (e->bitmask != 0) {
429 /* we make userspace set this right,
430 so there is no misunderstanding */
431 BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
432 "in distinguisher\n");
433 return -EINVAL;
434 }
435 if (i != NF_BR_NUMHOOKS)
436 newinfo->hook_entry[i] = (struct ebt_entries *)e;
437 if (left < sizeof(struct ebt_entries))
438 break;
439 offset += sizeof(struct ebt_entries);
440 } else {
441 if (left < sizeof(struct ebt_entry))
442 break;
443 if (left < e->next_offset)
444 break;
445 offset += e->next_offset;
446 }
447 }
448 if (offset != limit) {
449 BUGPRINT("entries_size too small\n");
450 return -EINVAL;
451 }
Al Viroe4fd77d2006-11-30 19:26:35 -0800452
453 /* check if all valid hooks have a chain */
454 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
455 if (!newinfo->hook_entry[i] &&
456 (valid_hooks & (1 << i))) {
457 BUGPRINT("Valid hook without chain\n");
458 return -EINVAL;
459 }
460 }
Al Viro70fe9af2006-11-30 19:26:14 -0800461 return 0;
Al Viro22b440b2006-11-30 19:25:51 -0800462}
463
464/*
465 * this one is very careful, as it is the first function
466 * to parse the userspace data
467 */
468static inline int
469ebt_check_entry_size_and_hooks(struct ebt_entry *e,
Al Viro0e795532006-11-30 19:27:13 -0800470 struct ebt_table_info *newinfo,
471 unsigned int *n, unsigned int *cnt,
472 unsigned int *totalcnt, unsigned int *udc_cnt)
Al Viro22b440b2006-11-30 19:25:51 -0800473{
Al Viro22b440b2006-11-30 19:25:51 -0800474 int i;
475
476 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Viro0e795532006-11-30 19:27:13 -0800477 if ((void *)e == (void *)newinfo->hook_entry[i])
Al Viro22b440b2006-11-30 19:25:51 -0800478 break;
479 }
480 /* beginning of a new chain
481 if i == NF_BR_NUMHOOKS it must be a user defined chain */
482 if (i != NF_BR_NUMHOOKS || !e->bitmask) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 /* this checks if the previous chain has as many entries
484 as it said it has */
485 if (*n != *cnt) {
486 BUGPRINT("nentries does not equal the nr of entries "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900487 "in the chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 return -EINVAL;
489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 if (((struct ebt_entries *)e)->policy != EBT_DROP &&
491 ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
492 /* only RETURN from udc */
493 if (i != NF_BR_NUMHOOKS ||
494 ((struct ebt_entries *)e)->policy != EBT_RETURN) {
495 BUGPRINT("bad policy\n");
496 return -EINVAL;
497 }
498 }
499 if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
500 (*udc_cnt)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
502 BUGPRINT("counter_offset != totalcnt");
503 return -EINVAL;
504 }
505 *n = ((struct ebt_entries *)e)->nentries;
506 *cnt = 0;
507 return 0;
508 }
509 /* a plain old entry, heh */
510 if (sizeof(struct ebt_entry) > e->watchers_offset ||
511 e->watchers_offset > e->target_offset ||
512 e->target_offset >= e->next_offset) {
513 BUGPRINT("entry offsets not in right order\n");
514 return -EINVAL;
515 }
516 /* this is not checked anywhere else */
517 if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
518 BUGPRINT("target size too small\n");
519 return -EINVAL;
520 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 (*cnt)++;
522 (*totalcnt)++;
523 return 0;
524}
525
526struct ebt_cl_stack
527{
528 struct ebt_chainstack cs;
529 int from;
530 unsigned int hookmask;
531};
532
533/*
534 * we need these positions to check that the jumps to a different part of the
535 * entries is a jump to the beginning of a new chain.
536 */
537static inline int
538ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Viro177abc32006-11-30 19:27:32 -0800539 unsigned int *n, struct ebt_cl_stack *udc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540{
541 int i;
542
543 /* we're only interested in chain starts */
Al Viro40642f92006-11-30 19:24:12 -0800544 if (e->bitmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 return 0;
546 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
548 break;
549 }
550 /* only care about udc */
551 if (i != NF_BR_NUMHOOKS)
552 return 0;
553
554 udc[*n].cs.chaininfo = (struct ebt_entries *)e;
555 /* these initialisations are depended on later in check_chainloops() */
556 udc[*n].cs.n = 0;
557 udc[*n].hookmask = 0;
558
559 (*n)++;
560 return 0;
561}
562
563static inline int
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100564ebt_cleanup_match(struct ebt_entry_match *m, struct net *net, unsigned int *i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565{
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200566 struct xt_mtdtor_param par;
567
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 if (i && (*i)-- == 0)
569 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100571 par.net = net;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200572 par.match = m->u.match;
573 par.matchinfo = m->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200574 par.family = NFPROTO_BRIDGE;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200575 if (par.match->destroy != NULL)
576 par.match->destroy(&par);
577 module_put(par.match->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 return 0;
579}
580
581static inline int
582ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
583{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200584 struct xt_tgdtor_param par;
585
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 if (i && (*i)-- == 0)
587 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
Jan Engelhardta2df1642008-10-08 11:35:19 +0200589 par.target = w->u.watcher;
590 par.targinfo = w->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200591 par.family = NFPROTO_BRIDGE;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200592 if (par.target->destroy != NULL)
593 par.target->destroy(&par);
594 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 return 0;
596}
597
598static inline int
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100599ebt_cleanup_entry(struct ebt_entry *e, struct net *net, unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200601 struct xt_tgdtor_param par;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 struct ebt_entry_target *t;
603
Al Viro40642f92006-11-30 19:24:12 -0800604 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 return 0;
606 /* we're done */
607 if (cnt && (*cnt)-- == 0)
608 return 1;
609 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100610 EBT_MATCH_ITERATE(e, ebt_cleanup_match, net, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
Jan Engelhardta2df1642008-10-08 11:35:19 +0200613 par.target = t->u.target;
614 par.targinfo = t->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200615 par.family = NFPROTO_BRIDGE;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200616 if (par.target->destroy != NULL)
617 par.target->destroy(&par);
618 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 return 0;
620}
621
622static inline int
Alexey Dobriyana83d8e82010-01-18 08:21:13 +0100623ebt_check_entry(struct ebt_entry *e,
624 struct net *net,
625 struct ebt_table_info *newinfo,
Al Virof7da79d2006-11-30 19:27:48 -0800626 const char *name, unsigned int *cnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
628{
629 struct ebt_entry_target *t;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200630 struct xt_target *target;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 unsigned int i, j, hook = 0, hookmask = 0;
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800632 size_t gap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 int ret;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200634 struct xt_mtchk_param mtpar;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200635 struct xt_tgchk_param tgpar;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
637 /* don't mess with the struct ebt_entries */
Al Viro40642f92006-11-30 19:24:12 -0800638 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 return 0;
640
641 if (e->bitmask & ~EBT_F_MASK) {
642 BUGPRINT("Unknown flag for bitmask\n");
643 return -EINVAL;
644 }
645 if (e->invflags & ~EBT_INV_MASK) {
646 BUGPRINT("Unknown flag for inv bitmask\n");
647 return -EINVAL;
648 }
649 if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
650 BUGPRINT("NOPROTO & 802_3 not allowed\n");
651 return -EINVAL;
652 }
653 /* what hook do we belong to? */
654 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Virof7da79d2006-11-30 19:27:48 -0800655 if (!newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 continue;
657 if ((char *)newinfo->hook_entry[i] < (char *)e)
658 hook = i;
659 else
660 break;
661 }
662 /* (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
663 a base chain */
664 if (i < NF_BR_NUMHOOKS)
665 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
666 else {
667 for (i = 0; i < udc_cnt; i++)
668 if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
669 break;
670 if (i == 0)
671 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
672 else
673 hookmask = cl_s[i - 1].hookmask;
674 }
675 i = 0;
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200676
Alexey Dobriyana83d8e82010-01-18 08:21:13 +0100677 mtpar.net = net;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200678 mtpar.table = tgpar.table = name;
679 mtpar.entryinfo = tgpar.entryinfo = e;
680 mtpar.hook_mask = tgpar.hook_mask = hookmask;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200681 mtpar.family = tgpar.family = NFPROTO_BRIDGE;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200682 ret = EBT_MATCH_ITERATE(e, ebt_check_match, &mtpar, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 if (ret != 0)
684 goto cleanup_matches;
685 j = 0;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200686 ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, &tgpar, &j);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 if (ret != 0)
688 goto cleanup_watchers;
689 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800690 gap = e->next_offset - e->target_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
Jan Engelhardt043ef462008-10-08 11:35:15 +0200692 target = try_then_request_module(
693 xt_find_target(NFPROTO_BRIDGE, t->u.name, 0),
694 "ebt_%s", t->u.name);
695 if (IS_ERR(target)) {
696 ret = PTR_ERR(target);
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200697 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200698 } else if (target == NULL) {
699 ret = -ENOENT;
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200700 goto cleanup_watchers;
701 }
702
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 t->u.target = target;
704 if (t->u.target == &ebt_standard_target) {
Al Viro14197d52006-11-30 19:25:21 -0800705 if (gap < sizeof(struct ebt_standard_target)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 BUGPRINT("Standard target size too big\n");
707 ret = -EFAULT;
708 goto cleanup_watchers;
709 }
710 if (((struct ebt_standard_target *)t)->verdict <
711 -NUM_STANDARD_TARGETS) {
712 BUGPRINT("Invalid standard target\n");
713 ret = -EFAULT;
714 goto cleanup_watchers;
715 }
Jan Engelhardt18219d32008-10-08 11:35:13 +0200716 } else if (t->target_size > gap - sizeof(struct ebt_entry_target)) {
717 module_put(t->u.target->me);
718 ret = -EFAULT;
719 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200720 }
721
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200722 tgpar.target = target;
723 tgpar.targinfo = t->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200724 ret = xt_check_target(&tgpar, t->target_size,
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200725 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200726 if (ret < 0) {
727 module_put(target->me);
Jan Engelhardt18219d32008-10-08 11:35:13 +0200728 goto cleanup_watchers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 }
730 (*cnt)++;
731 return 0;
732cleanup_watchers:
733 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);
734cleanup_matches:
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100735 EBT_MATCH_ITERATE(e, ebt_cleanup_match, net, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 return ret;
737}
738
739/*
740 * checks for loops and sets the hook mask for udc
741 * the hook mask for udc tells us from which base chains the udc can be
742 * accessed. This mask is a parameter to the check() functions of the extensions
743 */
744static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
745 unsigned int udc_cnt, unsigned int hooknr, char *base)
746{
747 int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
748 struct ebt_entry *e = (struct ebt_entry *)chain->data;
749 struct ebt_entry_target *t;
750
751 while (pos < nentries || chain_nr != -1) {
752 /* end of udc, go back one 'recursion' step */
753 if (pos == nentries) {
754 /* put back values of the time when this chain was called */
755 e = cl_s[chain_nr].cs.e;
756 if (cl_s[chain_nr].from != -1)
757 nentries =
758 cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
759 else
760 nentries = chain->nentries;
761 pos = cl_s[chain_nr].cs.n;
762 /* make sure we won't see a loop that isn't one */
763 cl_s[chain_nr].cs.n = 0;
764 chain_nr = cl_s[chain_nr].from;
765 if (pos == nentries)
766 continue;
767 }
768 t = (struct ebt_entry_target *)
769 (((char *)e) + e->target_offset);
770 if (strcmp(t->u.name, EBT_STANDARD_TARGET))
771 goto letscontinue;
772 if (e->target_offset + sizeof(struct ebt_standard_target) >
773 e->next_offset) {
774 BUGPRINT("Standard target size too big\n");
775 return -1;
776 }
777 verdict = ((struct ebt_standard_target *)t)->verdict;
778 if (verdict >= 0) { /* jump to another chain */
779 struct ebt_entries *hlp2 =
780 (struct ebt_entries *)(base + verdict);
781 for (i = 0; i < udc_cnt; i++)
782 if (hlp2 == cl_s[i].cs.chaininfo)
783 break;
784 /* bad destination or loop */
785 if (i == udc_cnt) {
786 BUGPRINT("bad destination\n");
787 return -1;
788 }
789 if (cl_s[i].cs.n) {
790 BUGPRINT("loop\n");
791 return -1;
792 }
Al Viro98a08242006-11-30 19:24:49 -0800793 if (cl_s[i].hookmask & (1 << hooknr))
794 goto letscontinue;
795 /* this can't be 0, so the loop test is correct */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 cl_s[i].cs.n = pos + 1;
797 pos = 0;
Jan Engelhardt98e86402009-04-15 21:06:05 +0200798 cl_s[i].cs.e = ebt_next_entry(e);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 e = (struct ebt_entry *)(hlp2->data);
800 nentries = hlp2->nentries;
801 cl_s[i].from = chain_nr;
802 chain_nr = i;
803 /* this udc is accessible from the base chain for hooknr */
804 cl_s[i].hookmask |= (1 << hooknr);
805 continue;
806 }
807letscontinue:
Jan Engelhardt98e86402009-04-15 21:06:05 +0200808 e = ebt_next_entry(e);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 pos++;
810 }
811 return 0;
812}
813
814/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
Alexey Dobriyana83d8e82010-01-18 08:21:13 +0100815static int translate_table(struct net *net, char *name,
816 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817{
818 unsigned int i, j, k, udc_cnt;
819 int ret;
820 struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
821
822 i = 0;
Al Viro1f072c92006-11-30 19:26:53 -0800823 while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 i++;
825 if (i == NF_BR_NUMHOOKS) {
826 BUGPRINT("No valid hooks specified\n");
827 return -EINVAL;
828 }
Al Viro1f072c92006-11-30 19:26:53 -0800829 if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 BUGPRINT("Chains don't start at beginning\n");
831 return -EINVAL;
832 }
833 /* make sure chains are ordered after each other in same order
834 as their corresponding hooks */
835 for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
Al Viro1f072c92006-11-30 19:26:53 -0800836 if (!newinfo->hook_entry[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 continue;
Al Viro1f072c92006-11-30 19:26:53 -0800838 if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 BUGPRINT("Hook order must be followed\n");
840 return -EINVAL;
841 }
842 i = j;
843 }
844
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 /* do some early checkings and initialize some things */
846 i = 0; /* holds the expected nr. of entries for the chain */
847 j = 0; /* holds the up to now counted entries for the chain */
848 k = 0; /* holds the total nr. of entries, should equal
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900849 newinfo->nentries afterwards */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
851 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro0e795532006-11-30 19:27:13 -0800852 ebt_check_entry_size_and_hooks, newinfo,
853 &i, &j, &k, &udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854
855 if (ret != 0)
856 return ret;
857
858 if (i != j) {
859 BUGPRINT("nentries does not equal the nr of entries in the "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900860 "(last) chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 return -EINVAL;
862 }
863 if (k != newinfo->nentries) {
864 BUGPRINT("Total nentries is wrong\n");
865 return -EINVAL;
866 }
867
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 /* get the location of the udc, put them in an array
869 while we're at it, allocate the chainstack */
870 if (udc_cnt) {
871 /* this will get free'd in do_replace()/ebt_register_table()
872 if an error occurs */
Jayachandran C7ad4d2f2006-04-11 17:25:38 -0700873 newinfo->chainstack =
Christoph Lameter53b8a312007-02-20 13:57:51 -0800874 vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 if (!newinfo->chainstack)
876 return -ENOMEM;
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700877 for_each_possible_cpu(i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 newinfo->chainstack[i] =
Jayachandran C18bc89a2006-04-20 00:14:49 -0700879 vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 if (!newinfo->chainstack[i]) {
881 while (i)
882 vfree(newinfo->chainstack[--i]);
883 vfree(newinfo->chainstack);
884 newinfo->chainstack = NULL;
885 return -ENOMEM;
886 }
887 }
888
Jayachandran C18bc89a2006-04-20 00:14:49 -0700889 cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 if (!cl_s)
891 return -ENOMEM;
892 i = 0; /* the i'th udc */
893 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro177abc32006-11-30 19:27:32 -0800894 ebt_get_udc_positions, newinfo, &i, cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 /* sanity check */
896 if (i != udc_cnt) {
897 BUGPRINT("i != udc_cnt\n");
898 vfree(cl_s);
899 return -EFAULT;
900 }
901 }
902
903 /* Check for loops */
904 for (i = 0; i < NF_BR_NUMHOOKS; i++)
Al Viro1f072c92006-11-30 19:26:53 -0800905 if (newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 if (check_chainloops(newinfo->hook_entry[i],
907 cl_s, udc_cnt, i, newinfo->entries)) {
James Lamanna68d31872005-06-22 22:12:57 -0700908 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 return -EINVAL;
910 }
911
Jan Engelhardt96de0e22007-10-19 23:21:04 +0200912 /* we now know the following (along with E=mc²):
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 - the nr of entries in each chain is right
914 - the size of the allocated space is right
915 - all valid hooks have a corresponding chain
916 - there are no loops
917 - wrong data can still be on the level of a single entry
918 - could be there are jumps to places that are not the
919 beginning of a chain. This can only occur in chains that
920 are not accessible from any base chains, so we don't care. */
921
922 /* used to know what we need to clean up if something goes wrong */
923 i = 0;
924 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Alexey Dobriyana83d8e82010-01-18 08:21:13 +0100925 ebt_check_entry, net, newinfo, name, &i, cl_s, udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 if (ret != 0) {
927 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100928 ebt_cleanup_entry, net, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 }
James Lamanna68d31872005-06-22 22:12:57 -0700930 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 return ret;
932}
933
934/* called under write_lock */
935static void get_counters(struct ebt_counter *oldcounters,
936 struct ebt_counter *counters, unsigned int nentries)
937{
938 int i, cpu;
939 struct ebt_counter *counter_base;
940
941 /* counters of cpu 0 */
942 memcpy(counters, oldcounters,
David S. Millerc8923c62005-10-13 14:41:23 -0700943 sizeof(struct ebt_counter) * nentries);
944
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 /* add other counters to those of cpu 0 */
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700946 for_each_possible_cpu(cpu) {
David S. Millerc8923c62005-10-13 14:41:23 -0700947 if (cpu == 0)
948 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
950 for (i = 0; i < nentries; i++) {
951 counters[i].pcnt += counter_base[i].pcnt;
952 counters[i].bcnt += counter_base[i].bcnt;
953 }
954 }
955}
956
957/* replace the table */
Alexey Dobriyan511061e2008-11-04 14:22:55 +0100958static int do_replace(struct net *net, void __user *user, unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959{
960 int ret, i, countersize;
961 struct ebt_table_info *newinfo;
962 struct ebt_replace tmp;
963 struct ebt_table *t;
964 struct ebt_counter *counterstmp = NULL;
965 /* used to be able to unlock earlier */
966 struct ebt_table_info *table;
967
968 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
969 return -EFAULT;
970
971 if (len != sizeof(tmp) + tmp.entries_size) {
972 BUGPRINT("Wrong len argument\n");
973 return -EINVAL;
974 }
975
976 if (tmp.entries_size == 0) {
977 BUGPRINT("Entries_size never zero\n");
978 return -EINVAL;
979 }
Kirill Korotaevee4bb812006-02-04 02:16:56 -0800980 /* overflow check */
981 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
982 SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
983 return -ENOMEM;
984 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
985 return -ENOMEM;
986
Christoph Lameter53b8a312007-02-20 13:57:51 -0800987 countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -0700988 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 if (!newinfo)
990 return -ENOMEM;
991
992 if (countersize)
993 memset(newinfo->counters, 0, countersize);
994
Kris Katterjohn8b3a7002006-01-11 15:56:43 -0800995 newinfo->entries = vmalloc(tmp.entries_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 if (!newinfo->entries) {
997 ret = -ENOMEM;
998 goto free_newinfo;
999 }
1000 if (copy_from_user(
1001 newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
1002 BUGPRINT("Couldn't copy entries from userspace\n");
1003 ret = -EFAULT;
1004 goto free_entries;
1005 }
1006
1007 /* the user wants counters back
1008 the check on the size is done later, when we have the lock */
1009 if (tmp.num_counters) {
Jayachandran C18bc89a2006-04-20 00:14:49 -07001010 counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 if (!counterstmp) {
1012 ret = -ENOMEM;
1013 goto free_entries;
1014 }
1015 }
1016 else
1017 counterstmp = NULL;
1018
1019 /* this can get initialized by translate_table() */
1020 newinfo->chainstack = NULL;
Al Viro1bc23262006-11-30 19:28:08 -08001021 ret = ebt_verify_pointers(&tmp, newinfo);
1022 if (ret != 0)
1023 goto free_counterstmp;
1024
Alexey Dobriyana83d8e82010-01-18 08:21:13 +01001025 ret = translate_table(net, tmp.name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026
1027 if (ret != 0)
1028 goto free_counterstmp;
1029
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001030 t = find_table_lock(net, tmp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 if (!t) {
1032 ret = -ENOENT;
1033 goto free_iterate;
1034 }
1035
1036 /* the table doesn't like it */
1037 if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
1038 goto free_unlock;
1039
1040 if (tmp.num_counters && tmp.num_counters != t->private->nentries) {
1041 BUGPRINT("Wrong nr. of counters requested\n");
1042 ret = -EINVAL;
1043 goto free_unlock;
1044 }
1045
1046 /* we have the mutex lock, so no danger in reading this pointer */
1047 table = t->private;
1048 /* make sure the table can only be rmmod'ed if it contains no rules */
1049 if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) {
1050 ret = -ENOENT;
1051 goto free_unlock;
1052 } else if (table->nentries && !newinfo->nentries)
1053 module_put(t->me);
1054 /* we need an atomic snapshot of the counters */
1055 write_lock_bh(&t->lock);
1056 if (tmp.num_counters)
1057 get_counters(t->private->counters, counterstmp,
1058 t->private->nentries);
1059
1060 t->private = newinfo;
1061 write_unlock_bh(&t->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001062 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 /* so, a user can change the chains while having messed up her counter
1064 allocation. Only reason why this is done is because this way the lock
1065 is held only once, while this doesn't bring the kernel into a
1066 dangerous state. */
1067 if (tmp.num_counters &&
1068 copy_to_user(tmp.counters, counterstmp,
1069 tmp.num_counters * sizeof(struct ebt_counter))) {
1070 BUGPRINT("Couldn't copy counters to userspace\n");
1071 ret = -EFAULT;
1072 }
1073 else
1074 ret = 0;
1075
1076 /* decrease module count and free resources */
1077 EBT_ENTRY_ITERATE(table->entries, table->entries_size,
Alexey Dobriyanf54e9362010-01-18 08:25:47 +01001078 ebt_cleanup_entry, net, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079
1080 vfree(table->entries);
1081 if (table->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001082 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 vfree(table->chainstack[i]);
1084 vfree(table->chainstack);
1085 }
1086 vfree(table);
1087
James Lamanna68d31872005-06-22 22:12:57 -07001088 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 return ret;
1090
1091free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001092 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093free_iterate:
1094 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Alexey Dobriyanf54e9362010-01-18 08:25:47 +01001095 ebt_cleanup_entry, net, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096free_counterstmp:
James Lamanna68d31872005-06-22 22:12:57 -07001097 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 /* can be initialized in translate_table() */
1099 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001100 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 vfree(newinfo->chainstack[i]);
1102 vfree(newinfo->chainstack);
1103 }
1104free_entries:
James Lamanna68d31872005-06-22 22:12:57 -07001105 vfree(newinfo->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106free_newinfo:
James Lamanna68d31872005-06-22 22:12:57 -07001107 vfree(newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 return ret;
1109}
1110
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001111struct ebt_table *
1112ebt_register_table(struct net *net, const struct ebt_table *input_table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113{
1114 struct ebt_table_info *newinfo;
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001115 struct ebt_table *t, *table;
Al Viro1e419cd2006-11-30 19:28:48 -08001116 struct ebt_replace_kernel *repl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 int ret, i, countersize;
Al Virodf07a812006-11-30 19:28:25 -08001118 void *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001120 if (input_table == NULL || (repl = input_table->table) == NULL ||
1121 repl->entries == 0 || repl->entries_size == 0 ||
1122 repl->counters != NULL || input_table->private != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 BUGPRINT("Bad table data for ebt_register_table!!!\n");
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001124 return ERR_PTR(-EINVAL);
1125 }
1126
1127 /* Don't add one table to multiple lists. */
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001128 table = kmemdup(input_table, sizeof(struct ebt_table), GFP_KERNEL);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001129 if (!table) {
1130 ret = -ENOMEM;
1131 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 }
1133
Christoph Lameter53b8a312007-02-20 13:57:51 -08001134 countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -07001135 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 ret = -ENOMEM;
1137 if (!newinfo)
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001138 goto free_table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139
Al Virodf07a812006-11-30 19:28:25 -08001140 p = vmalloc(repl->entries_size);
1141 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 goto free_newinfo;
1143
Al Virodf07a812006-11-30 19:28:25 -08001144 memcpy(p, repl->entries, repl->entries_size);
1145 newinfo->entries = p;
1146
1147 newinfo->entries_size = repl->entries_size;
1148 newinfo->nentries = repl->nentries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149
1150 if (countersize)
1151 memset(newinfo->counters, 0, countersize);
1152
1153 /* fill in newinfo and parse the entries */
1154 newinfo->chainstack = NULL;
Al Virodf07a812006-11-30 19:28:25 -08001155 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1156 if ((repl->valid_hooks & (1 << i)) == 0)
1157 newinfo->hook_entry[i] = NULL;
1158 else
1159 newinfo->hook_entry[i] = p +
1160 ((char *)repl->hook_entry[i] - repl->entries);
1161 }
Alexey Dobriyana83d8e82010-01-18 08:21:13 +01001162 ret = translate_table(net, repl->name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 if (ret != 0) {
1164 BUGPRINT("Translate_table failed\n");
1165 goto free_chainstack;
1166 }
1167
1168 if (table->check && table->check(newinfo, table->valid_hooks)) {
1169 BUGPRINT("The table doesn't like its own initial data, lol\n");
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001170 return ERR_PTR(-EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 }
1172
1173 table->private = newinfo;
1174 rwlock_init(&table->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001175 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 if (ret != 0)
1177 goto free_chainstack;
1178
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001179 list_for_each_entry(t, &net->xt.tables[NFPROTO_BRIDGE], list) {
Patrick McHardydf0933d2006-09-20 11:57:53 -07001180 if (strcmp(t->name, table->name) == 0) {
1181 ret = -EEXIST;
1182 BUGPRINT("Table name already exists\n");
1183 goto free_unlock;
1184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 }
1186
1187 /* Hold a reference count if the chains aren't empty */
1188 if (newinfo->nentries && !try_module_get(table->me)) {
1189 ret = -ENOENT;
1190 goto free_unlock;
1191 }
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001192 list_add(&table->list, &net->xt.tables[NFPROTO_BRIDGE]);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001193 mutex_unlock(&ebt_mutex);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001194 return table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001196 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197free_chainstack:
1198 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001199 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 vfree(newinfo->chainstack[i]);
1201 vfree(newinfo->chainstack);
1202 }
1203 vfree(newinfo->entries);
1204free_newinfo:
1205 vfree(newinfo);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001206free_table:
1207 kfree(table);
1208out:
1209 return ERR_PTR(ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210}
1211
Alexey Dobriyanf54e9362010-01-18 08:25:47 +01001212void ebt_unregister_table(struct net *net, struct ebt_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213{
1214 int i;
1215
1216 if (!table) {
1217 BUGPRINT("Request to unregister NULL table!!!\n");
1218 return;
1219 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001220 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001221 list_del(&table->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001222 mutex_unlock(&ebt_mutex);
Alexey Dobriyandbcdf852008-11-04 14:28:04 +01001223 EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size,
Alexey Dobriyanf54e9362010-01-18 08:25:47 +01001224 ebt_cleanup_entry, net, NULL);
Alexey Dobriyandbcdf852008-11-04 14:28:04 +01001225 if (table->private->nentries)
1226 module_put(table->me);
James Lamanna68d31872005-06-22 22:12:57 -07001227 vfree(table->private->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 if (table->private->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001229 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 vfree(table->private->chainstack[i]);
1231 vfree(table->private->chainstack);
1232 }
1233 vfree(table->private);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001234 kfree(table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235}
1236
1237/* userspace just supplied us with counters */
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001238static int update_counters(struct net *net, void __user *user, unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239{
1240 int i, ret;
1241 struct ebt_counter *tmp;
1242 struct ebt_replace hlp;
1243 struct ebt_table *t;
1244
1245 if (copy_from_user(&hlp, user, sizeof(hlp)))
1246 return -EFAULT;
1247
1248 if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
1249 return -EINVAL;
1250 if (hlp.num_counters == 0)
1251 return -EINVAL;
1252
Jayachandran C18bc89a2006-04-20 00:14:49 -07001253 if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 MEMPRINT("Update_counters && nomemory\n");
1255 return -ENOMEM;
1256 }
1257
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001258 t = find_table_lock(net, hlp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 if (!t)
1260 goto free_tmp;
1261
1262 if (hlp.num_counters != t->private->nentries) {
1263 BUGPRINT("Wrong nr of counters\n");
1264 ret = -EINVAL;
1265 goto unlock_mutex;
1266 }
1267
1268 if ( copy_from_user(tmp, hlp.counters,
1269 hlp.num_counters * sizeof(struct ebt_counter)) ) {
1270 BUGPRINT("Updata_counters && !cfu\n");
1271 ret = -EFAULT;
1272 goto unlock_mutex;
1273 }
1274
1275 /* we want an atomic add of the counters */
1276 write_lock_bh(&t->lock);
1277
1278 /* we add to the counters of the first cpu */
1279 for (i = 0; i < hlp.num_counters; i++) {
1280 t->private->counters[i].pcnt += tmp[i].pcnt;
1281 t->private->counters[i].bcnt += tmp[i].bcnt;
1282 }
1283
1284 write_unlock_bh(&t->lock);
1285 ret = 0;
1286unlock_mutex:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001287 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288free_tmp:
1289 vfree(tmp);
1290 return ret;
1291}
1292
1293static inline int ebt_make_matchname(struct ebt_entry_match *m,
Al Viro1e419cd2006-11-30 19:28:48 -08001294 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295{
Al Viro1e419cd2006-11-30 19:28:48 -08001296 char __user *hlp = ubase + ((char *)m - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
1298 return -EFAULT;
1299 return 0;
1300}
1301
1302static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
Al Viro1e419cd2006-11-30 19:28:48 -08001303 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304{
Al Viro1e419cd2006-11-30 19:28:48 -08001305 char __user *hlp = ubase + ((char *)w - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
1307 return -EFAULT;
1308 return 0;
1309}
1310
Al Viro1e419cd2006-11-30 19:28:48 -08001311static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312{
1313 int ret;
Al Viro1e419cd2006-11-30 19:28:48 -08001314 char __user *hlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 struct ebt_entry_target *t;
1316
Al Viro40642f92006-11-30 19:24:12 -08001317 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 return 0;
1319
Al Viro1e419cd2006-11-30 19:28:48 -08001320 hlp = ubase + (((char *)e + e->target_offset) - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +09001322
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
1324 if (ret != 0)
1325 return ret;
1326 ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
1327 if (ret != 0)
1328 return ret;
1329 if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
1330 return -EFAULT;
1331 return 0;
1332}
1333
Ingo Molnar57b47a52006-03-20 22:35:41 -08001334/* called with ebt_mutex locked */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335static int copy_everything_to_user(struct ebt_table *t, void __user *user,
1336 int *len, int cmd)
1337{
1338 struct ebt_replace tmp;
1339 struct ebt_counter *counterstmp, *oldcounters;
1340 unsigned int entries_size, nentries;
1341 char *entries;
1342
1343 if (cmd == EBT_SO_GET_ENTRIES) {
1344 entries_size = t->private->entries_size;
1345 nentries = t->private->nentries;
1346 entries = t->private->entries;
1347 oldcounters = t->private->counters;
1348 } else {
1349 entries_size = t->table->entries_size;
1350 nentries = t->table->nentries;
1351 entries = t->table->entries;
1352 oldcounters = t->table->counters;
1353 }
1354
1355 if (copy_from_user(&tmp, user, sizeof(tmp))) {
1356 BUGPRINT("Cfu didn't work\n");
1357 return -EFAULT;
1358 }
1359
1360 if (*len != sizeof(struct ebt_replace) + entries_size +
1361 (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
1362 BUGPRINT("Wrong size\n");
1363 return -EINVAL;
1364 }
1365
1366 if (tmp.nentries != nentries) {
1367 BUGPRINT("Nentries wrong\n");
1368 return -EINVAL;
1369 }
1370
1371 if (tmp.entries_size != entries_size) {
1372 BUGPRINT("Wrong size\n");
1373 return -EINVAL;
1374 }
1375
1376 /* userspace might not need the counters */
1377 if (tmp.num_counters) {
1378 if (tmp.num_counters != nentries) {
1379 BUGPRINT("Num_counters wrong\n");
1380 return -EINVAL;
1381 }
Jayachandran C18bc89a2006-04-20 00:14:49 -07001382 counterstmp = vmalloc(nentries * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 if (!counterstmp) {
1384 MEMPRINT("Couldn't copy counters, out of memory\n");
1385 return -ENOMEM;
1386 }
1387 write_lock_bh(&t->lock);
1388 get_counters(oldcounters, counterstmp, nentries);
1389 write_unlock_bh(&t->lock);
1390
1391 if (copy_to_user(tmp.counters, counterstmp,
1392 nentries * sizeof(struct ebt_counter))) {
1393 BUGPRINT("Couldn't copy counters to userspace\n");
1394 vfree(counterstmp);
1395 return -EFAULT;
1396 }
1397 vfree(counterstmp);
1398 }
1399
1400 if (copy_to_user(tmp.entries, entries, entries_size)) {
1401 BUGPRINT("Couldn't copy entries to userspace\n");
1402 return -EFAULT;
1403 }
1404 /* set the match/watcher/target names right */
1405 return EBT_ENTRY_ITERATE(entries, entries_size,
1406 ebt_make_names, entries, tmp.entries);
1407}
1408
1409static int do_ebt_set_ctl(struct sock *sk,
1410 int cmd, void __user *user, unsigned int len)
1411{
1412 int ret;
1413
1414 switch(cmd) {
1415 case EBT_SO_SET_ENTRIES:
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001416 ret = do_replace(sock_net(sk), user, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 break;
1418 case EBT_SO_SET_COUNTERS:
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001419 ret = update_counters(sock_net(sk), user, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 break;
1421 default:
1422 ret = -EINVAL;
1423 }
1424 return ret;
1425}
1426
1427static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1428{
1429 int ret;
1430 struct ebt_replace tmp;
1431 struct ebt_table *t;
1432
1433 if (copy_from_user(&tmp, user, sizeof(tmp)))
1434 return -EFAULT;
1435
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001436 t = find_table_lock(sock_net(sk), tmp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 if (!t)
1438 return ret;
1439
1440 switch(cmd) {
1441 case EBT_SO_GET_INFO:
1442 case EBT_SO_GET_INIT_INFO:
1443 if (*len != sizeof(struct ebt_replace)){
1444 ret = -EINVAL;
Ingo Molnar57b47a52006-03-20 22:35:41 -08001445 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 break;
1447 }
1448 if (cmd == EBT_SO_GET_INFO) {
1449 tmp.nentries = t->private->nentries;
1450 tmp.entries_size = t->private->entries_size;
1451 tmp.valid_hooks = t->valid_hooks;
1452 } else {
1453 tmp.nentries = t->table->nentries;
1454 tmp.entries_size = t->table->entries_size;
1455 tmp.valid_hooks = t->table->valid_hooks;
1456 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001457 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 if (copy_to_user(user, &tmp, *len) != 0){
1459 BUGPRINT("c2u Didn't work\n");
1460 ret = -EFAULT;
1461 break;
1462 }
1463 ret = 0;
1464 break;
1465
1466 case EBT_SO_GET_ENTRIES:
1467 case EBT_SO_GET_INIT_ENTRIES:
1468 ret = copy_everything_to_user(t, user, len, cmd);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001469 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 break;
1471
1472 default:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001473 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 ret = -EINVAL;
1475 }
1476
1477 return ret;
1478}
1479
1480static struct nf_sockopt_ops ebt_sockopts =
Andrew Morton74ca4e5a2006-03-20 22:55:02 -08001481{
1482 .pf = PF_INET,
1483 .set_optmin = EBT_BASE_CTL,
1484 .set_optmax = EBT_SO_SET_MAX + 1,
1485 .set = do_ebt_set_ctl,
1486 .get_optmin = EBT_BASE_CTL,
1487 .get_optmax = EBT_SO_GET_MAX + 1,
1488 .get = do_ebt_get_ctl,
Neil Horman16fcec32007-09-11 11:28:26 +02001489 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490};
1491
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001492static int __init ebtables_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493{
1494 int ret;
1495
Jan Engelhardt043ef462008-10-08 11:35:15 +02001496 ret = xt_register_target(&ebt_standard_target);
1497 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 return ret;
Jan Engelhardt043ef462008-10-08 11:35:15 +02001499 ret = nf_register_sockopt(&ebt_sockopts);
1500 if (ret < 0) {
1501 xt_unregister_target(&ebt_standard_target);
1502 return ret;
1503 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504
Patrick McHardya887c1c2007-07-14 20:46:15 -07001505 printk(KERN_INFO "Ebtables v2.0 registered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 return 0;
1507}
1508
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001509static void __exit ebtables_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510{
1511 nf_unregister_sockopt(&ebt_sockopts);
Jan Engelhardt043ef462008-10-08 11:35:15 +02001512 xt_unregister_target(&ebt_standard_target);
Patrick McHardya887c1c2007-07-14 20:46:15 -07001513 printk(KERN_INFO "Ebtables v2.0 unregistered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514}
1515
1516EXPORT_SYMBOL(ebt_register_table);
1517EXPORT_SYMBOL(ebt_unregister_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518EXPORT_SYMBOL(ebt_do_table);
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001519module_init(ebtables_init);
1520module_exit(ebtables_fini);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521MODULE_LICENSE("GPL");