blob: 82e17527e21ed5936d177694f7c5732d936aa6b6 [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;
82 return m->u.match->match(skb, par);
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;
Meelis Roos6f5b7ef2006-11-01 18:07:27 -080088 const char *devname = device->name;
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90 if (*entry == '\0')
91 return 0;
92 if (!device)
93 return 1;
94 /* 1 is the wildcard token */
95 while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i])
96 i++;
97 return (devname[i] != entry[i] && entry[i] != 1);
98}
99
100#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
101/* process standard matches */
102static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h,
103 const struct net_device *in, const struct net_device *out)
104{
105 int verdict, i;
106
107 if (e->bitmask & EBT_802_3) {
108 if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO))
109 return 1;
110 } else if (!(e->bitmask & EBT_NOPROTO) &&
111 FWINV2(e->ethproto != h->h_proto, EBT_IPROTO))
112 return 1;
113
114 if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
115 return 1;
116 if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
117 return 1;
118 if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check(
119 e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN))
120 return 1;
121 if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check(
122 e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT))
123 return 1;
124
125 if (e->bitmask & EBT_SOURCEMAC) {
126 verdict = 0;
127 for (i = 0; i < 6; i++)
128 verdict |= (h->h_source[i] ^ e->sourcemac[i]) &
129 e->sourcemsk[i];
130 if (FWINV2(verdict != 0, EBT_ISOURCE) )
131 return 1;
132 }
133 if (e->bitmask & EBT_DESTMAC) {
134 verdict = 0;
135 for (i = 0; i < 6; i++)
136 verdict |= (h->h_dest[i] ^ e->destmac[i]) &
137 e->destmsk[i];
138 if (FWINV2(verdict != 0, EBT_IDEST) )
139 return 1;
140 }
141 return 0;
142}
143
144/* Do some firewalling */
Herbert Xu3db05fe2007-10-15 00:53:15 -0700145unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 const struct net_device *in, const struct net_device *out,
147 struct ebt_table *table)
148{
149 int i, nentries;
150 struct ebt_entry *point;
151 struct ebt_counter *counter_base, *cb_base;
152 struct ebt_entry_target *t;
153 int verdict, sp = 0;
154 struct ebt_chainstack *cs;
155 struct ebt_entries *chaininfo;
156 char *base;
157 struct ebt_table_info *private;
Jan Engelhardt5365f802008-10-08 11:35:16 +0200158 bool hotdrop = false;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200159 struct xt_match_param mtpar;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200160 struct xt_target_param tgpar;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200161
Jan Engelhardt916a9172008-10-08 11:35:20 +0200162 mtpar.family = tgpar.family = NFPROTO_BRIDGE;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200163 mtpar.in = tgpar.in = in;
164 mtpar.out = tgpar.out = out;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200165 mtpar.hotdrop = &hotdrop;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200166 tgpar.hooknum = hook;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
168 read_lock_bh(&table->lock);
169 private = table->private;
170 cb_base = COUNTER_BASE(private->counters, private->nentries,
171 smp_processor_id());
172 if (private->chainstack)
173 cs = private->chainstack[smp_processor_id()];
174 else
175 cs = NULL;
176 chaininfo = private->hook_entry[hook];
177 nentries = private->hook_entry[hook]->nentries;
178 point = (struct ebt_entry *)(private->hook_entry[hook]->data);
179 counter_base = cb_base + private->hook_entry[hook]->counter_offset;
180 /* base for chain jumps */
181 base = private->entries;
182 i = 0;
183 while (i < nentries) {
Herbert Xu3db05fe2007-10-15 00:53:15 -0700184 if (ebt_basic_match(point, eth_hdr(skb), in, out))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 goto letscontinue;
186
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200187 if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, &mtpar) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 goto letscontinue;
Jan Engelhardt5365f802008-10-08 11:35:16 +0200189 if (hotdrop) {
190 read_unlock_bh(&table->lock);
191 return NF_DROP;
192 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
194 /* increase counter */
195 (*(counter_base + i)).pcnt++;
Herbert Xu3db05fe2007-10-15 00:53:15 -0700196 (*(counter_base + i)).bcnt += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
198 /* these should only watch: not modify, nor tell us
199 what to do with the packet */
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200200 EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, &tgpar);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
202 t = (struct ebt_entry_target *)
203 (((char *)point) + point->target_offset);
204 /* standard target */
205 if (!t->u.target->target)
206 verdict = ((struct ebt_standard_target *)t)->verdict;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200207 else {
208 tgpar.target = t->u.target;
209 tgpar.targinfo = t->data;
210 verdict = t->u.target->target(skb, &tgpar);
211 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 if (verdict == EBT_ACCEPT) {
213 read_unlock_bh(&table->lock);
214 return NF_ACCEPT;
215 }
216 if (verdict == EBT_DROP) {
217 read_unlock_bh(&table->lock);
218 return NF_DROP;
219 }
220 if (verdict == EBT_RETURN) {
221letsreturn:
222#ifdef CONFIG_NETFILTER_DEBUG
223 if (sp == 0) {
224 BUGPRINT("RETURN on base chain");
225 /* act like this is EBT_CONTINUE */
226 goto letscontinue;
227 }
228#endif
229 sp--;
230 /* put all the local variables right */
231 i = cs[sp].n;
232 chaininfo = cs[sp].chaininfo;
233 nentries = chaininfo->nentries;
234 point = cs[sp].e;
235 counter_base = cb_base +
236 chaininfo->counter_offset;
237 continue;
238 }
239 if (verdict == EBT_CONTINUE)
240 goto letscontinue;
241#ifdef CONFIG_NETFILTER_DEBUG
242 if (verdict < 0) {
243 BUGPRINT("bogus standard verdict\n");
244 read_unlock_bh(&table->lock);
245 return NF_DROP;
246 }
247#endif
248 /* jump to a udc */
249 cs[sp].n = i + 1;
250 cs[sp].chaininfo = chaininfo;
251 cs[sp].e = (struct ebt_entry *)
252 (((char *)point) + point->next_offset);
253 i = 0;
254 chaininfo = (struct ebt_entries *) (base + verdict);
255#ifdef CONFIG_NETFILTER_DEBUG
256 if (chaininfo->distinguisher) {
257 BUGPRINT("jump to non-chain\n");
258 read_unlock_bh(&table->lock);
259 return NF_DROP;
260 }
261#endif
262 nentries = chaininfo->nentries;
263 point = (struct ebt_entry *)chaininfo->data;
264 counter_base = cb_base + chaininfo->counter_offset;
265 sp++;
266 continue;
267letscontinue:
268 point = (struct ebt_entry *)
269 (((char *)point) + point->next_offset);
270 i++;
271 }
272
273 /* I actually like this :) */
274 if (chaininfo->policy == EBT_RETURN)
275 goto letsreturn;
276 if (chaininfo->policy == EBT_ACCEPT) {
277 read_unlock_bh(&table->lock);
278 return NF_ACCEPT;
279 }
280 read_unlock_bh(&table->lock);
281 return NF_DROP;
282}
283
284/* If it succeeds, returns element and locks mutex */
285static inline void *
286find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800287 struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288{
Patrick McHardydf0933d2006-09-20 11:57:53 -0700289 struct {
290 struct list_head list;
291 char name[EBT_FUNCTION_MAXNAMELEN];
292 } *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
Ingo Molnar57b47a52006-03-20 22:35:41 -0800294 *error = mutex_lock_interruptible(mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 if (*error != 0)
296 return NULL;
297
Patrick McHardydf0933d2006-09-20 11:57:53 -0700298 list_for_each_entry(e, head, list) {
299 if (strcmp(e->name, name) == 0)
300 return e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 }
Patrick McHardydf0933d2006-09-20 11:57:53 -0700302 *error = -ENOENT;
303 mutex_unlock(mutex);
304 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305}
306
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307static void *
308find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800309 int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310{
Johannes Berg95a5afc2008-10-16 15:24:51 -0700311 return try_then_request_module(
312 find_inlist_lock_noload(head, name, error, mutex),
313 "%s%s", prefix, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
316static inline struct ebt_table *
Alexey Dobriyan511061e2008-11-04 14:22:55 +0100317find_table_lock(struct net *net, const char *name, int *error,
318 struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319{
Alexey Dobriyan511061e2008-11-04 14:22:55 +0100320 return find_inlist_lock(&net->xt.tables[NFPROTO_BRIDGE], name,
321 "ebtable_", error, mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322}
323
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324static inline int
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200325ebt_check_match(struct ebt_entry_match *m, struct xt_mtchk_param *par,
326 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327{
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200328 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200329 struct xt_match *match;
Al Viro14197d52006-11-30 19:25:21 -0800330 size_t left = ((char *)e + e->watchers_offset) - (char *)m;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 int ret;
332
Al Viro14197d52006-11-30 19:25:21 -0800333 if (left < sizeof(struct ebt_entry_match) ||
334 left - sizeof(struct ebt_entry_match) < m->match_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200336
337 match = try_then_request_module(xt_find_match(NFPROTO_BRIDGE,
338 m->u.name, 0), "ebt_%s", m->u.name);
339 if (IS_ERR(match))
340 return PTR_ERR(match);
341 if (match == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200343 m->u.match = match;
344
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200345 par->match = match;
346 par->matchinfo = m->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200347 ret = xt_check_match(par, m->match_size,
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200348 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200349 if (ret < 0) {
350 module_put(match->me);
351 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200353
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 (*cnt)++;
355 return 0;
356}
357
358static inline int
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200359ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
360 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361{
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200362 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200363 struct xt_target *watcher;
Al Viro14197d52006-11-30 19:25:21 -0800364 size_t left = ((char *)e + e->target_offset) - (char *)w;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 int ret;
366
Al Viro14197d52006-11-30 19:25:21 -0800367 if (left < sizeof(struct ebt_entry_watcher) ||
368 left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200370
371 watcher = try_then_request_module(
372 xt_find_target(NFPROTO_BRIDGE, w->u.name, 0),
373 "ebt_%s", w->u.name);
374 if (IS_ERR(watcher))
375 return PTR_ERR(watcher);
376 if (watcher == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200378 w->u.watcher = watcher;
379
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200380 par->target = watcher;
381 par->targinfo = w->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200382 ret = xt_check_target(par, w->watcher_size,
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200383 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200384 if (ret < 0) {
385 module_put(watcher->me);
386 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200388
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 (*cnt)++;
390 return 0;
391}
392
Al Viro70fe9af2006-11-30 19:26:14 -0800393static int ebt_verify_pointers(struct ebt_replace *repl,
394 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395{
Al Viro70fe9af2006-11-30 19:26:14 -0800396 unsigned int limit = repl->entries_size;
397 unsigned int valid_hooks = repl->valid_hooks;
398 unsigned int offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 int i;
400
Al Viroe4fd77d2006-11-30 19:26:35 -0800401 for (i = 0; i < NF_BR_NUMHOOKS; i++)
402 newinfo->hook_entry[i] = NULL;
403
404 newinfo->entries_size = repl->entries_size;
405 newinfo->nentries = repl->nentries;
406
Al Viro70fe9af2006-11-30 19:26:14 -0800407 while (offset < limit) {
408 size_t left = limit - offset;
409 struct ebt_entry *e = (void *)newinfo->entries + offset;
Al Virobb2ef252006-11-30 19:22:42 -0800410
Al Viro70fe9af2006-11-30 19:26:14 -0800411 if (left < sizeof(unsigned int))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 break;
Al Viro22b440b2006-11-30 19:25:51 -0800413
Al Viro70fe9af2006-11-30 19:26:14 -0800414 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
415 if ((valid_hooks & (1 << i)) == 0)
416 continue;
Al Viro1e419cd2006-11-30 19:28:48 -0800417 if ((char __user *)repl->hook_entry[i] ==
418 repl->entries + offset)
Al Viro70fe9af2006-11-30 19:26:14 -0800419 break;
420 }
421
422 if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
423 if (e->bitmask != 0) {
424 /* we make userspace set this right,
425 so there is no misunderstanding */
426 BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
427 "in distinguisher\n");
428 return -EINVAL;
429 }
430 if (i != NF_BR_NUMHOOKS)
431 newinfo->hook_entry[i] = (struct ebt_entries *)e;
432 if (left < sizeof(struct ebt_entries))
433 break;
434 offset += sizeof(struct ebt_entries);
435 } else {
436 if (left < sizeof(struct ebt_entry))
437 break;
438 if (left < e->next_offset)
439 break;
440 offset += e->next_offset;
441 }
442 }
443 if (offset != limit) {
444 BUGPRINT("entries_size too small\n");
445 return -EINVAL;
446 }
Al Viroe4fd77d2006-11-30 19:26:35 -0800447
448 /* check if all valid hooks have a chain */
449 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
450 if (!newinfo->hook_entry[i] &&
451 (valid_hooks & (1 << i))) {
452 BUGPRINT("Valid hook without chain\n");
453 return -EINVAL;
454 }
455 }
Al Viro70fe9af2006-11-30 19:26:14 -0800456 return 0;
Al Viro22b440b2006-11-30 19:25:51 -0800457}
458
459/*
460 * this one is very careful, as it is the first function
461 * to parse the userspace data
462 */
463static inline int
464ebt_check_entry_size_and_hooks(struct ebt_entry *e,
Al Viro0e795532006-11-30 19:27:13 -0800465 struct ebt_table_info *newinfo,
466 unsigned int *n, unsigned int *cnt,
467 unsigned int *totalcnt, unsigned int *udc_cnt)
Al Viro22b440b2006-11-30 19:25:51 -0800468{
Al Viro22b440b2006-11-30 19:25:51 -0800469 int i;
470
471 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Viro0e795532006-11-30 19:27:13 -0800472 if ((void *)e == (void *)newinfo->hook_entry[i])
Al Viro22b440b2006-11-30 19:25:51 -0800473 break;
474 }
475 /* beginning of a new chain
476 if i == NF_BR_NUMHOOKS it must be a user defined chain */
477 if (i != NF_BR_NUMHOOKS || !e->bitmask) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 /* this checks if the previous chain has as many entries
479 as it said it has */
480 if (*n != *cnt) {
481 BUGPRINT("nentries does not equal the nr of entries "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900482 "in the chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 return -EINVAL;
484 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 if (((struct ebt_entries *)e)->policy != EBT_DROP &&
486 ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
487 /* only RETURN from udc */
488 if (i != NF_BR_NUMHOOKS ||
489 ((struct ebt_entries *)e)->policy != EBT_RETURN) {
490 BUGPRINT("bad policy\n");
491 return -EINVAL;
492 }
493 }
494 if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
495 (*udc_cnt)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
497 BUGPRINT("counter_offset != totalcnt");
498 return -EINVAL;
499 }
500 *n = ((struct ebt_entries *)e)->nentries;
501 *cnt = 0;
502 return 0;
503 }
504 /* a plain old entry, heh */
505 if (sizeof(struct ebt_entry) > e->watchers_offset ||
506 e->watchers_offset > e->target_offset ||
507 e->target_offset >= e->next_offset) {
508 BUGPRINT("entry offsets not in right order\n");
509 return -EINVAL;
510 }
511 /* this is not checked anywhere else */
512 if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
513 BUGPRINT("target size too small\n");
514 return -EINVAL;
515 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 (*cnt)++;
517 (*totalcnt)++;
518 return 0;
519}
520
521struct ebt_cl_stack
522{
523 struct ebt_chainstack cs;
524 int from;
525 unsigned int hookmask;
526};
527
528/*
529 * we need these positions to check that the jumps to a different part of the
530 * entries is a jump to the beginning of a new chain.
531 */
532static inline int
533ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Viro177abc32006-11-30 19:27:32 -0800534 unsigned int *n, struct ebt_cl_stack *udc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535{
536 int i;
537
538 /* we're only interested in chain starts */
Al Viro40642f92006-11-30 19:24:12 -0800539 if (e->bitmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 return 0;
541 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
543 break;
544 }
545 /* only care about udc */
546 if (i != NF_BR_NUMHOOKS)
547 return 0;
548
549 udc[*n].cs.chaininfo = (struct ebt_entries *)e;
550 /* these initialisations are depended on later in check_chainloops() */
551 udc[*n].cs.n = 0;
552 udc[*n].hookmask = 0;
553
554 (*n)++;
555 return 0;
556}
557
558static inline int
559ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i)
560{
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200561 struct xt_mtdtor_param par;
562
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 if (i && (*i)-- == 0)
564 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200566 par.match = m->u.match;
567 par.matchinfo = m->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200568 par.family = NFPROTO_BRIDGE;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200569 if (par.match->destroy != NULL)
570 par.match->destroy(&par);
571 module_put(par.match->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 return 0;
573}
574
575static inline int
576ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
577{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200578 struct xt_tgdtor_param par;
579
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 if (i && (*i)-- == 0)
581 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582
Jan Engelhardta2df1642008-10-08 11:35:19 +0200583 par.target = w->u.watcher;
584 par.targinfo = w->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200585 par.family = NFPROTO_BRIDGE;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200586 if (par.target->destroy != NULL)
587 par.target->destroy(&par);
588 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 return 0;
590}
591
592static inline int
593ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
594{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200595 struct xt_tgdtor_param par;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 struct ebt_entry_target *t;
597
Al Viro40642f92006-11-30 19:24:12 -0800598 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 return 0;
600 /* we're done */
601 if (cnt && (*cnt)-- == 0)
602 return 1;
603 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
604 EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL);
605 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
Jan Engelhardta2df1642008-10-08 11:35:19 +0200607 par.target = t->u.target;
608 par.targinfo = t->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200609 par.family = NFPROTO_BRIDGE;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200610 if (par.target->destroy != NULL)
611 par.target->destroy(&par);
612 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 return 0;
614}
615
616static inline int
617ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Virof7da79d2006-11-30 19:27:48 -0800618 const char *name, unsigned int *cnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
620{
621 struct ebt_entry_target *t;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200622 struct xt_target *target;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 unsigned int i, j, hook = 0, hookmask = 0;
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800624 size_t gap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 int ret;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200626 struct xt_mtchk_param mtpar;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200627 struct xt_tgchk_param tgpar;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
629 /* don't mess with the struct ebt_entries */
Al Viro40642f92006-11-30 19:24:12 -0800630 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 return 0;
632
633 if (e->bitmask & ~EBT_F_MASK) {
634 BUGPRINT("Unknown flag for bitmask\n");
635 return -EINVAL;
636 }
637 if (e->invflags & ~EBT_INV_MASK) {
638 BUGPRINT("Unknown flag for inv bitmask\n");
639 return -EINVAL;
640 }
641 if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
642 BUGPRINT("NOPROTO & 802_3 not allowed\n");
643 return -EINVAL;
644 }
645 /* what hook do we belong to? */
646 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Virof7da79d2006-11-30 19:27:48 -0800647 if (!newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 continue;
649 if ((char *)newinfo->hook_entry[i] < (char *)e)
650 hook = i;
651 else
652 break;
653 }
654 /* (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
655 a base chain */
656 if (i < NF_BR_NUMHOOKS)
657 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
658 else {
659 for (i = 0; i < udc_cnt; i++)
660 if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
661 break;
662 if (i == 0)
663 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
664 else
665 hookmask = cl_s[i - 1].hookmask;
666 }
667 i = 0;
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200668
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200669 mtpar.table = tgpar.table = name;
670 mtpar.entryinfo = tgpar.entryinfo = e;
671 mtpar.hook_mask = tgpar.hook_mask = hookmask;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200672 mtpar.family = tgpar.family = NFPROTO_BRIDGE;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200673 ret = EBT_MATCH_ITERATE(e, ebt_check_match, &mtpar, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 if (ret != 0)
675 goto cleanup_matches;
676 j = 0;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200677 ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, &tgpar, &j);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 if (ret != 0)
679 goto cleanup_watchers;
680 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800681 gap = e->next_offset - e->target_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
Jan Engelhardt043ef462008-10-08 11:35:15 +0200683 target = try_then_request_module(
684 xt_find_target(NFPROTO_BRIDGE, t->u.name, 0),
685 "ebt_%s", t->u.name);
686 if (IS_ERR(target)) {
687 ret = PTR_ERR(target);
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200688 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200689 } else if (target == NULL) {
690 ret = -ENOENT;
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200691 goto cleanup_watchers;
692 }
693
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 t->u.target = target;
695 if (t->u.target == &ebt_standard_target) {
Al Viro14197d52006-11-30 19:25:21 -0800696 if (gap < sizeof(struct ebt_standard_target)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 BUGPRINT("Standard target size too big\n");
698 ret = -EFAULT;
699 goto cleanup_watchers;
700 }
701 if (((struct ebt_standard_target *)t)->verdict <
702 -NUM_STANDARD_TARGETS) {
703 BUGPRINT("Invalid standard target\n");
704 ret = -EFAULT;
705 goto cleanup_watchers;
706 }
Jan Engelhardt18219d32008-10-08 11:35:13 +0200707 } else if (t->target_size > gap - sizeof(struct ebt_entry_target)) {
708 module_put(t->u.target->me);
709 ret = -EFAULT;
710 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200711 }
712
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200713 tgpar.target = target;
714 tgpar.targinfo = t->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200715 ret = xt_check_target(&tgpar, t->target_size,
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200716 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200717 if (ret < 0) {
718 module_put(target->me);
Jan Engelhardt18219d32008-10-08 11:35:13 +0200719 goto cleanup_watchers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 }
721 (*cnt)++;
722 return 0;
723cleanup_watchers:
724 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);
725cleanup_matches:
726 EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i);
727 return ret;
728}
729
730/*
731 * checks for loops and sets the hook mask for udc
732 * the hook mask for udc tells us from which base chains the udc can be
733 * accessed. This mask is a parameter to the check() functions of the extensions
734 */
735static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
736 unsigned int udc_cnt, unsigned int hooknr, char *base)
737{
738 int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
739 struct ebt_entry *e = (struct ebt_entry *)chain->data;
740 struct ebt_entry_target *t;
741
742 while (pos < nentries || chain_nr != -1) {
743 /* end of udc, go back one 'recursion' step */
744 if (pos == nentries) {
745 /* put back values of the time when this chain was called */
746 e = cl_s[chain_nr].cs.e;
747 if (cl_s[chain_nr].from != -1)
748 nentries =
749 cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
750 else
751 nentries = chain->nentries;
752 pos = cl_s[chain_nr].cs.n;
753 /* make sure we won't see a loop that isn't one */
754 cl_s[chain_nr].cs.n = 0;
755 chain_nr = cl_s[chain_nr].from;
756 if (pos == nentries)
757 continue;
758 }
759 t = (struct ebt_entry_target *)
760 (((char *)e) + e->target_offset);
761 if (strcmp(t->u.name, EBT_STANDARD_TARGET))
762 goto letscontinue;
763 if (e->target_offset + sizeof(struct ebt_standard_target) >
764 e->next_offset) {
765 BUGPRINT("Standard target size too big\n");
766 return -1;
767 }
768 verdict = ((struct ebt_standard_target *)t)->verdict;
769 if (verdict >= 0) { /* jump to another chain */
770 struct ebt_entries *hlp2 =
771 (struct ebt_entries *)(base + verdict);
772 for (i = 0; i < udc_cnt; i++)
773 if (hlp2 == cl_s[i].cs.chaininfo)
774 break;
775 /* bad destination or loop */
776 if (i == udc_cnt) {
777 BUGPRINT("bad destination\n");
778 return -1;
779 }
780 if (cl_s[i].cs.n) {
781 BUGPRINT("loop\n");
782 return -1;
783 }
Al Viro98a08242006-11-30 19:24:49 -0800784 if (cl_s[i].hookmask & (1 << hooknr))
785 goto letscontinue;
786 /* this can't be 0, so the loop test is correct */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 cl_s[i].cs.n = pos + 1;
788 pos = 0;
789 cl_s[i].cs.e = ((void *)e + e->next_offset);
790 e = (struct ebt_entry *)(hlp2->data);
791 nentries = hlp2->nentries;
792 cl_s[i].from = chain_nr;
793 chain_nr = i;
794 /* this udc is accessible from the base chain for hooknr */
795 cl_s[i].hookmask |= (1 << hooknr);
796 continue;
797 }
798letscontinue:
799 e = (void *)e + e->next_offset;
800 pos++;
801 }
802 return 0;
803}
804
805/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
Al Viro1bc23262006-11-30 19:28:08 -0800806static int translate_table(char *name, struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807{
808 unsigned int i, j, k, udc_cnt;
809 int ret;
810 struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
811
812 i = 0;
Al Viro1f072c92006-11-30 19:26:53 -0800813 while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 i++;
815 if (i == NF_BR_NUMHOOKS) {
816 BUGPRINT("No valid hooks specified\n");
817 return -EINVAL;
818 }
Al Viro1f072c92006-11-30 19:26:53 -0800819 if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 BUGPRINT("Chains don't start at beginning\n");
821 return -EINVAL;
822 }
823 /* make sure chains are ordered after each other in same order
824 as their corresponding hooks */
825 for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
Al Viro1f072c92006-11-30 19:26:53 -0800826 if (!newinfo->hook_entry[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 continue;
Al Viro1f072c92006-11-30 19:26:53 -0800828 if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 BUGPRINT("Hook order must be followed\n");
830 return -EINVAL;
831 }
832 i = j;
833 }
834
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 /* do some early checkings and initialize some things */
836 i = 0; /* holds the expected nr. of entries for the chain */
837 j = 0; /* holds the up to now counted entries for the chain */
838 k = 0; /* holds the total nr. of entries, should equal
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900839 newinfo->nentries afterwards */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
841 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro0e795532006-11-30 19:27:13 -0800842 ebt_check_entry_size_and_hooks, newinfo,
843 &i, &j, &k, &udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
845 if (ret != 0)
846 return ret;
847
848 if (i != j) {
849 BUGPRINT("nentries does not equal the nr of entries in the "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900850 "(last) chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 return -EINVAL;
852 }
853 if (k != newinfo->nentries) {
854 BUGPRINT("Total nentries is wrong\n");
855 return -EINVAL;
856 }
857
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 /* get the location of the udc, put them in an array
859 while we're at it, allocate the chainstack */
860 if (udc_cnt) {
861 /* this will get free'd in do_replace()/ebt_register_table()
862 if an error occurs */
Jayachandran C7ad4d2f2006-04-11 17:25:38 -0700863 newinfo->chainstack =
Christoph Lameter53b8a312007-02-20 13:57:51 -0800864 vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 if (!newinfo->chainstack)
866 return -ENOMEM;
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700867 for_each_possible_cpu(i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 newinfo->chainstack[i] =
Jayachandran C18bc89a2006-04-20 00:14:49 -0700869 vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 if (!newinfo->chainstack[i]) {
871 while (i)
872 vfree(newinfo->chainstack[--i]);
873 vfree(newinfo->chainstack);
874 newinfo->chainstack = NULL;
875 return -ENOMEM;
876 }
877 }
878
Jayachandran C18bc89a2006-04-20 00:14:49 -0700879 cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 if (!cl_s)
881 return -ENOMEM;
882 i = 0; /* the i'th udc */
883 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro177abc32006-11-30 19:27:32 -0800884 ebt_get_udc_positions, newinfo, &i, cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 /* sanity check */
886 if (i != udc_cnt) {
887 BUGPRINT("i != udc_cnt\n");
888 vfree(cl_s);
889 return -EFAULT;
890 }
891 }
892
893 /* Check for loops */
894 for (i = 0; i < NF_BR_NUMHOOKS; i++)
Al Viro1f072c92006-11-30 19:26:53 -0800895 if (newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 if (check_chainloops(newinfo->hook_entry[i],
897 cl_s, udc_cnt, i, newinfo->entries)) {
James Lamanna68d31872005-06-22 22:12:57 -0700898 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 return -EINVAL;
900 }
901
Jan Engelhardt96de0e22007-10-19 23:21:04 +0200902 /* we now know the following (along with E=mc²):
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 - the nr of entries in each chain is right
904 - the size of the allocated space is right
905 - all valid hooks have a corresponding chain
906 - there are no loops
907 - wrong data can still be on the level of a single entry
908 - could be there are jumps to places that are not the
909 beginning of a chain. This can only occur in chains that
910 are not accessible from any base chains, so we don't care. */
911
912 /* used to know what we need to clean up if something goes wrong */
913 i = 0;
914 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro1bc23262006-11-30 19:28:08 -0800915 ebt_check_entry, newinfo, name, &i, cl_s, udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 if (ret != 0) {
917 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
918 ebt_cleanup_entry, &i);
919 }
James Lamanna68d31872005-06-22 22:12:57 -0700920 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 return ret;
922}
923
924/* called under write_lock */
925static void get_counters(struct ebt_counter *oldcounters,
926 struct ebt_counter *counters, unsigned int nentries)
927{
928 int i, cpu;
929 struct ebt_counter *counter_base;
930
931 /* counters of cpu 0 */
932 memcpy(counters, oldcounters,
David S. Millerc8923c62005-10-13 14:41:23 -0700933 sizeof(struct ebt_counter) * nentries);
934
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 /* add other counters to those of cpu 0 */
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700936 for_each_possible_cpu(cpu) {
David S. Millerc8923c62005-10-13 14:41:23 -0700937 if (cpu == 0)
938 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
940 for (i = 0; i < nentries; i++) {
941 counters[i].pcnt += counter_base[i].pcnt;
942 counters[i].bcnt += counter_base[i].bcnt;
943 }
944 }
945}
946
947/* replace the table */
Alexey Dobriyan511061e2008-11-04 14:22:55 +0100948static int do_replace(struct net *net, void __user *user, unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949{
950 int ret, i, countersize;
951 struct ebt_table_info *newinfo;
952 struct ebt_replace tmp;
953 struct ebt_table *t;
954 struct ebt_counter *counterstmp = NULL;
955 /* used to be able to unlock earlier */
956 struct ebt_table_info *table;
957
958 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
959 return -EFAULT;
960
961 if (len != sizeof(tmp) + tmp.entries_size) {
962 BUGPRINT("Wrong len argument\n");
963 return -EINVAL;
964 }
965
966 if (tmp.entries_size == 0) {
967 BUGPRINT("Entries_size never zero\n");
968 return -EINVAL;
969 }
Kirill Korotaevee4bb812006-02-04 02:16:56 -0800970 /* overflow check */
971 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
972 SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
973 return -ENOMEM;
974 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
975 return -ENOMEM;
976
Christoph Lameter53b8a312007-02-20 13:57:51 -0800977 countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -0700978 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 if (!newinfo)
980 return -ENOMEM;
981
982 if (countersize)
983 memset(newinfo->counters, 0, countersize);
984
Kris Katterjohn8b3a7002006-01-11 15:56:43 -0800985 newinfo->entries = vmalloc(tmp.entries_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 if (!newinfo->entries) {
987 ret = -ENOMEM;
988 goto free_newinfo;
989 }
990 if (copy_from_user(
991 newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
992 BUGPRINT("Couldn't copy entries from userspace\n");
993 ret = -EFAULT;
994 goto free_entries;
995 }
996
997 /* the user wants counters back
998 the check on the size is done later, when we have the lock */
999 if (tmp.num_counters) {
Jayachandran C18bc89a2006-04-20 00:14:49 -07001000 counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 if (!counterstmp) {
1002 ret = -ENOMEM;
1003 goto free_entries;
1004 }
1005 }
1006 else
1007 counterstmp = NULL;
1008
1009 /* this can get initialized by translate_table() */
1010 newinfo->chainstack = NULL;
Al Viro1bc23262006-11-30 19:28:08 -08001011 ret = ebt_verify_pointers(&tmp, newinfo);
1012 if (ret != 0)
1013 goto free_counterstmp;
1014
1015 ret = translate_table(tmp.name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016
1017 if (ret != 0)
1018 goto free_counterstmp;
1019
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001020 t = find_table_lock(net, tmp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 if (!t) {
1022 ret = -ENOENT;
1023 goto free_iterate;
1024 }
1025
1026 /* the table doesn't like it */
1027 if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
1028 goto free_unlock;
1029
1030 if (tmp.num_counters && tmp.num_counters != t->private->nentries) {
1031 BUGPRINT("Wrong nr. of counters requested\n");
1032 ret = -EINVAL;
1033 goto free_unlock;
1034 }
1035
1036 /* we have the mutex lock, so no danger in reading this pointer */
1037 table = t->private;
1038 /* make sure the table can only be rmmod'ed if it contains no rules */
1039 if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) {
1040 ret = -ENOENT;
1041 goto free_unlock;
1042 } else if (table->nentries && !newinfo->nentries)
1043 module_put(t->me);
1044 /* we need an atomic snapshot of the counters */
1045 write_lock_bh(&t->lock);
1046 if (tmp.num_counters)
1047 get_counters(t->private->counters, counterstmp,
1048 t->private->nentries);
1049
1050 t->private = newinfo;
1051 write_unlock_bh(&t->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001052 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 /* so, a user can change the chains while having messed up her counter
1054 allocation. Only reason why this is done is because this way the lock
1055 is held only once, while this doesn't bring the kernel into a
1056 dangerous state. */
1057 if (tmp.num_counters &&
1058 copy_to_user(tmp.counters, counterstmp,
1059 tmp.num_counters * sizeof(struct ebt_counter))) {
1060 BUGPRINT("Couldn't copy counters to userspace\n");
1061 ret = -EFAULT;
1062 }
1063 else
1064 ret = 0;
1065
1066 /* decrease module count and free resources */
1067 EBT_ENTRY_ITERATE(table->entries, table->entries_size,
1068 ebt_cleanup_entry, NULL);
1069
1070 vfree(table->entries);
1071 if (table->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001072 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 vfree(table->chainstack[i]);
1074 vfree(table->chainstack);
1075 }
1076 vfree(table);
1077
James Lamanna68d31872005-06-22 22:12:57 -07001078 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 return ret;
1080
1081free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001082 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083free_iterate:
1084 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
1085 ebt_cleanup_entry, NULL);
1086free_counterstmp:
James Lamanna68d31872005-06-22 22:12:57 -07001087 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 /* can be initialized in translate_table() */
1089 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001090 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 vfree(newinfo->chainstack[i]);
1092 vfree(newinfo->chainstack);
1093 }
1094free_entries:
James Lamanna68d31872005-06-22 22:12:57 -07001095 vfree(newinfo->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096free_newinfo:
James Lamanna68d31872005-06-22 22:12:57 -07001097 vfree(newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 return ret;
1099}
1100
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001101struct ebt_table *ebt_register_table(struct net *net, struct ebt_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102{
1103 struct ebt_table_info *newinfo;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001104 struct ebt_table *t;
Al Viro1e419cd2006-11-30 19:28:48 -08001105 struct ebt_replace_kernel *repl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 int ret, i, countersize;
Al Virodf07a812006-11-30 19:28:25 -08001107 void *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108
Al Virodf07a812006-11-30 19:28:25 -08001109 if (!table || !(repl = table->table) || !repl->entries ||
1110 repl->entries_size == 0 ||
1111 repl->counters || table->private) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 BUGPRINT("Bad table data for ebt_register_table!!!\n");
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001113 return ERR_PTR(-EINVAL);
1114 }
1115
1116 /* Don't add one table to multiple lists. */
1117 table = kmemdup(table, sizeof(struct ebt_table), GFP_KERNEL);
1118 if (!table) {
1119 ret = -ENOMEM;
1120 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 }
1122
Christoph Lameter53b8a312007-02-20 13:57:51 -08001123 countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -07001124 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 ret = -ENOMEM;
1126 if (!newinfo)
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001127 goto free_table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128
Al Virodf07a812006-11-30 19:28:25 -08001129 p = vmalloc(repl->entries_size);
1130 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 goto free_newinfo;
1132
Al Virodf07a812006-11-30 19:28:25 -08001133 memcpy(p, repl->entries, repl->entries_size);
1134 newinfo->entries = p;
1135
1136 newinfo->entries_size = repl->entries_size;
1137 newinfo->nentries = repl->nentries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138
1139 if (countersize)
1140 memset(newinfo->counters, 0, countersize);
1141
1142 /* fill in newinfo and parse the entries */
1143 newinfo->chainstack = NULL;
Al Virodf07a812006-11-30 19:28:25 -08001144 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1145 if ((repl->valid_hooks & (1 << i)) == 0)
1146 newinfo->hook_entry[i] = NULL;
1147 else
1148 newinfo->hook_entry[i] = p +
1149 ((char *)repl->hook_entry[i] - repl->entries);
1150 }
1151 ret = translate_table(repl->name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 if (ret != 0) {
1153 BUGPRINT("Translate_table failed\n");
1154 goto free_chainstack;
1155 }
1156
1157 if (table->check && table->check(newinfo, table->valid_hooks)) {
1158 BUGPRINT("The table doesn't like its own initial data, lol\n");
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001159 return ERR_PTR(-EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 }
1161
1162 table->private = newinfo;
1163 rwlock_init(&table->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001164 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 if (ret != 0)
1166 goto free_chainstack;
1167
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001168 list_for_each_entry(t, &net->xt.tables[NFPROTO_BRIDGE], list) {
Patrick McHardydf0933d2006-09-20 11:57:53 -07001169 if (strcmp(t->name, table->name) == 0) {
1170 ret = -EEXIST;
1171 BUGPRINT("Table name already exists\n");
1172 goto free_unlock;
1173 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 }
1175
1176 /* Hold a reference count if the chains aren't empty */
1177 if (newinfo->nentries && !try_module_get(table->me)) {
1178 ret = -ENOENT;
1179 goto free_unlock;
1180 }
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001181 list_add(&table->list, &net->xt.tables[NFPROTO_BRIDGE]);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001182 mutex_unlock(&ebt_mutex);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001183 return table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001185 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186free_chainstack:
1187 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001188 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 vfree(newinfo->chainstack[i]);
1190 vfree(newinfo->chainstack);
1191 }
1192 vfree(newinfo->entries);
1193free_newinfo:
1194 vfree(newinfo);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001195free_table:
1196 kfree(table);
1197out:
1198 return ERR_PTR(ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199}
1200
1201void ebt_unregister_table(struct ebt_table *table)
1202{
1203 int i;
1204
1205 if (!table) {
1206 BUGPRINT("Request to unregister NULL table!!!\n");
1207 return;
1208 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001209 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001210 list_del(&table->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001211 mutex_unlock(&ebt_mutex);
James Lamanna68d31872005-06-22 22:12:57 -07001212 vfree(table->private->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 if (table->private->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001214 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 vfree(table->private->chainstack[i]);
1216 vfree(table->private->chainstack);
1217 }
1218 vfree(table->private);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001219 kfree(table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220}
1221
1222/* userspace just supplied us with counters */
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001223static int update_counters(struct net *net, void __user *user, unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224{
1225 int i, ret;
1226 struct ebt_counter *tmp;
1227 struct ebt_replace hlp;
1228 struct ebt_table *t;
1229
1230 if (copy_from_user(&hlp, user, sizeof(hlp)))
1231 return -EFAULT;
1232
1233 if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
1234 return -EINVAL;
1235 if (hlp.num_counters == 0)
1236 return -EINVAL;
1237
Jayachandran C18bc89a2006-04-20 00:14:49 -07001238 if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 MEMPRINT("Update_counters && nomemory\n");
1240 return -ENOMEM;
1241 }
1242
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001243 t = find_table_lock(net, hlp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 if (!t)
1245 goto free_tmp;
1246
1247 if (hlp.num_counters != t->private->nentries) {
1248 BUGPRINT("Wrong nr of counters\n");
1249 ret = -EINVAL;
1250 goto unlock_mutex;
1251 }
1252
1253 if ( copy_from_user(tmp, hlp.counters,
1254 hlp.num_counters * sizeof(struct ebt_counter)) ) {
1255 BUGPRINT("Updata_counters && !cfu\n");
1256 ret = -EFAULT;
1257 goto unlock_mutex;
1258 }
1259
1260 /* we want an atomic add of the counters */
1261 write_lock_bh(&t->lock);
1262
1263 /* we add to the counters of the first cpu */
1264 for (i = 0; i < hlp.num_counters; i++) {
1265 t->private->counters[i].pcnt += tmp[i].pcnt;
1266 t->private->counters[i].bcnt += tmp[i].bcnt;
1267 }
1268
1269 write_unlock_bh(&t->lock);
1270 ret = 0;
1271unlock_mutex:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001272 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273free_tmp:
1274 vfree(tmp);
1275 return ret;
1276}
1277
1278static inline int ebt_make_matchname(struct ebt_entry_match *m,
Al Viro1e419cd2006-11-30 19:28:48 -08001279 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280{
Al Viro1e419cd2006-11-30 19:28:48 -08001281 char __user *hlp = ubase + ((char *)m - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
1283 return -EFAULT;
1284 return 0;
1285}
1286
1287static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
Al Viro1e419cd2006-11-30 19:28:48 -08001288 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289{
Al Viro1e419cd2006-11-30 19:28:48 -08001290 char __user *hlp = ubase + ((char *)w - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
1292 return -EFAULT;
1293 return 0;
1294}
1295
Al Viro1e419cd2006-11-30 19:28:48 -08001296static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297{
1298 int ret;
Al Viro1e419cd2006-11-30 19:28:48 -08001299 char __user *hlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 struct ebt_entry_target *t;
1301
Al Viro40642f92006-11-30 19:24:12 -08001302 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 return 0;
1304
Al Viro1e419cd2006-11-30 19:28:48 -08001305 hlp = ubase + (((char *)e + e->target_offset) - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +09001307
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
1309 if (ret != 0)
1310 return ret;
1311 ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
1312 if (ret != 0)
1313 return ret;
1314 if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
1315 return -EFAULT;
1316 return 0;
1317}
1318
Ingo Molnar57b47a52006-03-20 22:35:41 -08001319/* called with ebt_mutex locked */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320static int copy_everything_to_user(struct ebt_table *t, void __user *user,
1321 int *len, int cmd)
1322{
1323 struct ebt_replace tmp;
1324 struct ebt_counter *counterstmp, *oldcounters;
1325 unsigned int entries_size, nentries;
1326 char *entries;
1327
1328 if (cmd == EBT_SO_GET_ENTRIES) {
1329 entries_size = t->private->entries_size;
1330 nentries = t->private->nentries;
1331 entries = t->private->entries;
1332 oldcounters = t->private->counters;
1333 } else {
1334 entries_size = t->table->entries_size;
1335 nentries = t->table->nentries;
1336 entries = t->table->entries;
1337 oldcounters = t->table->counters;
1338 }
1339
1340 if (copy_from_user(&tmp, user, sizeof(tmp))) {
1341 BUGPRINT("Cfu didn't work\n");
1342 return -EFAULT;
1343 }
1344
1345 if (*len != sizeof(struct ebt_replace) + entries_size +
1346 (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
1347 BUGPRINT("Wrong size\n");
1348 return -EINVAL;
1349 }
1350
1351 if (tmp.nentries != nentries) {
1352 BUGPRINT("Nentries wrong\n");
1353 return -EINVAL;
1354 }
1355
1356 if (tmp.entries_size != entries_size) {
1357 BUGPRINT("Wrong size\n");
1358 return -EINVAL;
1359 }
1360
1361 /* userspace might not need the counters */
1362 if (tmp.num_counters) {
1363 if (tmp.num_counters != nentries) {
1364 BUGPRINT("Num_counters wrong\n");
1365 return -EINVAL;
1366 }
Jayachandran C18bc89a2006-04-20 00:14:49 -07001367 counterstmp = vmalloc(nentries * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 if (!counterstmp) {
1369 MEMPRINT("Couldn't copy counters, out of memory\n");
1370 return -ENOMEM;
1371 }
1372 write_lock_bh(&t->lock);
1373 get_counters(oldcounters, counterstmp, nentries);
1374 write_unlock_bh(&t->lock);
1375
1376 if (copy_to_user(tmp.counters, counterstmp,
1377 nentries * sizeof(struct ebt_counter))) {
1378 BUGPRINT("Couldn't copy counters to userspace\n");
1379 vfree(counterstmp);
1380 return -EFAULT;
1381 }
1382 vfree(counterstmp);
1383 }
1384
1385 if (copy_to_user(tmp.entries, entries, entries_size)) {
1386 BUGPRINT("Couldn't copy entries to userspace\n");
1387 return -EFAULT;
1388 }
1389 /* set the match/watcher/target names right */
1390 return EBT_ENTRY_ITERATE(entries, entries_size,
1391 ebt_make_names, entries, tmp.entries);
1392}
1393
1394static int do_ebt_set_ctl(struct sock *sk,
1395 int cmd, void __user *user, unsigned int len)
1396{
1397 int ret;
1398
1399 switch(cmd) {
1400 case EBT_SO_SET_ENTRIES:
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001401 ret = do_replace(sock_net(sk), user, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 break;
1403 case EBT_SO_SET_COUNTERS:
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001404 ret = update_counters(sock_net(sk), user, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 break;
1406 default:
1407 ret = -EINVAL;
1408 }
1409 return ret;
1410}
1411
1412static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1413{
1414 int ret;
1415 struct ebt_replace tmp;
1416 struct ebt_table *t;
1417
1418 if (copy_from_user(&tmp, user, sizeof(tmp)))
1419 return -EFAULT;
1420
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001421 t = find_table_lock(sock_net(sk), tmp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 if (!t)
1423 return ret;
1424
1425 switch(cmd) {
1426 case EBT_SO_GET_INFO:
1427 case EBT_SO_GET_INIT_INFO:
1428 if (*len != sizeof(struct ebt_replace)){
1429 ret = -EINVAL;
Ingo Molnar57b47a52006-03-20 22:35:41 -08001430 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 break;
1432 }
1433 if (cmd == EBT_SO_GET_INFO) {
1434 tmp.nentries = t->private->nentries;
1435 tmp.entries_size = t->private->entries_size;
1436 tmp.valid_hooks = t->valid_hooks;
1437 } else {
1438 tmp.nentries = t->table->nentries;
1439 tmp.entries_size = t->table->entries_size;
1440 tmp.valid_hooks = t->table->valid_hooks;
1441 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001442 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 if (copy_to_user(user, &tmp, *len) != 0){
1444 BUGPRINT("c2u Didn't work\n");
1445 ret = -EFAULT;
1446 break;
1447 }
1448 ret = 0;
1449 break;
1450
1451 case EBT_SO_GET_ENTRIES:
1452 case EBT_SO_GET_INIT_ENTRIES:
1453 ret = copy_everything_to_user(t, user, len, cmd);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001454 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 break;
1456
1457 default:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001458 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 ret = -EINVAL;
1460 }
1461
1462 return ret;
1463}
1464
1465static struct nf_sockopt_ops ebt_sockopts =
Andrew Morton74ca4e5a2006-03-20 22:55:02 -08001466{
1467 .pf = PF_INET,
1468 .set_optmin = EBT_BASE_CTL,
1469 .set_optmax = EBT_SO_SET_MAX + 1,
1470 .set = do_ebt_set_ctl,
1471 .get_optmin = EBT_BASE_CTL,
1472 .get_optmax = EBT_SO_GET_MAX + 1,
1473 .get = do_ebt_get_ctl,
Neil Horman16fcec32007-09-11 11:28:26 +02001474 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475};
1476
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001477static int __init ebtables_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478{
1479 int ret;
1480
Jan Engelhardt043ef462008-10-08 11:35:15 +02001481 ret = xt_register_target(&ebt_standard_target);
1482 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 return ret;
Jan Engelhardt043ef462008-10-08 11:35:15 +02001484 ret = nf_register_sockopt(&ebt_sockopts);
1485 if (ret < 0) {
1486 xt_unregister_target(&ebt_standard_target);
1487 return ret;
1488 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489
Patrick McHardya887c1c2007-07-14 20:46:15 -07001490 printk(KERN_INFO "Ebtables v2.0 registered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 return 0;
1492}
1493
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001494static void __exit ebtables_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495{
1496 nf_unregister_sockopt(&ebt_sockopts);
Jan Engelhardt043ef462008-10-08 11:35:15 +02001497 xt_unregister_target(&ebt_standard_target);
Patrick McHardya887c1c2007-07-14 20:46:15 -07001498 printk(KERN_INFO "Ebtables v2.0 unregistered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499}
1500
1501EXPORT_SYMBOL(ebt_register_table);
1502EXPORT_SYMBOL(ebt_unregister_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503EXPORT_SYMBOL(ebt_do_table);
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001504module_init(ebtables_init);
1505module_exit(ebtables_fini);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506MODULE_LICENSE("GPL");