blob: bd1c65425d4fc02e4b514711a2ee951a122c99fb [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
564ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i)
565{
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
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200571 par.match = m->u.match;
572 par.matchinfo = m->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200573 par.family = NFPROTO_BRIDGE;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200574 if (par.match->destroy != NULL)
575 par.match->destroy(&par);
576 module_put(par.match->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 return 0;
578}
579
580static inline int
581ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
582{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200583 struct xt_tgdtor_param par;
584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 if (i && (*i)-- == 0)
586 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
Jan Engelhardta2df1642008-10-08 11:35:19 +0200588 par.target = w->u.watcher;
589 par.targinfo = w->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200590 par.family = NFPROTO_BRIDGE;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200591 if (par.target->destroy != NULL)
592 par.target->destroy(&par);
593 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 return 0;
595}
596
597static inline int
598ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
599{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200600 struct xt_tgdtor_param par;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 struct ebt_entry_target *t;
602
Al Viro40642f92006-11-30 19:24:12 -0800603 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 return 0;
605 /* we're done */
606 if (cnt && (*cnt)-- == 0)
607 return 1;
608 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
609 EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL);
610 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611
Jan Engelhardta2df1642008-10-08 11:35:19 +0200612 par.target = t->u.target;
613 par.targinfo = t->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200614 par.family = NFPROTO_BRIDGE;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200615 if (par.target->destroy != NULL)
616 par.target->destroy(&par);
617 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 return 0;
619}
620
621static inline int
622ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Virof7da79d2006-11-30 19:27:48 -0800623 const char *name, unsigned int *cnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
625{
626 struct ebt_entry_target *t;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200627 struct xt_target *target;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 unsigned int i, j, hook = 0, hookmask = 0;
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800629 size_t gap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 int ret;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200631 struct xt_mtchk_param mtpar;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200632 struct xt_tgchk_param tgpar;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
634 /* don't mess with the struct ebt_entries */
Al Viro40642f92006-11-30 19:24:12 -0800635 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 return 0;
637
638 if (e->bitmask & ~EBT_F_MASK) {
639 BUGPRINT("Unknown flag for bitmask\n");
640 return -EINVAL;
641 }
642 if (e->invflags & ~EBT_INV_MASK) {
643 BUGPRINT("Unknown flag for inv bitmask\n");
644 return -EINVAL;
645 }
646 if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
647 BUGPRINT("NOPROTO & 802_3 not allowed\n");
648 return -EINVAL;
649 }
650 /* what hook do we belong to? */
651 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Virof7da79d2006-11-30 19:27:48 -0800652 if (!newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 continue;
654 if ((char *)newinfo->hook_entry[i] < (char *)e)
655 hook = i;
656 else
657 break;
658 }
659 /* (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
660 a base chain */
661 if (i < NF_BR_NUMHOOKS)
662 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
663 else {
664 for (i = 0; i < udc_cnt; i++)
665 if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
666 break;
667 if (i == 0)
668 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
669 else
670 hookmask = cl_s[i - 1].hookmask;
671 }
672 i = 0;
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200673
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200674 mtpar.table = tgpar.table = name;
675 mtpar.entryinfo = tgpar.entryinfo = e;
676 mtpar.hook_mask = tgpar.hook_mask = hookmask;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200677 mtpar.family = tgpar.family = NFPROTO_BRIDGE;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200678 ret = EBT_MATCH_ITERATE(e, ebt_check_match, &mtpar, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 if (ret != 0)
680 goto cleanup_matches;
681 j = 0;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200682 ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, &tgpar, &j);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 if (ret != 0)
684 goto cleanup_watchers;
685 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800686 gap = e->next_offset - e->target_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
Jan Engelhardt043ef462008-10-08 11:35:15 +0200688 target = try_then_request_module(
689 xt_find_target(NFPROTO_BRIDGE, t->u.name, 0),
690 "ebt_%s", t->u.name);
691 if (IS_ERR(target)) {
692 ret = PTR_ERR(target);
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200693 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200694 } else if (target == NULL) {
695 ret = -ENOENT;
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200696 goto cleanup_watchers;
697 }
698
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 t->u.target = target;
700 if (t->u.target == &ebt_standard_target) {
Al Viro14197d52006-11-30 19:25:21 -0800701 if (gap < sizeof(struct ebt_standard_target)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 BUGPRINT("Standard target size too big\n");
703 ret = -EFAULT;
704 goto cleanup_watchers;
705 }
706 if (((struct ebt_standard_target *)t)->verdict <
707 -NUM_STANDARD_TARGETS) {
708 BUGPRINT("Invalid standard target\n");
709 ret = -EFAULT;
710 goto cleanup_watchers;
711 }
Jan Engelhardt18219d32008-10-08 11:35:13 +0200712 } else if (t->target_size > gap - sizeof(struct ebt_entry_target)) {
713 module_put(t->u.target->me);
714 ret = -EFAULT;
715 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200716 }
717
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200718 tgpar.target = target;
719 tgpar.targinfo = t->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200720 ret = xt_check_target(&tgpar, t->target_size,
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200721 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200722 if (ret < 0) {
723 module_put(target->me);
Jan Engelhardt18219d32008-10-08 11:35:13 +0200724 goto cleanup_watchers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 }
726 (*cnt)++;
727 return 0;
728cleanup_watchers:
729 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);
730cleanup_matches:
731 EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i);
732 return ret;
733}
734
735/*
736 * checks for loops and sets the hook mask for udc
737 * the hook mask for udc tells us from which base chains the udc can be
738 * accessed. This mask is a parameter to the check() functions of the extensions
739 */
740static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
741 unsigned int udc_cnt, unsigned int hooknr, char *base)
742{
743 int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
744 struct ebt_entry *e = (struct ebt_entry *)chain->data;
745 struct ebt_entry_target *t;
746
747 while (pos < nentries || chain_nr != -1) {
748 /* end of udc, go back one 'recursion' step */
749 if (pos == nentries) {
750 /* put back values of the time when this chain was called */
751 e = cl_s[chain_nr].cs.e;
752 if (cl_s[chain_nr].from != -1)
753 nentries =
754 cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
755 else
756 nentries = chain->nentries;
757 pos = cl_s[chain_nr].cs.n;
758 /* make sure we won't see a loop that isn't one */
759 cl_s[chain_nr].cs.n = 0;
760 chain_nr = cl_s[chain_nr].from;
761 if (pos == nentries)
762 continue;
763 }
764 t = (struct ebt_entry_target *)
765 (((char *)e) + e->target_offset);
766 if (strcmp(t->u.name, EBT_STANDARD_TARGET))
767 goto letscontinue;
768 if (e->target_offset + sizeof(struct ebt_standard_target) >
769 e->next_offset) {
770 BUGPRINT("Standard target size too big\n");
771 return -1;
772 }
773 verdict = ((struct ebt_standard_target *)t)->verdict;
774 if (verdict >= 0) { /* jump to another chain */
775 struct ebt_entries *hlp2 =
776 (struct ebt_entries *)(base + verdict);
777 for (i = 0; i < udc_cnt; i++)
778 if (hlp2 == cl_s[i].cs.chaininfo)
779 break;
780 /* bad destination or loop */
781 if (i == udc_cnt) {
782 BUGPRINT("bad destination\n");
783 return -1;
784 }
785 if (cl_s[i].cs.n) {
786 BUGPRINT("loop\n");
787 return -1;
788 }
Al Viro98a08242006-11-30 19:24:49 -0800789 if (cl_s[i].hookmask & (1 << hooknr))
790 goto letscontinue;
791 /* this can't be 0, so the loop test is correct */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 cl_s[i].cs.n = pos + 1;
793 pos = 0;
Jan Engelhardt98e86402009-04-15 21:06:05 +0200794 cl_s[i].cs.e = ebt_next_entry(e);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 e = (struct ebt_entry *)(hlp2->data);
796 nentries = hlp2->nentries;
797 cl_s[i].from = chain_nr;
798 chain_nr = i;
799 /* this udc is accessible from the base chain for hooknr */
800 cl_s[i].hookmask |= (1 << hooknr);
801 continue;
802 }
803letscontinue:
Jan Engelhardt98e86402009-04-15 21:06:05 +0200804 e = ebt_next_entry(e);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 pos++;
806 }
807 return 0;
808}
809
810/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
Al Viro1bc23262006-11-30 19:28:08 -0800811static int translate_table(char *name, struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812{
813 unsigned int i, j, k, udc_cnt;
814 int ret;
815 struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
816
817 i = 0;
Al Viro1f072c92006-11-30 19:26:53 -0800818 while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 i++;
820 if (i == NF_BR_NUMHOOKS) {
821 BUGPRINT("No valid hooks specified\n");
822 return -EINVAL;
823 }
Al Viro1f072c92006-11-30 19:26:53 -0800824 if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 BUGPRINT("Chains don't start at beginning\n");
826 return -EINVAL;
827 }
828 /* make sure chains are ordered after each other in same order
829 as their corresponding hooks */
830 for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
Al Viro1f072c92006-11-30 19:26:53 -0800831 if (!newinfo->hook_entry[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 continue;
Al Viro1f072c92006-11-30 19:26:53 -0800833 if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 BUGPRINT("Hook order must be followed\n");
835 return -EINVAL;
836 }
837 i = j;
838 }
839
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 /* do some early checkings and initialize some things */
841 i = 0; /* holds the expected nr. of entries for the chain */
842 j = 0; /* holds the up to now counted entries for the chain */
843 k = 0; /* holds the total nr. of entries, should equal
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900844 newinfo->nentries afterwards */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
846 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro0e795532006-11-30 19:27:13 -0800847 ebt_check_entry_size_and_hooks, newinfo,
848 &i, &j, &k, &udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849
850 if (ret != 0)
851 return ret;
852
853 if (i != j) {
854 BUGPRINT("nentries does not equal the nr of entries in the "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900855 "(last) chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 return -EINVAL;
857 }
858 if (k != newinfo->nentries) {
859 BUGPRINT("Total nentries is wrong\n");
860 return -EINVAL;
861 }
862
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 /* get the location of the udc, put them in an array
864 while we're at it, allocate the chainstack */
865 if (udc_cnt) {
866 /* this will get free'd in do_replace()/ebt_register_table()
867 if an error occurs */
Jayachandran C7ad4d2f2006-04-11 17:25:38 -0700868 newinfo->chainstack =
Christoph Lameter53b8a312007-02-20 13:57:51 -0800869 vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 if (!newinfo->chainstack)
871 return -ENOMEM;
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700872 for_each_possible_cpu(i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 newinfo->chainstack[i] =
Jayachandran C18bc89a2006-04-20 00:14:49 -0700874 vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 if (!newinfo->chainstack[i]) {
876 while (i)
877 vfree(newinfo->chainstack[--i]);
878 vfree(newinfo->chainstack);
879 newinfo->chainstack = NULL;
880 return -ENOMEM;
881 }
882 }
883
Jayachandran C18bc89a2006-04-20 00:14:49 -0700884 cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 if (!cl_s)
886 return -ENOMEM;
887 i = 0; /* the i'th udc */
888 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro177abc32006-11-30 19:27:32 -0800889 ebt_get_udc_positions, newinfo, &i, cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 /* sanity check */
891 if (i != udc_cnt) {
892 BUGPRINT("i != udc_cnt\n");
893 vfree(cl_s);
894 return -EFAULT;
895 }
896 }
897
898 /* Check for loops */
899 for (i = 0; i < NF_BR_NUMHOOKS; i++)
Al Viro1f072c92006-11-30 19:26:53 -0800900 if (newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 if (check_chainloops(newinfo->hook_entry[i],
902 cl_s, udc_cnt, i, newinfo->entries)) {
James Lamanna68d31872005-06-22 22:12:57 -0700903 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 return -EINVAL;
905 }
906
Jan Engelhardt96de0e22007-10-19 23:21:04 +0200907 /* we now know the following (along with E=mc²):
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 - the nr of entries in each chain is right
909 - the size of the allocated space is right
910 - all valid hooks have a corresponding chain
911 - there are no loops
912 - wrong data can still be on the level of a single entry
913 - could be there are jumps to places that are not the
914 beginning of a chain. This can only occur in chains that
915 are not accessible from any base chains, so we don't care. */
916
917 /* used to know what we need to clean up if something goes wrong */
918 i = 0;
919 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro1bc23262006-11-30 19:28:08 -0800920 ebt_check_entry, newinfo, name, &i, cl_s, udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 if (ret != 0) {
922 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
923 ebt_cleanup_entry, &i);
924 }
James Lamanna68d31872005-06-22 22:12:57 -0700925 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 return ret;
927}
928
929/* called under write_lock */
930static void get_counters(struct ebt_counter *oldcounters,
931 struct ebt_counter *counters, unsigned int nentries)
932{
933 int i, cpu;
934 struct ebt_counter *counter_base;
935
936 /* counters of cpu 0 */
937 memcpy(counters, oldcounters,
David S. Millerc8923c62005-10-13 14:41:23 -0700938 sizeof(struct ebt_counter) * nentries);
939
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 /* add other counters to those of cpu 0 */
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700941 for_each_possible_cpu(cpu) {
David S. Millerc8923c62005-10-13 14:41:23 -0700942 if (cpu == 0)
943 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
945 for (i = 0; i < nentries; i++) {
946 counters[i].pcnt += counter_base[i].pcnt;
947 counters[i].bcnt += counter_base[i].bcnt;
948 }
949 }
950}
951
952/* replace the table */
Alexey Dobriyan511061e2008-11-04 14:22:55 +0100953static int do_replace(struct net *net, void __user *user, unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954{
955 int ret, i, countersize;
956 struct ebt_table_info *newinfo;
957 struct ebt_replace tmp;
958 struct ebt_table *t;
959 struct ebt_counter *counterstmp = NULL;
960 /* used to be able to unlock earlier */
961 struct ebt_table_info *table;
962
963 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
964 return -EFAULT;
965
966 if (len != sizeof(tmp) + tmp.entries_size) {
967 BUGPRINT("Wrong len argument\n");
968 return -EINVAL;
969 }
970
971 if (tmp.entries_size == 0) {
972 BUGPRINT("Entries_size never zero\n");
973 return -EINVAL;
974 }
Kirill Korotaevee4bb812006-02-04 02:16:56 -0800975 /* overflow check */
976 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
977 SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
978 return -ENOMEM;
979 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
980 return -ENOMEM;
981
Christoph Lameter53b8a312007-02-20 13:57:51 -0800982 countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -0700983 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 if (!newinfo)
985 return -ENOMEM;
986
987 if (countersize)
988 memset(newinfo->counters, 0, countersize);
989
Kris Katterjohn8b3a7002006-01-11 15:56:43 -0800990 newinfo->entries = vmalloc(tmp.entries_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 if (!newinfo->entries) {
992 ret = -ENOMEM;
993 goto free_newinfo;
994 }
995 if (copy_from_user(
996 newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
997 BUGPRINT("Couldn't copy entries from userspace\n");
998 ret = -EFAULT;
999 goto free_entries;
1000 }
1001
1002 /* the user wants counters back
1003 the check on the size is done later, when we have the lock */
1004 if (tmp.num_counters) {
Jayachandran C18bc89a2006-04-20 00:14:49 -07001005 counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 if (!counterstmp) {
1007 ret = -ENOMEM;
1008 goto free_entries;
1009 }
1010 }
1011 else
1012 counterstmp = NULL;
1013
1014 /* this can get initialized by translate_table() */
1015 newinfo->chainstack = NULL;
Al Viro1bc23262006-11-30 19:28:08 -08001016 ret = ebt_verify_pointers(&tmp, newinfo);
1017 if (ret != 0)
1018 goto free_counterstmp;
1019
1020 ret = translate_table(tmp.name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021
1022 if (ret != 0)
1023 goto free_counterstmp;
1024
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001025 t = find_table_lock(net, tmp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 if (!t) {
1027 ret = -ENOENT;
1028 goto free_iterate;
1029 }
1030
1031 /* the table doesn't like it */
1032 if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
1033 goto free_unlock;
1034
1035 if (tmp.num_counters && tmp.num_counters != t->private->nentries) {
1036 BUGPRINT("Wrong nr. of counters requested\n");
1037 ret = -EINVAL;
1038 goto free_unlock;
1039 }
1040
1041 /* we have the mutex lock, so no danger in reading this pointer */
1042 table = t->private;
1043 /* make sure the table can only be rmmod'ed if it contains no rules */
1044 if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) {
1045 ret = -ENOENT;
1046 goto free_unlock;
1047 } else if (table->nentries && !newinfo->nentries)
1048 module_put(t->me);
1049 /* we need an atomic snapshot of the counters */
1050 write_lock_bh(&t->lock);
1051 if (tmp.num_counters)
1052 get_counters(t->private->counters, counterstmp,
1053 t->private->nentries);
1054
1055 t->private = newinfo;
1056 write_unlock_bh(&t->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001057 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 /* so, a user can change the chains while having messed up her counter
1059 allocation. Only reason why this is done is because this way the lock
1060 is held only once, while this doesn't bring the kernel into a
1061 dangerous state. */
1062 if (tmp.num_counters &&
1063 copy_to_user(tmp.counters, counterstmp,
1064 tmp.num_counters * sizeof(struct ebt_counter))) {
1065 BUGPRINT("Couldn't copy counters to userspace\n");
1066 ret = -EFAULT;
1067 }
1068 else
1069 ret = 0;
1070
1071 /* decrease module count and free resources */
1072 EBT_ENTRY_ITERATE(table->entries, table->entries_size,
1073 ebt_cleanup_entry, NULL);
1074
1075 vfree(table->entries);
1076 if (table->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001077 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 vfree(table->chainstack[i]);
1079 vfree(table->chainstack);
1080 }
1081 vfree(table);
1082
James Lamanna68d31872005-06-22 22:12:57 -07001083 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 return ret;
1085
1086free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001087 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088free_iterate:
1089 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
1090 ebt_cleanup_entry, NULL);
1091free_counterstmp:
James Lamanna68d31872005-06-22 22:12:57 -07001092 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 /* can be initialized in translate_table() */
1094 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001095 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 vfree(newinfo->chainstack[i]);
1097 vfree(newinfo->chainstack);
1098 }
1099free_entries:
James Lamanna68d31872005-06-22 22:12:57 -07001100 vfree(newinfo->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101free_newinfo:
James Lamanna68d31872005-06-22 22:12:57 -07001102 vfree(newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 return ret;
1104}
1105
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001106struct ebt_table *
1107ebt_register_table(struct net *net, const struct ebt_table *input_table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108{
1109 struct ebt_table_info *newinfo;
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001110 struct ebt_table *t, *table;
Al Viro1e419cd2006-11-30 19:28:48 -08001111 struct ebt_replace_kernel *repl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 int ret, i, countersize;
Al Virodf07a812006-11-30 19:28:25 -08001113 void *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001115 if (input_table == NULL || (repl = input_table->table) == NULL ||
1116 repl->entries == 0 || repl->entries_size == 0 ||
1117 repl->counters != NULL || input_table->private != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 BUGPRINT("Bad table data for ebt_register_table!!!\n");
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001119 return ERR_PTR(-EINVAL);
1120 }
1121
1122 /* Don't add one table to multiple lists. */
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001123 table = kmemdup(input_table, sizeof(struct ebt_table), GFP_KERNEL);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001124 if (!table) {
1125 ret = -ENOMEM;
1126 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 }
1128
Christoph Lameter53b8a312007-02-20 13:57:51 -08001129 countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -07001130 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 ret = -ENOMEM;
1132 if (!newinfo)
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001133 goto free_table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134
Al Virodf07a812006-11-30 19:28:25 -08001135 p = vmalloc(repl->entries_size);
1136 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 goto free_newinfo;
1138
Al Virodf07a812006-11-30 19:28:25 -08001139 memcpy(p, repl->entries, repl->entries_size);
1140 newinfo->entries = p;
1141
1142 newinfo->entries_size = repl->entries_size;
1143 newinfo->nentries = repl->nentries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
1145 if (countersize)
1146 memset(newinfo->counters, 0, countersize);
1147
1148 /* fill in newinfo and parse the entries */
1149 newinfo->chainstack = NULL;
Al Virodf07a812006-11-30 19:28:25 -08001150 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1151 if ((repl->valid_hooks & (1 << i)) == 0)
1152 newinfo->hook_entry[i] = NULL;
1153 else
1154 newinfo->hook_entry[i] = p +
1155 ((char *)repl->hook_entry[i] - repl->entries);
1156 }
1157 ret = translate_table(repl->name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 if (ret != 0) {
1159 BUGPRINT("Translate_table failed\n");
1160 goto free_chainstack;
1161 }
1162
1163 if (table->check && table->check(newinfo, table->valid_hooks)) {
1164 BUGPRINT("The table doesn't like its own initial data, lol\n");
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001165 return ERR_PTR(-EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 }
1167
1168 table->private = newinfo;
1169 rwlock_init(&table->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001170 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 if (ret != 0)
1172 goto free_chainstack;
1173
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001174 list_for_each_entry(t, &net->xt.tables[NFPROTO_BRIDGE], list) {
Patrick McHardydf0933d2006-09-20 11:57:53 -07001175 if (strcmp(t->name, table->name) == 0) {
1176 ret = -EEXIST;
1177 BUGPRINT("Table name already exists\n");
1178 goto free_unlock;
1179 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 }
1181
1182 /* Hold a reference count if the chains aren't empty */
1183 if (newinfo->nentries && !try_module_get(table->me)) {
1184 ret = -ENOENT;
1185 goto free_unlock;
1186 }
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001187 list_add(&table->list, &net->xt.tables[NFPROTO_BRIDGE]);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001188 mutex_unlock(&ebt_mutex);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001189 return table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001191 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192free_chainstack:
1193 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001194 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 vfree(newinfo->chainstack[i]);
1196 vfree(newinfo->chainstack);
1197 }
1198 vfree(newinfo->entries);
1199free_newinfo:
1200 vfree(newinfo);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001201free_table:
1202 kfree(table);
1203out:
1204 return ERR_PTR(ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205}
1206
1207void ebt_unregister_table(struct ebt_table *table)
1208{
1209 int i;
1210
1211 if (!table) {
1212 BUGPRINT("Request to unregister NULL table!!!\n");
1213 return;
1214 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001215 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001216 list_del(&table->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001217 mutex_unlock(&ebt_mutex);
Alexey Dobriyandbcdf852008-11-04 14:28:04 +01001218 EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size,
1219 ebt_cleanup_entry, NULL);
1220 if (table->private->nentries)
1221 module_put(table->me);
James Lamanna68d31872005-06-22 22:12:57 -07001222 vfree(table->private->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 if (table->private->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001224 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 vfree(table->private->chainstack[i]);
1226 vfree(table->private->chainstack);
1227 }
1228 vfree(table->private);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001229 kfree(table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230}
1231
1232/* userspace just supplied us with counters */
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001233static int update_counters(struct net *net, void __user *user, unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234{
1235 int i, ret;
1236 struct ebt_counter *tmp;
1237 struct ebt_replace hlp;
1238 struct ebt_table *t;
1239
1240 if (copy_from_user(&hlp, user, sizeof(hlp)))
1241 return -EFAULT;
1242
1243 if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
1244 return -EINVAL;
1245 if (hlp.num_counters == 0)
1246 return -EINVAL;
1247
Jayachandran C18bc89a2006-04-20 00:14:49 -07001248 if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 MEMPRINT("Update_counters && nomemory\n");
1250 return -ENOMEM;
1251 }
1252
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001253 t = find_table_lock(net, hlp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 if (!t)
1255 goto free_tmp;
1256
1257 if (hlp.num_counters != t->private->nentries) {
1258 BUGPRINT("Wrong nr of counters\n");
1259 ret = -EINVAL;
1260 goto unlock_mutex;
1261 }
1262
1263 if ( copy_from_user(tmp, hlp.counters,
1264 hlp.num_counters * sizeof(struct ebt_counter)) ) {
1265 BUGPRINT("Updata_counters && !cfu\n");
1266 ret = -EFAULT;
1267 goto unlock_mutex;
1268 }
1269
1270 /* we want an atomic add of the counters */
1271 write_lock_bh(&t->lock);
1272
1273 /* we add to the counters of the first cpu */
1274 for (i = 0; i < hlp.num_counters; i++) {
1275 t->private->counters[i].pcnt += tmp[i].pcnt;
1276 t->private->counters[i].bcnt += tmp[i].bcnt;
1277 }
1278
1279 write_unlock_bh(&t->lock);
1280 ret = 0;
1281unlock_mutex:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001282 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283free_tmp:
1284 vfree(tmp);
1285 return ret;
1286}
1287
1288static inline int ebt_make_matchname(struct ebt_entry_match *m,
Al Viro1e419cd2006-11-30 19:28:48 -08001289 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290{
Al Viro1e419cd2006-11-30 19:28:48 -08001291 char __user *hlp = ubase + ((char *)m - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
1293 return -EFAULT;
1294 return 0;
1295}
1296
1297static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
Al Viro1e419cd2006-11-30 19:28:48 -08001298 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299{
Al Viro1e419cd2006-11-30 19:28:48 -08001300 char __user *hlp = ubase + ((char *)w - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
1302 return -EFAULT;
1303 return 0;
1304}
1305
Al Viro1e419cd2006-11-30 19:28:48 -08001306static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307{
1308 int ret;
Al Viro1e419cd2006-11-30 19:28:48 -08001309 char __user *hlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 struct ebt_entry_target *t;
1311
Al Viro40642f92006-11-30 19:24:12 -08001312 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 return 0;
1314
Al Viro1e419cd2006-11-30 19:28:48 -08001315 hlp = ubase + (((char *)e + e->target_offset) - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +09001317
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
1319 if (ret != 0)
1320 return ret;
1321 ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
1322 if (ret != 0)
1323 return ret;
1324 if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
1325 return -EFAULT;
1326 return 0;
1327}
1328
Ingo Molnar57b47a52006-03-20 22:35:41 -08001329/* called with ebt_mutex locked */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330static int copy_everything_to_user(struct ebt_table *t, void __user *user,
1331 int *len, int cmd)
1332{
1333 struct ebt_replace tmp;
1334 struct ebt_counter *counterstmp, *oldcounters;
1335 unsigned int entries_size, nentries;
1336 char *entries;
1337
1338 if (cmd == EBT_SO_GET_ENTRIES) {
1339 entries_size = t->private->entries_size;
1340 nentries = t->private->nentries;
1341 entries = t->private->entries;
1342 oldcounters = t->private->counters;
1343 } else {
1344 entries_size = t->table->entries_size;
1345 nentries = t->table->nentries;
1346 entries = t->table->entries;
1347 oldcounters = t->table->counters;
1348 }
1349
1350 if (copy_from_user(&tmp, user, sizeof(tmp))) {
1351 BUGPRINT("Cfu didn't work\n");
1352 return -EFAULT;
1353 }
1354
1355 if (*len != sizeof(struct ebt_replace) + entries_size +
1356 (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
1357 BUGPRINT("Wrong size\n");
1358 return -EINVAL;
1359 }
1360
1361 if (tmp.nentries != nentries) {
1362 BUGPRINT("Nentries wrong\n");
1363 return -EINVAL;
1364 }
1365
1366 if (tmp.entries_size != entries_size) {
1367 BUGPRINT("Wrong size\n");
1368 return -EINVAL;
1369 }
1370
1371 /* userspace might not need the counters */
1372 if (tmp.num_counters) {
1373 if (tmp.num_counters != nentries) {
1374 BUGPRINT("Num_counters wrong\n");
1375 return -EINVAL;
1376 }
Jayachandran C18bc89a2006-04-20 00:14:49 -07001377 counterstmp = vmalloc(nentries * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 if (!counterstmp) {
1379 MEMPRINT("Couldn't copy counters, out of memory\n");
1380 return -ENOMEM;
1381 }
1382 write_lock_bh(&t->lock);
1383 get_counters(oldcounters, counterstmp, nentries);
1384 write_unlock_bh(&t->lock);
1385
1386 if (copy_to_user(tmp.counters, counterstmp,
1387 nentries * sizeof(struct ebt_counter))) {
1388 BUGPRINT("Couldn't copy counters to userspace\n");
1389 vfree(counterstmp);
1390 return -EFAULT;
1391 }
1392 vfree(counterstmp);
1393 }
1394
1395 if (copy_to_user(tmp.entries, entries, entries_size)) {
1396 BUGPRINT("Couldn't copy entries to userspace\n");
1397 return -EFAULT;
1398 }
1399 /* set the match/watcher/target names right */
1400 return EBT_ENTRY_ITERATE(entries, entries_size,
1401 ebt_make_names, entries, tmp.entries);
1402}
1403
1404static int do_ebt_set_ctl(struct sock *sk,
1405 int cmd, void __user *user, unsigned int len)
1406{
1407 int ret;
1408
1409 switch(cmd) {
1410 case EBT_SO_SET_ENTRIES:
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001411 ret = do_replace(sock_net(sk), user, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 break;
1413 case EBT_SO_SET_COUNTERS:
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001414 ret = update_counters(sock_net(sk), user, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 break;
1416 default:
1417 ret = -EINVAL;
1418 }
1419 return ret;
1420}
1421
1422static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1423{
1424 int ret;
1425 struct ebt_replace tmp;
1426 struct ebt_table *t;
1427
1428 if (copy_from_user(&tmp, user, sizeof(tmp)))
1429 return -EFAULT;
1430
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001431 t = find_table_lock(sock_net(sk), tmp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 if (!t)
1433 return ret;
1434
1435 switch(cmd) {
1436 case EBT_SO_GET_INFO:
1437 case EBT_SO_GET_INIT_INFO:
1438 if (*len != sizeof(struct ebt_replace)){
1439 ret = -EINVAL;
Ingo Molnar57b47a52006-03-20 22:35:41 -08001440 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 break;
1442 }
1443 if (cmd == EBT_SO_GET_INFO) {
1444 tmp.nentries = t->private->nentries;
1445 tmp.entries_size = t->private->entries_size;
1446 tmp.valid_hooks = t->valid_hooks;
1447 } else {
1448 tmp.nentries = t->table->nentries;
1449 tmp.entries_size = t->table->entries_size;
1450 tmp.valid_hooks = t->table->valid_hooks;
1451 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001452 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 if (copy_to_user(user, &tmp, *len) != 0){
1454 BUGPRINT("c2u Didn't work\n");
1455 ret = -EFAULT;
1456 break;
1457 }
1458 ret = 0;
1459 break;
1460
1461 case EBT_SO_GET_ENTRIES:
1462 case EBT_SO_GET_INIT_ENTRIES:
1463 ret = copy_everything_to_user(t, user, len, cmd);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001464 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 break;
1466
1467 default:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001468 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 ret = -EINVAL;
1470 }
1471
1472 return ret;
1473}
1474
1475static struct nf_sockopt_ops ebt_sockopts =
Andrew Morton74ca4e5a2006-03-20 22:55:02 -08001476{
1477 .pf = PF_INET,
1478 .set_optmin = EBT_BASE_CTL,
1479 .set_optmax = EBT_SO_SET_MAX + 1,
1480 .set = do_ebt_set_ctl,
1481 .get_optmin = EBT_BASE_CTL,
1482 .get_optmax = EBT_SO_GET_MAX + 1,
1483 .get = do_ebt_get_ctl,
Neil Horman16fcec32007-09-11 11:28:26 +02001484 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485};
1486
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001487static int __init ebtables_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488{
1489 int ret;
1490
Jan Engelhardt043ef462008-10-08 11:35:15 +02001491 ret = xt_register_target(&ebt_standard_target);
1492 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 return ret;
Jan Engelhardt043ef462008-10-08 11:35:15 +02001494 ret = nf_register_sockopt(&ebt_sockopts);
1495 if (ret < 0) {
1496 xt_unregister_target(&ebt_standard_target);
1497 return ret;
1498 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499
Patrick McHardya887c1c2007-07-14 20:46:15 -07001500 printk(KERN_INFO "Ebtables v2.0 registered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 return 0;
1502}
1503
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001504static void __exit ebtables_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505{
1506 nf_unregister_sockopt(&ebt_sockopts);
Jan Engelhardt043ef462008-10-08 11:35:15 +02001507 xt_unregister_target(&ebt_standard_target);
Patrick McHardya887c1c2007-07-14 20:46:15 -07001508 printk(KERN_INFO "Ebtables v2.0 unregistered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509}
1510
1511EXPORT_SYMBOL(ebt_register_table);
1512EXPORT_SYMBOL(ebt_unregister_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513EXPORT_SYMBOL(ebt_do_table);
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001514module_init(ebtables_init);
1515module_exit(ebtables_fini);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516MODULE_LICENSE("GPL");