blob: fa108c46e8510d1cf447cd4501576d2fd9cf4934 [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);
Alexey Dobriyandbcdf852008-11-04 14:28:04 +01001212 EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size,
1213 ebt_cleanup_entry, NULL);
1214 if (table->private->nentries)
1215 module_put(table->me);
James Lamanna68d31872005-06-22 22:12:57 -07001216 vfree(table->private->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 if (table->private->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001218 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 vfree(table->private->chainstack[i]);
1220 vfree(table->private->chainstack);
1221 }
1222 vfree(table->private);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001223 kfree(table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224}
1225
1226/* userspace just supplied us with counters */
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001227static int update_counters(struct net *net, void __user *user, unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228{
1229 int i, ret;
1230 struct ebt_counter *tmp;
1231 struct ebt_replace hlp;
1232 struct ebt_table *t;
1233
1234 if (copy_from_user(&hlp, user, sizeof(hlp)))
1235 return -EFAULT;
1236
1237 if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
1238 return -EINVAL;
1239 if (hlp.num_counters == 0)
1240 return -EINVAL;
1241
Jayachandran C18bc89a2006-04-20 00:14:49 -07001242 if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 MEMPRINT("Update_counters && nomemory\n");
1244 return -ENOMEM;
1245 }
1246
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001247 t = find_table_lock(net, hlp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 if (!t)
1249 goto free_tmp;
1250
1251 if (hlp.num_counters != t->private->nentries) {
1252 BUGPRINT("Wrong nr of counters\n");
1253 ret = -EINVAL;
1254 goto unlock_mutex;
1255 }
1256
1257 if ( copy_from_user(tmp, hlp.counters,
1258 hlp.num_counters * sizeof(struct ebt_counter)) ) {
1259 BUGPRINT("Updata_counters && !cfu\n");
1260 ret = -EFAULT;
1261 goto unlock_mutex;
1262 }
1263
1264 /* we want an atomic add of the counters */
1265 write_lock_bh(&t->lock);
1266
1267 /* we add to the counters of the first cpu */
1268 for (i = 0; i < hlp.num_counters; i++) {
1269 t->private->counters[i].pcnt += tmp[i].pcnt;
1270 t->private->counters[i].bcnt += tmp[i].bcnt;
1271 }
1272
1273 write_unlock_bh(&t->lock);
1274 ret = 0;
1275unlock_mutex:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001276 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277free_tmp:
1278 vfree(tmp);
1279 return ret;
1280}
1281
1282static inline int ebt_make_matchname(struct ebt_entry_match *m,
Al Viro1e419cd2006-11-30 19:28:48 -08001283 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284{
Al Viro1e419cd2006-11-30 19:28:48 -08001285 char __user *hlp = ubase + ((char *)m - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
1287 return -EFAULT;
1288 return 0;
1289}
1290
1291static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
Al Viro1e419cd2006-11-30 19:28:48 -08001292 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293{
Al Viro1e419cd2006-11-30 19:28:48 -08001294 char __user *hlp = ubase + ((char *)w - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
1296 return -EFAULT;
1297 return 0;
1298}
1299
Al Viro1e419cd2006-11-30 19:28:48 -08001300static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301{
1302 int ret;
Al Viro1e419cd2006-11-30 19:28:48 -08001303 char __user *hlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 struct ebt_entry_target *t;
1305
Al Viro40642f92006-11-30 19:24:12 -08001306 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 return 0;
1308
Al Viro1e419cd2006-11-30 19:28:48 -08001309 hlp = ubase + (((char *)e + e->target_offset) - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +09001311
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
1313 if (ret != 0)
1314 return ret;
1315 ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
1316 if (ret != 0)
1317 return ret;
1318 if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
1319 return -EFAULT;
1320 return 0;
1321}
1322
Ingo Molnar57b47a52006-03-20 22:35:41 -08001323/* called with ebt_mutex locked */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324static int copy_everything_to_user(struct ebt_table *t, void __user *user,
1325 int *len, int cmd)
1326{
1327 struct ebt_replace tmp;
1328 struct ebt_counter *counterstmp, *oldcounters;
1329 unsigned int entries_size, nentries;
1330 char *entries;
1331
1332 if (cmd == EBT_SO_GET_ENTRIES) {
1333 entries_size = t->private->entries_size;
1334 nentries = t->private->nentries;
1335 entries = t->private->entries;
1336 oldcounters = t->private->counters;
1337 } else {
1338 entries_size = t->table->entries_size;
1339 nentries = t->table->nentries;
1340 entries = t->table->entries;
1341 oldcounters = t->table->counters;
1342 }
1343
1344 if (copy_from_user(&tmp, user, sizeof(tmp))) {
1345 BUGPRINT("Cfu didn't work\n");
1346 return -EFAULT;
1347 }
1348
1349 if (*len != sizeof(struct ebt_replace) + entries_size +
1350 (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
1351 BUGPRINT("Wrong size\n");
1352 return -EINVAL;
1353 }
1354
1355 if (tmp.nentries != nentries) {
1356 BUGPRINT("Nentries wrong\n");
1357 return -EINVAL;
1358 }
1359
1360 if (tmp.entries_size != entries_size) {
1361 BUGPRINT("Wrong size\n");
1362 return -EINVAL;
1363 }
1364
1365 /* userspace might not need the counters */
1366 if (tmp.num_counters) {
1367 if (tmp.num_counters != nentries) {
1368 BUGPRINT("Num_counters wrong\n");
1369 return -EINVAL;
1370 }
Jayachandran C18bc89a2006-04-20 00:14:49 -07001371 counterstmp = vmalloc(nentries * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 if (!counterstmp) {
1373 MEMPRINT("Couldn't copy counters, out of memory\n");
1374 return -ENOMEM;
1375 }
1376 write_lock_bh(&t->lock);
1377 get_counters(oldcounters, counterstmp, nentries);
1378 write_unlock_bh(&t->lock);
1379
1380 if (copy_to_user(tmp.counters, counterstmp,
1381 nentries * sizeof(struct ebt_counter))) {
1382 BUGPRINT("Couldn't copy counters to userspace\n");
1383 vfree(counterstmp);
1384 return -EFAULT;
1385 }
1386 vfree(counterstmp);
1387 }
1388
1389 if (copy_to_user(tmp.entries, entries, entries_size)) {
1390 BUGPRINT("Couldn't copy entries to userspace\n");
1391 return -EFAULT;
1392 }
1393 /* set the match/watcher/target names right */
1394 return EBT_ENTRY_ITERATE(entries, entries_size,
1395 ebt_make_names, entries, tmp.entries);
1396}
1397
1398static int do_ebt_set_ctl(struct sock *sk,
1399 int cmd, void __user *user, unsigned int len)
1400{
1401 int ret;
1402
1403 switch(cmd) {
1404 case EBT_SO_SET_ENTRIES:
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001405 ret = do_replace(sock_net(sk), user, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 break;
1407 case EBT_SO_SET_COUNTERS:
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001408 ret = update_counters(sock_net(sk), user, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 break;
1410 default:
1411 ret = -EINVAL;
1412 }
1413 return ret;
1414}
1415
1416static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1417{
1418 int ret;
1419 struct ebt_replace tmp;
1420 struct ebt_table *t;
1421
1422 if (copy_from_user(&tmp, user, sizeof(tmp)))
1423 return -EFAULT;
1424
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001425 t = find_table_lock(sock_net(sk), tmp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 if (!t)
1427 return ret;
1428
1429 switch(cmd) {
1430 case EBT_SO_GET_INFO:
1431 case EBT_SO_GET_INIT_INFO:
1432 if (*len != sizeof(struct ebt_replace)){
1433 ret = -EINVAL;
Ingo Molnar57b47a52006-03-20 22:35:41 -08001434 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 break;
1436 }
1437 if (cmd == EBT_SO_GET_INFO) {
1438 tmp.nentries = t->private->nentries;
1439 tmp.entries_size = t->private->entries_size;
1440 tmp.valid_hooks = t->valid_hooks;
1441 } else {
1442 tmp.nentries = t->table->nentries;
1443 tmp.entries_size = t->table->entries_size;
1444 tmp.valid_hooks = t->table->valid_hooks;
1445 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001446 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 if (copy_to_user(user, &tmp, *len) != 0){
1448 BUGPRINT("c2u Didn't work\n");
1449 ret = -EFAULT;
1450 break;
1451 }
1452 ret = 0;
1453 break;
1454
1455 case EBT_SO_GET_ENTRIES:
1456 case EBT_SO_GET_INIT_ENTRIES:
1457 ret = copy_everything_to_user(t, user, len, cmd);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001458 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 break;
1460
1461 default:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001462 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 ret = -EINVAL;
1464 }
1465
1466 return ret;
1467}
1468
1469static struct nf_sockopt_ops ebt_sockopts =
Andrew Morton74ca4e5a2006-03-20 22:55:02 -08001470{
1471 .pf = PF_INET,
1472 .set_optmin = EBT_BASE_CTL,
1473 .set_optmax = EBT_SO_SET_MAX + 1,
1474 .set = do_ebt_set_ctl,
1475 .get_optmin = EBT_BASE_CTL,
1476 .get_optmax = EBT_SO_GET_MAX + 1,
1477 .get = do_ebt_get_ctl,
Neil Horman16fcec32007-09-11 11:28:26 +02001478 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479};
1480
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001481static int __init ebtables_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482{
1483 int ret;
1484
Jan Engelhardt043ef462008-10-08 11:35:15 +02001485 ret = xt_register_target(&ebt_standard_target);
1486 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 return ret;
Jan Engelhardt043ef462008-10-08 11:35:15 +02001488 ret = nf_register_sockopt(&ebt_sockopts);
1489 if (ret < 0) {
1490 xt_unregister_target(&ebt_standard_target);
1491 return ret;
1492 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493
Patrick McHardya887c1c2007-07-14 20:46:15 -07001494 printk(KERN_INFO "Ebtables v2.0 registered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 return 0;
1496}
1497
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001498static void __exit ebtables_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499{
1500 nf_unregister_sockopt(&ebt_sockopts);
Jan Engelhardt043ef462008-10-08 11:35:15 +02001501 xt_unregister_target(&ebt_standard_target);
Patrick McHardya887c1c2007-07-14 20:46:15 -07001502 printk(KERN_INFO "Ebtables v2.0 unregistered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503}
1504
1505EXPORT_SYMBOL(ebt_register_table);
1506EXPORT_SYMBOL(ebt_unregister_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507EXPORT_SYMBOL(ebt_do_table);
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001508module_init(ebtables_init);
1509module_exit(ebtables_fini);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510MODULE_LICENSE("GPL");