blob: bc4b3f4f37c4a9197dd0f124e99cb282a77b7b38 [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 -070058static LIST_HEAD(ebt_tables);
59static LIST_HEAD(ebt_targets);
60static LIST_HEAD(ebt_matches);
61static LIST_HEAD(ebt_watchers);
62
Jan Engelhardt18219d32008-10-08 11:35:13 +020063static struct ebt_target ebt_standard_target = {
Jan Engelhardt001a18d2008-10-08 11:35:14 +020064 .name = "standard",
65 .revision = 0,
66 .family = NFPROTO_BRIDGE,
Jan Engelhardt18219d32008-10-08 11:35:13 +020067};
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69static inline int ebt_do_watcher (struct ebt_entry_watcher *w,
70 const struct sk_buff *skb, unsigned int hooknr, const struct net_device *in,
71 const struct net_device *out)
72{
73 w->u.watcher->watcher(skb, hooknr, in, out, w->data,
74 w->watcher_size);
75 /* watchers don't give a verdict */
76 return 0;
77}
78
79static inline int ebt_do_match (struct ebt_entry_match *m,
80 const struct sk_buff *skb, const struct net_device *in,
81 const struct net_device *out)
82{
83 return m->u.match->match(skb, in, out, m->data,
84 m->match_size);
85}
86
87static inline int ebt_dev_check(char *entry, const struct net_device *device)
88{
89 int i = 0;
Meelis Roos6f5b7ef2006-11-01 18:07:27 -080090 const char *devname = device->name;
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
92 if (*entry == '\0')
93 return 0;
94 if (!device)
95 return 1;
96 /* 1 is the wildcard token */
97 while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i])
98 i++;
99 return (devname[i] != entry[i] && entry[i] != 1);
100}
101
102#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
103/* process standard matches */
104static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h,
105 const struct net_device *in, const struct net_device *out)
106{
107 int verdict, i;
108
109 if (e->bitmask & EBT_802_3) {
110 if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO))
111 return 1;
112 } else if (!(e->bitmask & EBT_NOPROTO) &&
113 FWINV2(e->ethproto != h->h_proto, EBT_IPROTO))
114 return 1;
115
116 if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
117 return 1;
118 if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
119 return 1;
120 if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check(
121 e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN))
122 return 1;
123 if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check(
124 e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT))
125 return 1;
126
127 if (e->bitmask & EBT_SOURCEMAC) {
128 verdict = 0;
129 for (i = 0; i < 6; i++)
130 verdict |= (h->h_source[i] ^ e->sourcemac[i]) &
131 e->sourcemsk[i];
132 if (FWINV2(verdict != 0, EBT_ISOURCE) )
133 return 1;
134 }
135 if (e->bitmask & EBT_DESTMAC) {
136 verdict = 0;
137 for (i = 0; i < 6; i++)
138 verdict |= (h->h_dest[i] ^ e->destmac[i]) &
139 e->destmsk[i];
140 if (FWINV2(verdict != 0, EBT_IDEST) )
141 return 1;
142 }
143 return 0;
144}
145
146/* Do some firewalling */
Herbert Xu3db05fe2007-10-15 00:53:15 -0700147unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 const struct net_device *in, const struct net_device *out,
149 struct ebt_table *table)
150{
151 int i, nentries;
152 struct ebt_entry *point;
153 struct ebt_counter *counter_base, *cb_base;
154 struct ebt_entry_target *t;
155 int verdict, sp = 0;
156 struct ebt_chainstack *cs;
157 struct ebt_entries *chaininfo;
158 char *base;
159 struct ebt_table_info *private;
160
161 read_lock_bh(&table->lock);
162 private = table->private;
163 cb_base = COUNTER_BASE(private->counters, private->nentries,
164 smp_processor_id());
165 if (private->chainstack)
166 cs = private->chainstack[smp_processor_id()];
167 else
168 cs = NULL;
169 chaininfo = private->hook_entry[hook];
170 nentries = private->hook_entry[hook]->nentries;
171 point = (struct ebt_entry *)(private->hook_entry[hook]->data);
172 counter_base = cb_base + private->hook_entry[hook]->counter_offset;
173 /* base for chain jumps */
174 base = private->entries;
175 i = 0;
176 while (i < nentries) {
Herbert Xu3db05fe2007-10-15 00:53:15 -0700177 if (ebt_basic_match(point, eth_hdr(skb), in, out))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 goto letscontinue;
179
Herbert Xu3db05fe2007-10-15 00:53:15 -0700180 if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, in, out) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 goto letscontinue;
182
183 /* increase counter */
184 (*(counter_base + i)).pcnt++;
Herbert Xu3db05fe2007-10-15 00:53:15 -0700185 (*(counter_base + i)).bcnt += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
187 /* these should only watch: not modify, nor tell us
188 what to do with the packet */
Herbert Xu3db05fe2007-10-15 00:53:15 -0700189 EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, hook, in,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 out);
191
192 t = (struct ebt_entry_target *)
193 (((char *)point) + point->target_offset);
194 /* standard target */
195 if (!t->u.target->target)
196 verdict = ((struct ebt_standard_target *)t)->verdict;
197 else
Herbert Xu3db05fe2007-10-15 00:53:15 -0700198 verdict = t->u.target->target(skb, hook,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 in, out, t->data, t->target_size);
200 if (verdict == EBT_ACCEPT) {
201 read_unlock_bh(&table->lock);
202 return NF_ACCEPT;
203 }
204 if (verdict == EBT_DROP) {
205 read_unlock_bh(&table->lock);
206 return NF_DROP;
207 }
208 if (verdict == EBT_RETURN) {
209letsreturn:
210#ifdef CONFIG_NETFILTER_DEBUG
211 if (sp == 0) {
212 BUGPRINT("RETURN on base chain");
213 /* act like this is EBT_CONTINUE */
214 goto letscontinue;
215 }
216#endif
217 sp--;
218 /* put all the local variables right */
219 i = cs[sp].n;
220 chaininfo = cs[sp].chaininfo;
221 nentries = chaininfo->nentries;
222 point = cs[sp].e;
223 counter_base = cb_base +
224 chaininfo->counter_offset;
225 continue;
226 }
227 if (verdict == EBT_CONTINUE)
228 goto letscontinue;
229#ifdef CONFIG_NETFILTER_DEBUG
230 if (verdict < 0) {
231 BUGPRINT("bogus standard verdict\n");
232 read_unlock_bh(&table->lock);
233 return NF_DROP;
234 }
235#endif
236 /* jump to a udc */
237 cs[sp].n = i + 1;
238 cs[sp].chaininfo = chaininfo;
239 cs[sp].e = (struct ebt_entry *)
240 (((char *)point) + point->next_offset);
241 i = 0;
242 chaininfo = (struct ebt_entries *) (base + verdict);
243#ifdef CONFIG_NETFILTER_DEBUG
244 if (chaininfo->distinguisher) {
245 BUGPRINT("jump to non-chain\n");
246 read_unlock_bh(&table->lock);
247 return NF_DROP;
248 }
249#endif
250 nentries = chaininfo->nentries;
251 point = (struct ebt_entry *)chaininfo->data;
252 counter_base = cb_base + chaininfo->counter_offset;
253 sp++;
254 continue;
255letscontinue:
256 point = (struct ebt_entry *)
257 (((char *)point) + point->next_offset);
258 i++;
259 }
260
261 /* I actually like this :) */
262 if (chaininfo->policy == EBT_RETURN)
263 goto letsreturn;
264 if (chaininfo->policy == EBT_ACCEPT) {
265 read_unlock_bh(&table->lock);
266 return NF_ACCEPT;
267 }
268 read_unlock_bh(&table->lock);
269 return NF_DROP;
270}
271
272/* If it succeeds, returns element and locks mutex */
273static inline void *
274find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800275 struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276{
Patrick McHardydf0933d2006-09-20 11:57:53 -0700277 struct {
278 struct list_head list;
279 char name[EBT_FUNCTION_MAXNAMELEN];
280 } *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
Ingo Molnar57b47a52006-03-20 22:35:41 -0800282 *error = mutex_lock_interruptible(mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 if (*error != 0)
284 return NULL;
285
Patrick McHardydf0933d2006-09-20 11:57:53 -0700286 list_for_each_entry(e, head, list) {
287 if (strcmp(e->name, name) == 0)
288 return e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 }
Patrick McHardydf0933d2006-09-20 11:57:53 -0700290 *error = -ENOENT;
291 mutex_unlock(mutex);
292 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293}
294
295#ifndef CONFIG_KMOD
296#define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
297#else
298static void *
299find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800300 int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301{
302 void *ret;
303
304 ret = find_inlist_lock_noload(head, name, error, mutex);
305 if (!ret) {
306 request_module("%s%s", prefix, name);
307 ret = find_inlist_lock_noload(head, name, error, mutex);
308 }
309 return ret;
310}
311#endif
312
313static inline struct ebt_table *
Ingo Molnar57b47a52006-03-20 22:35:41 -0800314find_table_lock(const char *name, int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315{
316 return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex);
317}
318
319static inline struct ebt_match *
Ingo Molnar57b47a52006-03-20 22:35:41 -0800320find_match_lock(const char *name, int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321{
322 return find_inlist_lock(&ebt_matches, name, "ebt_", error, mutex);
323}
324
325static inline struct ebt_watcher *
Ingo Molnar57b47a52006-03-20 22:35:41 -0800326find_watcher_lock(const char *name, int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327{
328 return find_inlist_lock(&ebt_watchers, name, "ebt_", error, mutex);
329}
330
331static inline struct ebt_target *
Ingo Molnar57b47a52006-03-20 22:35:41 -0800332find_target_lock(const char *name, int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333{
334 return find_inlist_lock(&ebt_targets, name, "ebt_", error, mutex);
335}
336
337static inline int
338ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e,
339 const char *name, unsigned int hookmask, unsigned int *cnt)
340{
341 struct ebt_match *match;
Al Viro14197d52006-11-30 19:25:21 -0800342 size_t left = ((char *)e + e->watchers_offset) - (char *)m;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 int ret;
344
Al Viro14197d52006-11-30 19:25:21 -0800345 if (left < sizeof(struct ebt_entry_match) ||
346 left - sizeof(struct ebt_entry_match) < m->match_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 return -EINVAL;
348 match = find_match_lock(m->u.name, &ret, &ebt_mutex);
349 if (!match)
350 return ret;
351 m->u.match = match;
352 if (!try_module_get(match->me)) {
Ingo Molnar57b47a52006-03-20 22:35:41 -0800353 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 return -ENOENT;
355 }
Ingo Molnar57b47a52006-03-20 22:35:41 -0800356 mutex_unlock(&ebt_mutex);
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200357 if (match->family != NFPROTO_BRIDGE) {
358 printk(KERN_WARNING "ebtables: %s match: not for ebtables?\n",
359 match->name);
360 goto out;
361 }
362 if (match->revision != 0) {
363 printk(KERN_WARNING "ebtables: %s match: ebtables is not "
364 "supporting revisions at this time\n",
365 match->name);
366 goto out;
367 }
Jan Engelhardt18219d32008-10-08 11:35:13 +0200368 if (XT_ALIGN(match->matchsize) != m->match_size &&
369 match->matchsize != -1) {
370 /*
371 * ebt_among is exempt from centralized matchsize checking
372 * because it uses a dynamic-size data set.
373 */
374 printk(KERN_WARNING "ebtables: %s match: "
375 "invalid size %Zu != %u\n",
376 match->name, XT_ALIGN(match->matchsize), m->match_size);
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200377 goto out;
Jan Engelhardt18219d32008-10-08 11:35:13 +0200378 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 if (match->check &&
Jan Engelhardt19eda872008-10-08 11:35:13 +0200380 !match->check(name, hookmask, e, m->data, m->match_size)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 BUGPRINT("match->check failed\n");
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200382 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 }
384 (*cnt)++;
385 return 0;
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200386 out:
387 module_put(match->me);
388 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389}
390
391static inline int
392ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,
393 const char *name, unsigned int hookmask, unsigned int *cnt)
394{
395 struct ebt_watcher *watcher;
Al Viro14197d52006-11-30 19:25:21 -0800396 size_t left = ((char *)e + e->target_offset) - (char *)w;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 int ret;
398
Al Viro14197d52006-11-30 19:25:21 -0800399 if (left < sizeof(struct ebt_entry_watcher) ||
400 left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 return -EINVAL;
402 watcher = find_watcher_lock(w->u.name, &ret, &ebt_mutex);
403 if (!watcher)
404 return ret;
405 w->u.watcher = watcher;
406 if (!try_module_get(watcher->me)) {
Ingo Molnar57b47a52006-03-20 22:35:41 -0800407 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 return -ENOENT;
409 }
Ingo Molnar57b47a52006-03-20 22:35:41 -0800410 mutex_unlock(&ebt_mutex);
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200411 if (watcher->family != NFPROTO_BRIDGE) {
412 printk(KERN_WARNING "ebtables: %s watcher: not for ebtables?\n",
413 watcher->name);
414 goto out;
415 }
416 if (watcher->revision != 0) {
417 printk(KERN_WARNING "ebtables: %s watcher: ebtables is not "
418 "supporting revisions at this time\n",
419 watcher->name);
420 goto out;
421 }
Jan Engelhardt18219d32008-10-08 11:35:13 +0200422 if (XT_ALIGN(watcher->targetsize) != w->watcher_size) {
423 printk(KERN_WARNING "ebtables: %s watcher: "
424 "invalid size %Zu != %u\n",
425 watcher->name, XT_ALIGN(watcher->targetsize),
426 w->watcher_size);
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200427 goto out;
Jan Engelhardt18219d32008-10-08 11:35:13 +0200428 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 if (watcher->check &&
Jan Engelhardt19eda872008-10-08 11:35:13 +0200430 !watcher->check(name, hookmask, e, w->data, w->watcher_size)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 BUGPRINT("watcher->check failed\n");
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200432 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 }
434 (*cnt)++;
435 return 0;
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200436 out:
437 module_put(watcher->me);
438 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439}
440
Al Viro70fe9af2006-11-30 19:26:14 -0800441static int ebt_verify_pointers(struct ebt_replace *repl,
442 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443{
Al Viro70fe9af2006-11-30 19:26:14 -0800444 unsigned int limit = repl->entries_size;
445 unsigned int valid_hooks = repl->valid_hooks;
446 unsigned int offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 int i;
448
Al Viroe4fd77d2006-11-30 19:26:35 -0800449 for (i = 0; i < NF_BR_NUMHOOKS; i++)
450 newinfo->hook_entry[i] = NULL;
451
452 newinfo->entries_size = repl->entries_size;
453 newinfo->nentries = repl->nentries;
454
Al Viro70fe9af2006-11-30 19:26:14 -0800455 while (offset < limit) {
456 size_t left = limit - offset;
457 struct ebt_entry *e = (void *)newinfo->entries + offset;
Al Virobb2ef252006-11-30 19:22:42 -0800458
Al Viro70fe9af2006-11-30 19:26:14 -0800459 if (left < sizeof(unsigned int))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 break;
Al Viro22b440b2006-11-30 19:25:51 -0800461
Al Viro70fe9af2006-11-30 19:26:14 -0800462 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
463 if ((valid_hooks & (1 << i)) == 0)
464 continue;
Al Viro1e419cd2006-11-30 19:28:48 -0800465 if ((char __user *)repl->hook_entry[i] ==
466 repl->entries + offset)
Al Viro70fe9af2006-11-30 19:26:14 -0800467 break;
468 }
469
470 if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
471 if (e->bitmask != 0) {
472 /* we make userspace set this right,
473 so there is no misunderstanding */
474 BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
475 "in distinguisher\n");
476 return -EINVAL;
477 }
478 if (i != NF_BR_NUMHOOKS)
479 newinfo->hook_entry[i] = (struct ebt_entries *)e;
480 if (left < sizeof(struct ebt_entries))
481 break;
482 offset += sizeof(struct ebt_entries);
483 } else {
484 if (left < sizeof(struct ebt_entry))
485 break;
486 if (left < e->next_offset)
487 break;
488 offset += e->next_offset;
489 }
490 }
491 if (offset != limit) {
492 BUGPRINT("entries_size too small\n");
493 return -EINVAL;
494 }
Al Viroe4fd77d2006-11-30 19:26:35 -0800495
496 /* check if all valid hooks have a chain */
497 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
498 if (!newinfo->hook_entry[i] &&
499 (valid_hooks & (1 << i))) {
500 BUGPRINT("Valid hook without chain\n");
501 return -EINVAL;
502 }
503 }
Al Viro70fe9af2006-11-30 19:26:14 -0800504 return 0;
Al Viro22b440b2006-11-30 19:25:51 -0800505}
506
507/*
508 * this one is very careful, as it is the first function
509 * to parse the userspace data
510 */
511static inline int
512ebt_check_entry_size_and_hooks(struct ebt_entry *e,
Al Viro0e795532006-11-30 19:27:13 -0800513 struct ebt_table_info *newinfo,
514 unsigned int *n, unsigned int *cnt,
515 unsigned int *totalcnt, unsigned int *udc_cnt)
Al Viro22b440b2006-11-30 19:25:51 -0800516{
Al Viro22b440b2006-11-30 19:25:51 -0800517 int i;
518
519 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Viro0e795532006-11-30 19:27:13 -0800520 if ((void *)e == (void *)newinfo->hook_entry[i])
Al Viro22b440b2006-11-30 19:25:51 -0800521 break;
522 }
523 /* beginning of a new chain
524 if i == NF_BR_NUMHOOKS it must be a user defined chain */
525 if (i != NF_BR_NUMHOOKS || !e->bitmask) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 /* this checks if the previous chain has as many entries
527 as it said it has */
528 if (*n != *cnt) {
529 BUGPRINT("nentries does not equal the nr of entries "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900530 "in the chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 return -EINVAL;
532 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 if (((struct ebt_entries *)e)->policy != EBT_DROP &&
534 ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
535 /* only RETURN from udc */
536 if (i != NF_BR_NUMHOOKS ||
537 ((struct ebt_entries *)e)->policy != EBT_RETURN) {
538 BUGPRINT("bad policy\n");
539 return -EINVAL;
540 }
541 }
542 if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
543 (*udc_cnt)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
545 BUGPRINT("counter_offset != totalcnt");
546 return -EINVAL;
547 }
548 *n = ((struct ebt_entries *)e)->nentries;
549 *cnt = 0;
550 return 0;
551 }
552 /* a plain old entry, heh */
553 if (sizeof(struct ebt_entry) > e->watchers_offset ||
554 e->watchers_offset > e->target_offset ||
555 e->target_offset >= e->next_offset) {
556 BUGPRINT("entry offsets not in right order\n");
557 return -EINVAL;
558 }
559 /* this is not checked anywhere else */
560 if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
561 BUGPRINT("target size too small\n");
562 return -EINVAL;
563 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 (*cnt)++;
565 (*totalcnt)++;
566 return 0;
567}
568
569struct ebt_cl_stack
570{
571 struct ebt_chainstack cs;
572 int from;
573 unsigned int hookmask;
574};
575
576/*
577 * we need these positions to check that the jumps to a different part of the
578 * entries is a jump to the beginning of a new chain.
579 */
580static inline int
581ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Viro177abc32006-11-30 19:27:32 -0800582 unsigned int *n, struct ebt_cl_stack *udc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583{
584 int i;
585
586 /* we're only interested in chain starts */
Al Viro40642f92006-11-30 19:24:12 -0800587 if (e->bitmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 return 0;
589 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
591 break;
592 }
593 /* only care about udc */
594 if (i != NF_BR_NUMHOOKS)
595 return 0;
596
597 udc[*n].cs.chaininfo = (struct ebt_entries *)e;
598 /* these initialisations are depended on later in check_chainloops() */
599 udc[*n].cs.n = 0;
600 udc[*n].hookmask = 0;
601
602 (*n)++;
603 return 0;
604}
605
606static inline int
607ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i)
608{
609 if (i && (*i)-- == 0)
610 return 1;
611 if (m->u.match->destroy)
612 m->u.match->destroy(m->data, m->match_size);
613 module_put(m->u.match->me);
614
615 return 0;
616}
617
618static inline int
619ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
620{
621 if (i && (*i)-- == 0)
622 return 1;
623 if (w->u.watcher->destroy)
624 w->u.watcher->destroy(w->data, w->watcher_size);
625 module_put(w->u.watcher->me);
626
627 return 0;
628}
629
630static inline int
631ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
632{
633 struct ebt_entry_target *t;
634
Al Viro40642f92006-11-30 19:24:12 -0800635 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 return 0;
637 /* we're done */
638 if (cnt && (*cnt)-- == 0)
639 return 1;
640 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
641 EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL);
642 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
643 if (t->u.target->destroy)
644 t->u.target->destroy(t->data, t->target_size);
645 module_put(t->u.target->me);
646
647 return 0;
648}
649
650static inline int
651ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Virof7da79d2006-11-30 19:27:48 -0800652 const char *name, unsigned int *cnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
654{
655 struct ebt_entry_target *t;
656 struct ebt_target *target;
657 unsigned int i, j, hook = 0, hookmask = 0;
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800658 size_t gap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 int ret;
660
661 /* don't mess with the struct ebt_entries */
Al Viro40642f92006-11-30 19:24:12 -0800662 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 return 0;
664
665 if (e->bitmask & ~EBT_F_MASK) {
666 BUGPRINT("Unknown flag for bitmask\n");
667 return -EINVAL;
668 }
669 if (e->invflags & ~EBT_INV_MASK) {
670 BUGPRINT("Unknown flag for inv bitmask\n");
671 return -EINVAL;
672 }
673 if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
674 BUGPRINT("NOPROTO & 802_3 not allowed\n");
675 return -EINVAL;
676 }
677 /* what hook do we belong to? */
678 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Virof7da79d2006-11-30 19:27:48 -0800679 if (!newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 continue;
681 if ((char *)newinfo->hook_entry[i] < (char *)e)
682 hook = i;
683 else
684 break;
685 }
686 /* (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
687 a base chain */
688 if (i < NF_BR_NUMHOOKS)
689 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
690 else {
691 for (i = 0; i < udc_cnt; i++)
692 if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
693 break;
694 if (i == 0)
695 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
696 else
697 hookmask = cl_s[i - 1].hookmask;
698 }
699 i = 0;
700 ret = EBT_MATCH_ITERATE(e, ebt_check_match, e, name, hookmask, &i);
701 if (ret != 0)
702 goto cleanup_matches;
703 j = 0;
704 ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, e, name, hookmask, &j);
705 if (ret != 0)
706 goto cleanup_watchers;
707 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800708 gap = e->next_offset - e->target_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 target = find_target_lock(t->u.name, &ret, &ebt_mutex);
710 if (!target)
711 goto cleanup_watchers;
712 if (!try_module_get(target->me)) {
Ingo Molnar57b47a52006-03-20 22:35:41 -0800713 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 ret = -ENOENT;
715 goto cleanup_watchers;
716 }
Ingo Molnar57b47a52006-03-20 22:35:41 -0800717 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200719 if (target->family != NFPROTO_BRIDGE) {
720 printk(KERN_WARNING "ebtables: %s target: not for ebtables?\n",
721 target->name);
722 ret = -EINVAL;
723 goto cleanup_watchers;
724 }
725 if (target->revision != 0) {
726 printk(KERN_WARNING "ebtables: %s target: ebtables is not "
727 "supporting revisions at this time\n",
728 target->name);
729 ret = -EINVAL;
730 goto cleanup_watchers;
731 }
732
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 t->u.target = target;
734 if (t->u.target == &ebt_standard_target) {
Al Viro14197d52006-11-30 19:25:21 -0800735 if (gap < sizeof(struct ebt_standard_target)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 BUGPRINT("Standard target size too big\n");
737 ret = -EFAULT;
738 goto cleanup_watchers;
739 }
740 if (((struct ebt_standard_target *)t)->verdict <
741 -NUM_STANDARD_TARGETS) {
742 BUGPRINT("Invalid standard target\n");
743 ret = -EFAULT;
744 goto cleanup_watchers;
745 }
Jan Engelhardt18219d32008-10-08 11:35:13 +0200746 } else if (t->target_size > gap - sizeof(struct ebt_entry_target)) {
747 module_put(t->u.target->me);
748 ret = -EFAULT;
749 goto cleanup_watchers;
750 } else if (XT_ALIGN(target->targetsize) != t->target_size) {
751 printk(KERN_WARNING "ebtables: %s target: "
752 "invalid size %Zu != %u\n",
753 target->name, XT_ALIGN(target->targetsize),
754 t->target_size);
755 module_put(t->u.target->me);
756 ret = -EINVAL;
757 goto cleanup_watchers;
758 } else if (t->u.target->check &&
Jan Engelhardt19eda872008-10-08 11:35:13 +0200759 !t->u.target->check(name, hookmask, e, t->data, t->target_size)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 module_put(t->u.target->me);
761 ret = -EFAULT;
762 goto cleanup_watchers;
763 }
764 (*cnt)++;
765 return 0;
766cleanup_watchers:
767 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);
768cleanup_matches:
769 EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i);
770 return ret;
771}
772
773/*
774 * checks for loops and sets the hook mask for udc
775 * the hook mask for udc tells us from which base chains the udc can be
776 * accessed. This mask is a parameter to the check() functions of the extensions
777 */
778static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
779 unsigned int udc_cnt, unsigned int hooknr, char *base)
780{
781 int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
782 struct ebt_entry *e = (struct ebt_entry *)chain->data;
783 struct ebt_entry_target *t;
784
785 while (pos < nentries || chain_nr != -1) {
786 /* end of udc, go back one 'recursion' step */
787 if (pos == nentries) {
788 /* put back values of the time when this chain was called */
789 e = cl_s[chain_nr].cs.e;
790 if (cl_s[chain_nr].from != -1)
791 nentries =
792 cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
793 else
794 nentries = chain->nentries;
795 pos = cl_s[chain_nr].cs.n;
796 /* make sure we won't see a loop that isn't one */
797 cl_s[chain_nr].cs.n = 0;
798 chain_nr = cl_s[chain_nr].from;
799 if (pos == nentries)
800 continue;
801 }
802 t = (struct ebt_entry_target *)
803 (((char *)e) + e->target_offset);
804 if (strcmp(t->u.name, EBT_STANDARD_TARGET))
805 goto letscontinue;
806 if (e->target_offset + sizeof(struct ebt_standard_target) >
807 e->next_offset) {
808 BUGPRINT("Standard target size too big\n");
809 return -1;
810 }
811 verdict = ((struct ebt_standard_target *)t)->verdict;
812 if (verdict >= 0) { /* jump to another chain */
813 struct ebt_entries *hlp2 =
814 (struct ebt_entries *)(base + verdict);
815 for (i = 0; i < udc_cnt; i++)
816 if (hlp2 == cl_s[i].cs.chaininfo)
817 break;
818 /* bad destination or loop */
819 if (i == udc_cnt) {
820 BUGPRINT("bad destination\n");
821 return -1;
822 }
823 if (cl_s[i].cs.n) {
824 BUGPRINT("loop\n");
825 return -1;
826 }
Al Viro98a08242006-11-30 19:24:49 -0800827 if (cl_s[i].hookmask & (1 << hooknr))
828 goto letscontinue;
829 /* this can't be 0, so the loop test is correct */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 cl_s[i].cs.n = pos + 1;
831 pos = 0;
832 cl_s[i].cs.e = ((void *)e + e->next_offset);
833 e = (struct ebt_entry *)(hlp2->data);
834 nentries = hlp2->nentries;
835 cl_s[i].from = chain_nr;
836 chain_nr = i;
837 /* this udc is accessible from the base chain for hooknr */
838 cl_s[i].hookmask |= (1 << hooknr);
839 continue;
840 }
841letscontinue:
842 e = (void *)e + e->next_offset;
843 pos++;
844 }
845 return 0;
846}
847
848/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
Al Viro1bc23262006-11-30 19:28:08 -0800849static int translate_table(char *name, struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850{
851 unsigned int i, j, k, udc_cnt;
852 int ret;
853 struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
854
855 i = 0;
Al Viro1f072c92006-11-30 19:26:53 -0800856 while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 i++;
858 if (i == NF_BR_NUMHOOKS) {
859 BUGPRINT("No valid hooks specified\n");
860 return -EINVAL;
861 }
Al Viro1f072c92006-11-30 19:26:53 -0800862 if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 BUGPRINT("Chains don't start at beginning\n");
864 return -EINVAL;
865 }
866 /* make sure chains are ordered after each other in same order
867 as their corresponding hooks */
868 for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
Al Viro1f072c92006-11-30 19:26:53 -0800869 if (!newinfo->hook_entry[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 continue;
Al Viro1f072c92006-11-30 19:26:53 -0800871 if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 BUGPRINT("Hook order must be followed\n");
873 return -EINVAL;
874 }
875 i = j;
876 }
877
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 /* do some early checkings and initialize some things */
879 i = 0; /* holds the expected nr. of entries for the chain */
880 j = 0; /* holds the up to now counted entries for the chain */
881 k = 0; /* holds the total nr. of entries, should equal
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900882 newinfo->nentries afterwards */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
884 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro0e795532006-11-30 19:27:13 -0800885 ebt_check_entry_size_and_hooks, newinfo,
886 &i, &j, &k, &udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887
888 if (ret != 0)
889 return ret;
890
891 if (i != j) {
892 BUGPRINT("nentries does not equal the nr of entries in the "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900893 "(last) chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 return -EINVAL;
895 }
896 if (k != newinfo->nentries) {
897 BUGPRINT("Total nentries is wrong\n");
898 return -EINVAL;
899 }
900
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 /* get the location of the udc, put them in an array
902 while we're at it, allocate the chainstack */
903 if (udc_cnt) {
904 /* this will get free'd in do_replace()/ebt_register_table()
905 if an error occurs */
Jayachandran C7ad4d2f2006-04-11 17:25:38 -0700906 newinfo->chainstack =
Christoph Lameter53b8a312007-02-20 13:57:51 -0800907 vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 if (!newinfo->chainstack)
909 return -ENOMEM;
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700910 for_each_possible_cpu(i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 newinfo->chainstack[i] =
Jayachandran C18bc89a2006-04-20 00:14:49 -0700912 vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 if (!newinfo->chainstack[i]) {
914 while (i)
915 vfree(newinfo->chainstack[--i]);
916 vfree(newinfo->chainstack);
917 newinfo->chainstack = NULL;
918 return -ENOMEM;
919 }
920 }
921
Jayachandran C18bc89a2006-04-20 00:14:49 -0700922 cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 if (!cl_s)
924 return -ENOMEM;
925 i = 0; /* the i'th udc */
926 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro177abc32006-11-30 19:27:32 -0800927 ebt_get_udc_positions, newinfo, &i, cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 /* sanity check */
929 if (i != udc_cnt) {
930 BUGPRINT("i != udc_cnt\n");
931 vfree(cl_s);
932 return -EFAULT;
933 }
934 }
935
936 /* Check for loops */
937 for (i = 0; i < NF_BR_NUMHOOKS; i++)
Al Viro1f072c92006-11-30 19:26:53 -0800938 if (newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 if (check_chainloops(newinfo->hook_entry[i],
940 cl_s, udc_cnt, i, newinfo->entries)) {
James Lamanna68d31872005-06-22 22:12:57 -0700941 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 return -EINVAL;
943 }
944
Jan Engelhardt96de0e22007-10-19 23:21:04 +0200945 /* we now know the following (along with E=mc²):
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 - the nr of entries in each chain is right
947 - the size of the allocated space is right
948 - all valid hooks have a corresponding chain
949 - there are no loops
950 - wrong data can still be on the level of a single entry
951 - could be there are jumps to places that are not the
952 beginning of a chain. This can only occur in chains that
953 are not accessible from any base chains, so we don't care. */
954
955 /* used to know what we need to clean up if something goes wrong */
956 i = 0;
957 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro1bc23262006-11-30 19:28:08 -0800958 ebt_check_entry, newinfo, name, &i, cl_s, udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 if (ret != 0) {
960 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
961 ebt_cleanup_entry, &i);
962 }
James Lamanna68d31872005-06-22 22:12:57 -0700963 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 return ret;
965}
966
967/* called under write_lock */
968static void get_counters(struct ebt_counter *oldcounters,
969 struct ebt_counter *counters, unsigned int nentries)
970{
971 int i, cpu;
972 struct ebt_counter *counter_base;
973
974 /* counters of cpu 0 */
975 memcpy(counters, oldcounters,
David S. Millerc8923c62005-10-13 14:41:23 -0700976 sizeof(struct ebt_counter) * nentries);
977
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 /* add other counters to those of cpu 0 */
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700979 for_each_possible_cpu(cpu) {
David S. Millerc8923c62005-10-13 14:41:23 -0700980 if (cpu == 0)
981 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
983 for (i = 0; i < nentries; i++) {
984 counters[i].pcnt += counter_base[i].pcnt;
985 counters[i].bcnt += counter_base[i].bcnt;
986 }
987 }
988}
989
990/* replace the table */
991static int do_replace(void __user *user, unsigned int len)
992{
993 int ret, i, countersize;
994 struct ebt_table_info *newinfo;
995 struct ebt_replace tmp;
996 struct ebt_table *t;
997 struct ebt_counter *counterstmp = NULL;
998 /* used to be able to unlock earlier */
999 struct ebt_table_info *table;
1000
1001 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1002 return -EFAULT;
1003
1004 if (len != sizeof(tmp) + tmp.entries_size) {
1005 BUGPRINT("Wrong len argument\n");
1006 return -EINVAL;
1007 }
1008
1009 if (tmp.entries_size == 0) {
1010 BUGPRINT("Entries_size never zero\n");
1011 return -EINVAL;
1012 }
Kirill Korotaevee4bb812006-02-04 02:16:56 -08001013 /* overflow check */
1014 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
1015 SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
1016 return -ENOMEM;
1017 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
1018 return -ENOMEM;
1019
Christoph Lameter53b8a312007-02-20 13:57:51 -08001020 countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -07001021 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 if (!newinfo)
1023 return -ENOMEM;
1024
1025 if (countersize)
1026 memset(newinfo->counters, 0, countersize);
1027
Kris Katterjohn8b3a7002006-01-11 15:56:43 -08001028 newinfo->entries = vmalloc(tmp.entries_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 if (!newinfo->entries) {
1030 ret = -ENOMEM;
1031 goto free_newinfo;
1032 }
1033 if (copy_from_user(
1034 newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
1035 BUGPRINT("Couldn't copy entries from userspace\n");
1036 ret = -EFAULT;
1037 goto free_entries;
1038 }
1039
1040 /* the user wants counters back
1041 the check on the size is done later, when we have the lock */
1042 if (tmp.num_counters) {
Jayachandran C18bc89a2006-04-20 00:14:49 -07001043 counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 if (!counterstmp) {
1045 ret = -ENOMEM;
1046 goto free_entries;
1047 }
1048 }
1049 else
1050 counterstmp = NULL;
1051
1052 /* this can get initialized by translate_table() */
1053 newinfo->chainstack = NULL;
Al Viro1bc23262006-11-30 19:28:08 -08001054 ret = ebt_verify_pointers(&tmp, newinfo);
1055 if (ret != 0)
1056 goto free_counterstmp;
1057
1058 ret = translate_table(tmp.name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
1060 if (ret != 0)
1061 goto free_counterstmp;
1062
1063 t = find_table_lock(tmp.name, &ret, &ebt_mutex);
1064 if (!t) {
1065 ret = -ENOENT;
1066 goto free_iterate;
1067 }
1068
1069 /* the table doesn't like it */
1070 if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
1071 goto free_unlock;
1072
1073 if (tmp.num_counters && tmp.num_counters != t->private->nentries) {
1074 BUGPRINT("Wrong nr. of counters requested\n");
1075 ret = -EINVAL;
1076 goto free_unlock;
1077 }
1078
1079 /* we have the mutex lock, so no danger in reading this pointer */
1080 table = t->private;
1081 /* make sure the table can only be rmmod'ed if it contains no rules */
1082 if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) {
1083 ret = -ENOENT;
1084 goto free_unlock;
1085 } else if (table->nentries && !newinfo->nentries)
1086 module_put(t->me);
1087 /* we need an atomic snapshot of the counters */
1088 write_lock_bh(&t->lock);
1089 if (tmp.num_counters)
1090 get_counters(t->private->counters, counterstmp,
1091 t->private->nentries);
1092
1093 t->private = newinfo;
1094 write_unlock_bh(&t->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001095 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 /* so, a user can change the chains while having messed up her counter
1097 allocation. Only reason why this is done is because this way the lock
1098 is held only once, while this doesn't bring the kernel into a
1099 dangerous state. */
1100 if (tmp.num_counters &&
1101 copy_to_user(tmp.counters, counterstmp,
1102 tmp.num_counters * sizeof(struct ebt_counter))) {
1103 BUGPRINT("Couldn't copy counters to userspace\n");
1104 ret = -EFAULT;
1105 }
1106 else
1107 ret = 0;
1108
1109 /* decrease module count and free resources */
1110 EBT_ENTRY_ITERATE(table->entries, table->entries_size,
1111 ebt_cleanup_entry, NULL);
1112
1113 vfree(table->entries);
1114 if (table->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001115 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 vfree(table->chainstack[i]);
1117 vfree(table->chainstack);
1118 }
1119 vfree(table);
1120
James Lamanna68d31872005-06-22 22:12:57 -07001121 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 return ret;
1123
1124free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001125 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126free_iterate:
1127 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
1128 ebt_cleanup_entry, NULL);
1129free_counterstmp:
James Lamanna68d31872005-06-22 22:12:57 -07001130 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 /* can be initialized in translate_table() */
1132 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001133 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 vfree(newinfo->chainstack[i]);
1135 vfree(newinfo->chainstack);
1136 }
1137free_entries:
James Lamanna68d31872005-06-22 22:12:57 -07001138 vfree(newinfo->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139free_newinfo:
James Lamanna68d31872005-06-22 22:12:57 -07001140 vfree(newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 return ret;
1142}
1143
1144int ebt_register_target(struct ebt_target *target)
1145{
Patrick McHardydf0933d2006-09-20 11:57:53 -07001146 struct ebt_target *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 int ret;
1148
Ingo Molnar57b47a52006-03-20 22:35:41 -08001149 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 if (ret != 0)
1151 return ret;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001152 list_for_each_entry(t, &ebt_targets, list) {
1153 if (strcmp(t->name, target->name) == 0) {
1154 mutex_unlock(&ebt_mutex);
1155 return -EEXIST;
1156 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 }
Patrick McHardydf0933d2006-09-20 11:57:53 -07001158 list_add(&target->list, &ebt_targets);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001159 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160
1161 return 0;
1162}
1163
1164void ebt_unregister_target(struct ebt_target *target)
1165{
Ingo Molnar57b47a52006-03-20 22:35:41 -08001166 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001167 list_del(&target->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001168 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169}
1170
1171int ebt_register_match(struct ebt_match *match)
1172{
Patrick McHardydf0933d2006-09-20 11:57:53 -07001173 struct ebt_match *m;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 int ret;
1175
Ingo Molnar57b47a52006-03-20 22:35:41 -08001176 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 if (ret != 0)
1178 return ret;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001179 list_for_each_entry(m, &ebt_matches, list) {
1180 if (strcmp(m->name, match->name) == 0) {
1181 mutex_unlock(&ebt_mutex);
1182 return -EEXIST;
1183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 }
Patrick McHardydf0933d2006-09-20 11:57:53 -07001185 list_add(&match->list, &ebt_matches);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001186 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187
1188 return 0;
1189}
1190
1191void ebt_unregister_match(struct ebt_match *match)
1192{
Ingo Molnar57b47a52006-03-20 22:35:41 -08001193 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001194 list_del(&match->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001195 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196}
1197
1198int ebt_register_watcher(struct ebt_watcher *watcher)
1199{
Patrick McHardydf0933d2006-09-20 11:57:53 -07001200 struct ebt_watcher *w;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 int ret;
1202
Ingo Molnar57b47a52006-03-20 22:35:41 -08001203 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 if (ret != 0)
1205 return ret;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001206 list_for_each_entry(w, &ebt_watchers, list) {
1207 if (strcmp(w->name, watcher->name) == 0) {
1208 mutex_unlock(&ebt_mutex);
1209 return -EEXIST;
1210 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 }
Patrick McHardydf0933d2006-09-20 11:57:53 -07001212 list_add(&watcher->list, &ebt_watchers);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001213 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214
1215 return 0;
1216}
1217
1218void ebt_unregister_watcher(struct ebt_watcher *watcher)
1219{
Ingo Molnar57b47a52006-03-20 22:35:41 -08001220 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001221 list_del(&watcher->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001222 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223}
1224
1225int ebt_register_table(struct ebt_table *table)
1226{
1227 struct ebt_table_info *newinfo;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001228 struct ebt_table *t;
Al Viro1e419cd2006-11-30 19:28:48 -08001229 struct ebt_replace_kernel *repl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 int ret, i, countersize;
Al Virodf07a812006-11-30 19:28:25 -08001231 void *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232
Al Virodf07a812006-11-30 19:28:25 -08001233 if (!table || !(repl = table->table) || !repl->entries ||
1234 repl->entries_size == 0 ||
1235 repl->counters || table->private) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 BUGPRINT("Bad table data for ebt_register_table!!!\n");
1237 return -EINVAL;
1238 }
1239
Christoph Lameter53b8a312007-02-20 13:57:51 -08001240 countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -07001241 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 ret = -ENOMEM;
1243 if (!newinfo)
1244 return -ENOMEM;
1245
Al Virodf07a812006-11-30 19:28:25 -08001246 p = vmalloc(repl->entries_size);
1247 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 goto free_newinfo;
1249
Al Virodf07a812006-11-30 19:28:25 -08001250 memcpy(p, repl->entries, repl->entries_size);
1251 newinfo->entries = p;
1252
1253 newinfo->entries_size = repl->entries_size;
1254 newinfo->nentries = repl->nentries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255
1256 if (countersize)
1257 memset(newinfo->counters, 0, countersize);
1258
1259 /* fill in newinfo and parse the entries */
1260 newinfo->chainstack = NULL;
Al Virodf07a812006-11-30 19:28:25 -08001261 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1262 if ((repl->valid_hooks & (1 << i)) == 0)
1263 newinfo->hook_entry[i] = NULL;
1264 else
1265 newinfo->hook_entry[i] = p +
1266 ((char *)repl->hook_entry[i] - repl->entries);
1267 }
1268 ret = translate_table(repl->name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 if (ret != 0) {
1270 BUGPRINT("Translate_table failed\n");
1271 goto free_chainstack;
1272 }
1273
1274 if (table->check && table->check(newinfo, table->valid_hooks)) {
1275 BUGPRINT("The table doesn't like its own initial data, lol\n");
1276 return -EINVAL;
1277 }
1278
1279 table->private = newinfo;
1280 rwlock_init(&table->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001281 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 if (ret != 0)
1283 goto free_chainstack;
1284
Patrick McHardydf0933d2006-09-20 11:57:53 -07001285 list_for_each_entry(t, &ebt_tables, list) {
1286 if (strcmp(t->name, table->name) == 0) {
1287 ret = -EEXIST;
1288 BUGPRINT("Table name already exists\n");
1289 goto free_unlock;
1290 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 }
1292
1293 /* Hold a reference count if the chains aren't empty */
1294 if (newinfo->nentries && !try_module_get(table->me)) {
1295 ret = -ENOENT;
1296 goto free_unlock;
1297 }
Patrick McHardydf0933d2006-09-20 11:57:53 -07001298 list_add(&table->list, &ebt_tables);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001299 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 return 0;
1301free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001302 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303free_chainstack:
1304 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001305 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 vfree(newinfo->chainstack[i]);
1307 vfree(newinfo->chainstack);
1308 }
1309 vfree(newinfo->entries);
1310free_newinfo:
1311 vfree(newinfo);
1312 return ret;
1313}
1314
1315void ebt_unregister_table(struct ebt_table *table)
1316{
1317 int i;
1318
1319 if (!table) {
1320 BUGPRINT("Request to unregister NULL table!!!\n");
1321 return;
1322 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001323 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001324 list_del(&table->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001325 mutex_unlock(&ebt_mutex);
James Lamanna68d31872005-06-22 22:12:57 -07001326 vfree(table->private->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 if (table->private->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001328 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 vfree(table->private->chainstack[i]);
1330 vfree(table->private->chainstack);
1331 }
1332 vfree(table->private);
1333}
1334
1335/* userspace just supplied us with counters */
1336static int update_counters(void __user *user, unsigned int len)
1337{
1338 int i, ret;
1339 struct ebt_counter *tmp;
1340 struct ebt_replace hlp;
1341 struct ebt_table *t;
1342
1343 if (copy_from_user(&hlp, user, sizeof(hlp)))
1344 return -EFAULT;
1345
1346 if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
1347 return -EINVAL;
1348 if (hlp.num_counters == 0)
1349 return -EINVAL;
1350
Jayachandran C18bc89a2006-04-20 00:14:49 -07001351 if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 MEMPRINT("Update_counters && nomemory\n");
1353 return -ENOMEM;
1354 }
1355
1356 t = find_table_lock(hlp.name, &ret, &ebt_mutex);
1357 if (!t)
1358 goto free_tmp;
1359
1360 if (hlp.num_counters != t->private->nentries) {
1361 BUGPRINT("Wrong nr of counters\n");
1362 ret = -EINVAL;
1363 goto unlock_mutex;
1364 }
1365
1366 if ( copy_from_user(tmp, hlp.counters,
1367 hlp.num_counters * sizeof(struct ebt_counter)) ) {
1368 BUGPRINT("Updata_counters && !cfu\n");
1369 ret = -EFAULT;
1370 goto unlock_mutex;
1371 }
1372
1373 /* we want an atomic add of the counters */
1374 write_lock_bh(&t->lock);
1375
1376 /* we add to the counters of the first cpu */
1377 for (i = 0; i < hlp.num_counters; i++) {
1378 t->private->counters[i].pcnt += tmp[i].pcnt;
1379 t->private->counters[i].bcnt += tmp[i].bcnt;
1380 }
1381
1382 write_unlock_bh(&t->lock);
1383 ret = 0;
1384unlock_mutex:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001385 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386free_tmp:
1387 vfree(tmp);
1388 return ret;
1389}
1390
1391static inline int ebt_make_matchname(struct ebt_entry_match *m,
Al Viro1e419cd2006-11-30 19:28:48 -08001392 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393{
Al Viro1e419cd2006-11-30 19:28:48 -08001394 char __user *hlp = ubase + ((char *)m - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
1396 return -EFAULT;
1397 return 0;
1398}
1399
1400static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
Al Viro1e419cd2006-11-30 19:28:48 -08001401 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402{
Al Viro1e419cd2006-11-30 19:28:48 -08001403 char __user *hlp = ubase + ((char *)w - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
1405 return -EFAULT;
1406 return 0;
1407}
1408
Al Viro1e419cd2006-11-30 19:28:48 -08001409static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410{
1411 int ret;
Al Viro1e419cd2006-11-30 19:28:48 -08001412 char __user *hlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 struct ebt_entry_target *t;
1414
Al Viro40642f92006-11-30 19:24:12 -08001415 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 return 0;
1417
Al Viro1e419cd2006-11-30 19:28:48 -08001418 hlp = ubase + (((char *)e + e->target_offset) - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +09001420
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
1422 if (ret != 0)
1423 return ret;
1424 ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
1425 if (ret != 0)
1426 return ret;
1427 if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
1428 return -EFAULT;
1429 return 0;
1430}
1431
Ingo Molnar57b47a52006-03-20 22:35:41 -08001432/* called with ebt_mutex locked */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433static int copy_everything_to_user(struct ebt_table *t, void __user *user,
1434 int *len, int cmd)
1435{
1436 struct ebt_replace tmp;
1437 struct ebt_counter *counterstmp, *oldcounters;
1438 unsigned int entries_size, nentries;
1439 char *entries;
1440
1441 if (cmd == EBT_SO_GET_ENTRIES) {
1442 entries_size = t->private->entries_size;
1443 nentries = t->private->nentries;
1444 entries = t->private->entries;
1445 oldcounters = t->private->counters;
1446 } else {
1447 entries_size = t->table->entries_size;
1448 nentries = t->table->nentries;
1449 entries = t->table->entries;
1450 oldcounters = t->table->counters;
1451 }
1452
1453 if (copy_from_user(&tmp, user, sizeof(tmp))) {
1454 BUGPRINT("Cfu didn't work\n");
1455 return -EFAULT;
1456 }
1457
1458 if (*len != sizeof(struct ebt_replace) + entries_size +
1459 (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
1460 BUGPRINT("Wrong size\n");
1461 return -EINVAL;
1462 }
1463
1464 if (tmp.nentries != nentries) {
1465 BUGPRINT("Nentries wrong\n");
1466 return -EINVAL;
1467 }
1468
1469 if (tmp.entries_size != entries_size) {
1470 BUGPRINT("Wrong size\n");
1471 return -EINVAL;
1472 }
1473
1474 /* userspace might not need the counters */
1475 if (tmp.num_counters) {
1476 if (tmp.num_counters != nentries) {
1477 BUGPRINT("Num_counters wrong\n");
1478 return -EINVAL;
1479 }
Jayachandran C18bc89a2006-04-20 00:14:49 -07001480 counterstmp = vmalloc(nentries * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 if (!counterstmp) {
1482 MEMPRINT("Couldn't copy counters, out of memory\n");
1483 return -ENOMEM;
1484 }
1485 write_lock_bh(&t->lock);
1486 get_counters(oldcounters, counterstmp, nentries);
1487 write_unlock_bh(&t->lock);
1488
1489 if (copy_to_user(tmp.counters, counterstmp,
1490 nentries * sizeof(struct ebt_counter))) {
1491 BUGPRINT("Couldn't copy counters to userspace\n");
1492 vfree(counterstmp);
1493 return -EFAULT;
1494 }
1495 vfree(counterstmp);
1496 }
1497
1498 if (copy_to_user(tmp.entries, entries, entries_size)) {
1499 BUGPRINT("Couldn't copy entries to userspace\n");
1500 return -EFAULT;
1501 }
1502 /* set the match/watcher/target names right */
1503 return EBT_ENTRY_ITERATE(entries, entries_size,
1504 ebt_make_names, entries, tmp.entries);
1505}
1506
1507static int do_ebt_set_ctl(struct sock *sk,
1508 int cmd, void __user *user, unsigned int len)
1509{
1510 int ret;
1511
1512 switch(cmd) {
1513 case EBT_SO_SET_ENTRIES:
1514 ret = do_replace(user, len);
1515 break;
1516 case EBT_SO_SET_COUNTERS:
1517 ret = update_counters(user, len);
1518 break;
1519 default:
1520 ret = -EINVAL;
1521 }
1522 return ret;
1523}
1524
1525static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1526{
1527 int ret;
1528 struct ebt_replace tmp;
1529 struct ebt_table *t;
1530
1531 if (copy_from_user(&tmp, user, sizeof(tmp)))
1532 return -EFAULT;
1533
1534 t = find_table_lock(tmp.name, &ret, &ebt_mutex);
1535 if (!t)
1536 return ret;
1537
1538 switch(cmd) {
1539 case EBT_SO_GET_INFO:
1540 case EBT_SO_GET_INIT_INFO:
1541 if (*len != sizeof(struct ebt_replace)){
1542 ret = -EINVAL;
Ingo Molnar57b47a52006-03-20 22:35:41 -08001543 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 break;
1545 }
1546 if (cmd == EBT_SO_GET_INFO) {
1547 tmp.nentries = t->private->nentries;
1548 tmp.entries_size = t->private->entries_size;
1549 tmp.valid_hooks = t->valid_hooks;
1550 } else {
1551 tmp.nentries = t->table->nentries;
1552 tmp.entries_size = t->table->entries_size;
1553 tmp.valid_hooks = t->table->valid_hooks;
1554 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001555 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 if (copy_to_user(user, &tmp, *len) != 0){
1557 BUGPRINT("c2u Didn't work\n");
1558 ret = -EFAULT;
1559 break;
1560 }
1561 ret = 0;
1562 break;
1563
1564 case EBT_SO_GET_ENTRIES:
1565 case EBT_SO_GET_INIT_ENTRIES:
1566 ret = copy_everything_to_user(t, user, len, cmd);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001567 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 break;
1569
1570 default:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001571 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 ret = -EINVAL;
1573 }
1574
1575 return ret;
1576}
1577
1578static struct nf_sockopt_ops ebt_sockopts =
Andrew Morton74ca4e5a2006-03-20 22:55:02 -08001579{
1580 .pf = PF_INET,
1581 .set_optmin = EBT_BASE_CTL,
1582 .set_optmax = EBT_SO_SET_MAX + 1,
1583 .set = do_ebt_set_ctl,
1584 .get_optmin = EBT_BASE_CTL,
1585 .get_optmax = EBT_SO_GET_MAX + 1,
1586 .get = do_ebt_get_ctl,
Neil Horman16fcec32007-09-11 11:28:26 +02001587 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588};
1589
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001590static int __init ebtables_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591{
1592 int ret;
1593
Ingo Molnar57b47a52006-03-20 22:35:41 -08001594 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001595 list_add(&ebt_standard_target.list, &ebt_targets);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001596 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0)
1598 return ret;
1599
Patrick McHardya887c1c2007-07-14 20:46:15 -07001600 printk(KERN_INFO "Ebtables v2.0 registered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 return 0;
1602}
1603
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001604static void __exit ebtables_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605{
1606 nf_unregister_sockopt(&ebt_sockopts);
Patrick McHardya887c1c2007-07-14 20:46:15 -07001607 printk(KERN_INFO "Ebtables v2.0 unregistered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608}
1609
1610EXPORT_SYMBOL(ebt_register_table);
1611EXPORT_SYMBOL(ebt_unregister_table);
1612EXPORT_SYMBOL(ebt_register_match);
1613EXPORT_SYMBOL(ebt_unregister_match);
1614EXPORT_SYMBOL(ebt_register_watcher);
1615EXPORT_SYMBOL(ebt_unregister_watcher);
1616EXPORT_SYMBOL(ebt_register_target);
1617EXPORT_SYMBOL(ebt_unregister_target);
1618EXPORT_SYMBOL(ebt_do_table);
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001619module_init(ebtables_init);
1620module_exit(ebtables_fini);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621MODULE_LICENSE("GPL");