blob: c4f7a2e8ed39a30d9fcd8c218e4afe2fa9435544 [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 Engelhardt043ef462008-10-08 11:35:15 +020063static struct xt_target ebt_standard_target = {
Jan Engelhardt001a18d2008-10-08 11:35:14 +020064 .name = "standard",
65 .revision = 0,
66 .family = NFPROTO_BRIDGE,
Jan Engelhardt043ef462008-10-08 11:35:15 +020067 .targetsize = sizeof(int),
Jan Engelhardt18219d32008-10-08 11:35:13 +020068};
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
70static inline int ebt_do_watcher (struct ebt_entry_watcher *w,
Jan Engelhardt2d06d4a2008-10-08 11:35:15 +020071 struct sk_buff *skb, unsigned int hooknr, const struct net_device *in,
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 const struct net_device *out)
73{
Jan Engelhardt043ef462008-10-08 11:35:15 +020074 w->u.watcher->target(skb, in, out, hooknr, w->u.watcher, w->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 /* 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{
Jan Engelhardt043ef462008-10-08 11:35:15 +020083 return m->u.match->match(skb, in, out, m->u.match, m->data, 0, 0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084}
85
86static inline int ebt_dev_check(char *entry, const struct net_device *device)
87{
88 int i = 0;
Meelis Roos6f5b7ef2006-11-01 18:07:27 -080089 const char *devname = device->name;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
91 if (*entry == '\0')
92 return 0;
93 if (!device)
94 return 1;
95 /* 1 is the wildcard token */
96 while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i])
97 i++;
98 return (devname[i] != entry[i] && entry[i] != 1);
99}
100
101#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
102/* process standard matches */
103static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h,
104 const struct net_device *in, const struct net_device *out)
105{
106 int verdict, i;
107
108 if (e->bitmask & EBT_802_3) {
109 if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO))
110 return 1;
111 } else if (!(e->bitmask & EBT_NOPROTO) &&
112 FWINV2(e->ethproto != h->h_proto, EBT_IPROTO))
113 return 1;
114
115 if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
116 return 1;
117 if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
118 return 1;
119 if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check(
120 e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN))
121 return 1;
122 if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check(
123 e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT))
124 return 1;
125
126 if (e->bitmask & EBT_SOURCEMAC) {
127 verdict = 0;
128 for (i = 0; i < 6; i++)
129 verdict |= (h->h_source[i] ^ e->sourcemac[i]) &
130 e->sourcemsk[i];
131 if (FWINV2(verdict != 0, EBT_ISOURCE) )
132 return 1;
133 }
134 if (e->bitmask & EBT_DESTMAC) {
135 verdict = 0;
136 for (i = 0; i < 6; i++)
137 verdict |= (h->h_dest[i] ^ e->destmac[i]) &
138 e->destmsk[i];
139 if (FWINV2(verdict != 0, EBT_IDEST) )
140 return 1;
141 }
142 return 0;
143}
144
145/* Do some firewalling */
Herbert Xu3db05fe2007-10-15 00:53:15 -0700146unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 const struct net_device *in, const struct net_device *out,
148 struct ebt_table *table)
149{
150 int i, nentries;
151 struct ebt_entry *point;
152 struct ebt_counter *counter_base, *cb_base;
153 struct ebt_entry_target *t;
154 int verdict, sp = 0;
155 struct ebt_chainstack *cs;
156 struct ebt_entries *chaininfo;
157 char *base;
158 struct ebt_table_info *private;
159
160 read_lock_bh(&table->lock);
161 private = table->private;
162 cb_base = COUNTER_BASE(private->counters, private->nentries,
163 smp_processor_id());
164 if (private->chainstack)
165 cs = private->chainstack[smp_processor_id()];
166 else
167 cs = NULL;
168 chaininfo = private->hook_entry[hook];
169 nentries = private->hook_entry[hook]->nentries;
170 point = (struct ebt_entry *)(private->hook_entry[hook]->data);
171 counter_base = cb_base + private->hook_entry[hook]->counter_offset;
172 /* base for chain jumps */
173 base = private->entries;
174 i = 0;
175 while (i < nentries) {
Herbert Xu3db05fe2007-10-15 00:53:15 -0700176 if (ebt_basic_match(point, eth_hdr(skb), in, out))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 goto letscontinue;
178
Herbert Xu3db05fe2007-10-15 00:53:15 -0700179 if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, in, out) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 goto letscontinue;
181
182 /* increase counter */
183 (*(counter_base + i)).pcnt++;
Herbert Xu3db05fe2007-10-15 00:53:15 -0700184 (*(counter_base + i)).bcnt += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185
186 /* these should only watch: not modify, nor tell us
187 what to do with the packet */
Herbert Xu3db05fe2007-10-15 00:53:15 -0700188 EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, hook, in,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 out);
190
191 t = (struct ebt_entry_target *)
192 (((char *)point) + point->target_offset);
193 /* standard target */
194 if (!t->u.target->target)
195 verdict = ((struct ebt_standard_target *)t)->verdict;
196 else
Jan Engelhardt2d06d4a2008-10-08 11:35:15 +0200197 verdict = t->u.target->target(skb, in, out, hook,
Jan Engelhardt043ef462008-10-08 11:35:15 +0200198 t->u.target, t->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 if (verdict == EBT_ACCEPT) {
200 read_unlock_bh(&table->lock);
201 return NF_ACCEPT;
202 }
203 if (verdict == EBT_DROP) {
204 read_unlock_bh(&table->lock);
205 return NF_DROP;
206 }
207 if (verdict == EBT_RETURN) {
208letsreturn:
209#ifdef CONFIG_NETFILTER_DEBUG
210 if (sp == 0) {
211 BUGPRINT("RETURN on base chain");
212 /* act like this is EBT_CONTINUE */
213 goto letscontinue;
214 }
215#endif
216 sp--;
217 /* put all the local variables right */
218 i = cs[sp].n;
219 chaininfo = cs[sp].chaininfo;
220 nentries = chaininfo->nentries;
221 point = cs[sp].e;
222 counter_base = cb_base +
223 chaininfo->counter_offset;
224 continue;
225 }
226 if (verdict == EBT_CONTINUE)
227 goto letscontinue;
228#ifdef CONFIG_NETFILTER_DEBUG
229 if (verdict < 0) {
230 BUGPRINT("bogus standard verdict\n");
231 read_unlock_bh(&table->lock);
232 return NF_DROP;
233 }
234#endif
235 /* jump to a udc */
236 cs[sp].n = i + 1;
237 cs[sp].chaininfo = chaininfo;
238 cs[sp].e = (struct ebt_entry *)
239 (((char *)point) + point->next_offset);
240 i = 0;
241 chaininfo = (struct ebt_entries *) (base + verdict);
242#ifdef CONFIG_NETFILTER_DEBUG
243 if (chaininfo->distinguisher) {
244 BUGPRINT("jump to non-chain\n");
245 read_unlock_bh(&table->lock);
246 return NF_DROP;
247 }
248#endif
249 nentries = chaininfo->nentries;
250 point = (struct ebt_entry *)chaininfo->data;
251 counter_base = cb_base + chaininfo->counter_offset;
252 sp++;
253 continue;
254letscontinue:
255 point = (struct ebt_entry *)
256 (((char *)point) + point->next_offset);
257 i++;
258 }
259
260 /* I actually like this :) */
261 if (chaininfo->policy == EBT_RETURN)
262 goto letsreturn;
263 if (chaininfo->policy == EBT_ACCEPT) {
264 read_unlock_bh(&table->lock);
265 return NF_ACCEPT;
266 }
267 read_unlock_bh(&table->lock);
268 return NF_DROP;
269}
270
271/* If it succeeds, returns element and locks mutex */
272static inline void *
273find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800274 struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275{
Patrick McHardydf0933d2006-09-20 11:57:53 -0700276 struct {
277 struct list_head list;
278 char name[EBT_FUNCTION_MAXNAMELEN];
279 } *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Ingo Molnar57b47a52006-03-20 22:35:41 -0800281 *error = mutex_lock_interruptible(mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 if (*error != 0)
283 return NULL;
284
Patrick McHardydf0933d2006-09-20 11:57:53 -0700285 list_for_each_entry(e, head, list) {
286 if (strcmp(e->name, name) == 0)
287 return e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 }
Patrick McHardydf0933d2006-09-20 11:57:53 -0700289 *error = -ENOENT;
290 mutex_unlock(mutex);
291 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292}
293
294#ifndef CONFIG_KMOD
295#define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
296#else
297static void *
298find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800299 int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300{
301 void *ret;
302
303 ret = find_inlist_lock_noload(head, name, error, mutex);
304 if (!ret) {
305 request_module("%s%s", prefix, name);
306 ret = find_inlist_lock_noload(head, name, error, mutex);
307 }
308 return ret;
309}
310#endif
311
312static inline struct ebt_table *
Ingo Molnar57b47a52006-03-20 22:35:41 -0800313find_table_lock(const char *name, int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314{
315 return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex);
316}
317
318static inline struct ebt_match *
Ingo Molnar57b47a52006-03-20 22:35:41 -0800319find_match_lock(const char *name, int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320{
321 return find_inlist_lock(&ebt_matches, name, "ebt_", error, mutex);
322}
323
324static inline struct ebt_watcher *
Ingo Molnar57b47a52006-03-20 22:35:41 -0800325find_watcher_lock(const char *name, int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326{
327 return find_inlist_lock(&ebt_watchers, name, "ebt_", error, mutex);
328}
329
330static inline struct ebt_target *
Ingo Molnar57b47a52006-03-20 22:35:41 -0800331find_target_lock(const char *name, int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332{
333 return find_inlist_lock(&ebt_targets, name, "ebt_", error, mutex);
334}
335
336static inline int
337ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e,
338 const char *name, unsigned int hookmask, unsigned int *cnt)
339{
Jan Engelhardt043ef462008-10-08 11:35:15 +0200340 struct xt_match *match;
Al Viro14197d52006-11-30 19:25:21 -0800341 size_t left = ((char *)e + e->watchers_offset) - (char *)m;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 int ret;
343
Al Viro14197d52006-11-30 19:25:21 -0800344 if (left < sizeof(struct ebt_entry_match) ||
345 left - sizeof(struct ebt_entry_match) < m->match_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200347
348 match = try_then_request_module(xt_find_match(NFPROTO_BRIDGE,
349 m->u.name, 0), "ebt_%s", m->u.name);
350 if (IS_ERR(match))
351 return PTR_ERR(match);
352 if (match == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200354 m->u.match = match;
355
356 ret = xt_check_match(match, NFPROTO_BRIDGE, m->match_size,
357 name, hookmask, e->ethproto, e->invflags & EBT_IPROTO);
358 if (ret < 0) {
359 module_put(match->me);
360 return ret;
361 } else if (match->checkentry != NULL &&
Jan Engelhardt2d06d4a2008-10-08 11:35:15 +0200362 !match->checkentry(name, e, NULL, m->data, hookmask)) {
Jan Engelhardt043ef462008-10-08 11:35:15 +0200363 module_put(match->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 BUGPRINT("match->check failed\n");
Jan Engelhardt043ef462008-10-08 11:35:15 +0200365 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200367
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 (*cnt)++;
369 return 0;
370}
371
372static inline int
373ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,
374 const char *name, unsigned int hookmask, unsigned int *cnt)
375{
Jan Engelhardt043ef462008-10-08 11:35:15 +0200376 struct xt_target *watcher;
Al Viro14197d52006-11-30 19:25:21 -0800377 size_t left = ((char *)e + e->target_offset) - (char *)w;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 int ret;
379
Al Viro14197d52006-11-30 19:25:21 -0800380 if (left < sizeof(struct ebt_entry_watcher) ||
381 left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200383
384 watcher = try_then_request_module(
385 xt_find_target(NFPROTO_BRIDGE, w->u.name, 0),
386 "ebt_%s", w->u.name);
387 if (IS_ERR(watcher))
388 return PTR_ERR(watcher);
389 if (watcher == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200391 w->u.watcher = watcher;
392
393 ret = xt_check_target(watcher, NFPROTO_BRIDGE, w->watcher_size,
394 name, hookmask, e->ethproto, e->invflags & EBT_IPROTO);
395 if (ret < 0) {
396 module_put(watcher->me);
397 return ret;
398 } else if (watcher->checkentry != NULL &&
Jan Engelhardt2d06d4a2008-10-08 11:35:15 +0200399 !watcher->checkentry(name, e, NULL, w->data, hookmask)) {
Jan Engelhardt043ef462008-10-08 11:35:15 +0200400 module_put(watcher->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 BUGPRINT("watcher->check failed\n");
Jan Engelhardt043ef462008-10-08 11:35:15 +0200402 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200404
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 (*cnt)++;
406 return 0;
407}
408
Al Viro70fe9af2006-11-30 19:26:14 -0800409static int ebt_verify_pointers(struct ebt_replace *repl,
410 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411{
Al Viro70fe9af2006-11-30 19:26:14 -0800412 unsigned int limit = repl->entries_size;
413 unsigned int valid_hooks = repl->valid_hooks;
414 unsigned int offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 int i;
416
Al Viroe4fd77d2006-11-30 19:26:35 -0800417 for (i = 0; i < NF_BR_NUMHOOKS; i++)
418 newinfo->hook_entry[i] = NULL;
419
420 newinfo->entries_size = repl->entries_size;
421 newinfo->nentries = repl->nentries;
422
Al Viro70fe9af2006-11-30 19:26:14 -0800423 while (offset < limit) {
424 size_t left = limit - offset;
425 struct ebt_entry *e = (void *)newinfo->entries + offset;
Al Virobb2ef252006-11-30 19:22:42 -0800426
Al Viro70fe9af2006-11-30 19:26:14 -0800427 if (left < sizeof(unsigned int))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 break;
Al Viro22b440b2006-11-30 19:25:51 -0800429
Al Viro70fe9af2006-11-30 19:26:14 -0800430 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
431 if ((valid_hooks & (1 << i)) == 0)
432 continue;
Al Viro1e419cd2006-11-30 19:28:48 -0800433 if ((char __user *)repl->hook_entry[i] ==
434 repl->entries + offset)
Al Viro70fe9af2006-11-30 19:26:14 -0800435 break;
436 }
437
438 if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
439 if (e->bitmask != 0) {
440 /* we make userspace set this right,
441 so there is no misunderstanding */
442 BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
443 "in distinguisher\n");
444 return -EINVAL;
445 }
446 if (i != NF_BR_NUMHOOKS)
447 newinfo->hook_entry[i] = (struct ebt_entries *)e;
448 if (left < sizeof(struct ebt_entries))
449 break;
450 offset += sizeof(struct ebt_entries);
451 } else {
452 if (left < sizeof(struct ebt_entry))
453 break;
454 if (left < e->next_offset)
455 break;
456 offset += e->next_offset;
457 }
458 }
459 if (offset != limit) {
460 BUGPRINT("entries_size too small\n");
461 return -EINVAL;
462 }
Al Viroe4fd77d2006-11-30 19:26:35 -0800463
464 /* check if all valid hooks have a chain */
465 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
466 if (!newinfo->hook_entry[i] &&
467 (valid_hooks & (1 << i))) {
468 BUGPRINT("Valid hook without chain\n");
469 return -EINVAL;
470 }
471 }
Al Viro70fe9af2006-11-30 19:26:14 -0800472 return 0;
Al Viro22b440b2006-11-30 19:25:51 -0800473}
474
475/*
476 * this one is very careful, as it is the first function
477 * to parse the userspace data
478 */
479static inline int
480ebt_check_entry_size_and_hooks(struct ebt_entry *e,
Al Viro0e795532006-11-30 19:27:13 -0800481 struct ebt_table_info *newinfo,
482 unsigned int *n, unsigned int *cnt,
483 unsigned int *totalcnt, unsigned int *udc_cnt)
Al Viro22b440b2006-11-30 19:25:51 -0800484{
Al Viro22b440b2006-11-30 19:25:51 -0800485 int i;
486
487 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Viro0e795532006-11-30 19:27:13 -0800488 if ((void *)e == (void *)newinfo->hook_entry[i])
Al Viro22b440b2006-11-30 19:25:51 -0800489 break;
490 }
491 /* beginning of a new chain
492 if i == NF_BR_NUMHOOKS it must be a user defined chain */
493 if (i != NF_BR_NUMHOOKS || !e->bitmask) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 /* this checks if the previous chain has as many entries
495 as it said it has */
496 if (*n != *cnt) {
497 BUGPRINT("nentries does not equal the nr of entries "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900498 "in the chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 return -EINVAL;
500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 if (((struct ebt_entries *)e)->policy != EBT_DROP &&
502 ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
503 /* only RETURN from udc */
504 if (i != NF_BR_NUMHOOKS ||
505 ((struct ebt_entries *)e)->policy != EBT_RETURN) {
506 BUGPRINT("bad policy\n");
507 return -EINVAL;
508 }
509 }
510 if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
511 (*udc_cnt)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
513 BUGPRINT("counter_offset != totalcnt");
514 return -EINVAL;
515 }
516 *n = ((struct ebt_entries *)e)->nentries;
517 *cnt = 0;
518 return 0;
519 }
520 /* a plain old entry, heh */
521 if (sizeof(struct ebt_entry) > e->watchers_offset ||
522 e->watchers_offset > e->target_offset ||
523 e->target_offset >= e->next_offset) {
524 BUGPRINT("entry offsets not in right order\n");
525 return -EINVAL;
526 }
527 /* this is not checked anywhere else */
528 if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
529 BUGPRINT("target size too small\n");
530 return -EINVAL;
531 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 (*cnt)++;
533 (*totalcnt)++;
534 return 0;
535}
536
537struct ebt_cl_stack
538{
539 struct ebt_chainstack cs;
540 int from;
541 unsigned int hookmask;
542};
543
544/*
545 * we need these positions to check that the jumps to a different part of the
546 * entries is a jump to the beginning of a new chain.
547 */
548static inline int
549ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Viro177abc32006-11-30 19:27:32 -0800550 unsigned int *n, struct ebt_cl_stack *udc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551{
552 int i;
553
554 /* we're only interested in chain starts */
Al Viro40642f92006-11-30 19:24:12 -0800555 if (e->bitmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 return 0;
557 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
559 break;
560 }
561 /* only care about udc */
562 if (i != NF_BR_NUMHOOKS)
563 return 0;
564
565 udc[*n].cs.chaininfo = (struct ebt_entries *)e;
566 /* these initialisations are depended on later in check_chainloops() */
567 udc[*n].cs.n = 0;
568 udc[*n].hookmask = 0;
569
570 (*n)++;
571 return 0;
572}
573
574static inline int
575ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i)
576{
577 if (i && (*i)-- == 0)
578 return 1;
579 if (m->u.match->destroy)
Jan Engelhardt043ef462008-10-08 11:35:15 +0200580 m->u.match->destroy(m->u.match, m->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 module_put(m->u.match->me);
582
583 return 0;
584}
585
586static inline int
587ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
588{
589 if (i && (*i)-- == 0)
590 return 1;
591 if (w->u.watcher->destroy)
Jan Engelhardt043ef462008-10-08 11:35:15 +0200592 w->u.watcher->destroy(w->u.watcher, w->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 module_put(w->u.watcher->me);
594
595 return 0;
596}
597
598static inline int
599ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
600{
601 struct ebt_entry_target *t;
602
Al Viro40642f92006-11-30 19:24:12 -0800603 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 return 0;
605 /* we're done */
606 if (cnt && (*cnt)-- == 0)
607 return 1;
608 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
609 EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL);
610 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
611 if (t->u.target->destroy)
Jan Engelhardt043ef462008-10-08 11:35:15 +0200612 t->u.target->destroy(t->u.target, t->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 module_put(t->u.target->me);
614
615 return 0;
616}
617
618static inline int
619ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Virof7da79d2006-11-30 19:27:48 -0800620 const char *name, unsigned int *cnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
622{
623 struct ebt_entry_target *t;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200624 struct xt_target *target;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 unsigned int i, j, hook = 0, hookmask = 0;
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800626 size_t gap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 int ret;
628
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;
668 ret = EBT_MATCH_ITERATE(e, ebt_check_match, e, name, hookmask, &i);
669 if (ret != 0)
670 goto cleanup_matches;
671 j = 0;
672 ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, e, name, hookmask, &j);
673 if (ret != 0)
674 goto cleanup_watchers;
675 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800676 gap = e->next_offset - e->target_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
Jan Engelhardt043ef462008-10-08 11:35:15 +0200678 target = try_then_request_module(
679 xt_find_target(NFPROTO_BRIDGE, t->u.name, 0),
680 "ebt_%s", t->u.name);
681 if (IS_ERR(target)) {
682 ret = PTR_ERR(target);
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200683 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200684 } else if (target == NULL) {
685 ret = -ENOENT;
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200686 goto cleanup_watchers;
687 }
688
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 t->u.target = target;
690 if (t->u.target == &ebt_standard_target) {
Al Viro14197d52006-11-30 19:25:21 -0800691 if (gap < sizeof(struct ebt_standard_target)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 BUGPRINT("Standard target size too big\n");
693 ret = -EFAULT;
694 goto cleanup_watchers;
695 }
696 if (((struct ebt_standard_target *)t)->verdict <
697 -NUM_STANDARD_TARGETS) {
698 BUGPRINT("Invalid standard target\n");
699 ret = -EFAULT;
700 goto cleanup_watchers;
701 }
Jan Engelhardt18219d32008-10-08 11:35:13 +0200702 } else if (t->target_size > gap - sizeof(struct ebt_entry_target)) {
703 module_put(t->u.target->me);
704 ret = -EFAULT;
705 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200706 }
707
708 ret = xt_check_target(target, NFPROTO_BRIDGE, t->target_size,
709 name, hookmask, e->ethproto, e->invflags & EBT_IPROTO);
710 if (ret < 0) {
711 module_put(target->me);
Jan Engelhardt18219d32008-10-08 11:35:13 +0200712 goto cleanup_watchers;
Jan Engelhardt2d06d4a2008-10-08 11:35:15 +0200713 } else if (t->u.target->checkentry &&
714 !t->u.target->checkentry(name, e, NULL, t->data, hookmask)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 module_put(t->u.target->me);
716 ret = -EFAULT;
717 goto cleanup_watchers;
718 }
719 (*cnt)++;
720 return 0;
721cleanup_watchers:
722 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);
723cleanup_matches:
724 EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i);
725 return ret;
726}
727
728/*
729 * checks for loops and sets the hook mask for udc
730 * the hook mask for udc tells us from which base chains the udc can be
731 * accessed. This mask is a parameter to the check() functions of the extensions
732 */
733static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
734 unsigned int udc_cnt, unsigned int hooknr, char *base)
735{
736 int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
737 struct ebt_entry *e = (struct ebt_entry *)chain->data;
738 struct ebt_entry_target *t;
739
740 while (pos < nentries || chain_nr != -1) {
741 /* end of udc, go back one 'recursion' step */
742 if (pos == nentries) {
743 /* put back values of the time when this chain was called */
744 e = cl_s[chain_nr].cs.e;
745 if (cl_s[chain_nr].from != -1)
746 nentries =
747 cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
748 else
749 nentries = chain->nentries;
750 pos = cl_s[chain_nr].cs.n;
751 /* make sure we won't see a loop that isn't one */
752 cl_s[chain_nr].cs.n = 0;
753 chain_nr = cl_s[chain_nr].from;
754 if (pos == nentries)
755 continue;
756 }
757 t = (struct ebt_entry_target *)
758 (((char *)e) + e->target_offset);
759 if (strcmp(t->u.name, EBT_STANDARD_TARGET))
760 goto letscontinue;
761 if (e->target_offset + sizeof(struct ebt_standard_target) >
762 e->next_offset) {
763 BUGPRINT("Standard target size too big\n");
764 return -1;
765 }
766 verdict = ((struct ebt_standard_target *)t)->verdict;
767 if (verdict >= 0) { /* jump to another chain */
768 struct ebt_entries *hlp2 =
769 (struct ebt_entries *)(base + verdict);
770 for (i = 0; i < udc_cnt; i++)
771 if (hlp2 == cl_s[i].cs.chaininfo)
772 break;
773 /* bad destination or loop */
774 if (i == udc_cnt) {
775 BUGPRINT("bad destination\n");
776 return -1;
777 }
778 if (cl_s[i].cs.n) {
779 BUGPRINT("loop\n");
780 return -1;
781 }
Al Viro98a08242006-11-30 19:24:49 -0800782 if (cl_s[i].hookmask & (1 << hooknr))
783 goto letscontinue;
784 /* this can't be 0, so the loop test is correct */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 cl_s[i].cs.n = pos + 1;
786 pos = 0;
787 cl_s[i].cs.e = ((void *)e + e->next_offset);
788 e = (struct ebt_entry *)(hlp2->data);
789 nentries = hlp2->nentries;
790 cl_s[i].from = chain_nr;
791 chain_nr = i;
792 /* this udc is accessible from the base chain for hooknr */
793 cl_s[i].hookmask |= (1 << hooknr);
794 continue;
795 }
796letscontinue:
797 e = (void *)e + e->next_offset;
798 pos++;
799 }
800 return 0;
801}
802
803/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
Al Viro1bc23262006-11-30 19:28:08 -0800804static int translate_table(char *name, struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805{
806 unsigned int i, j, k, udc_cnt;
807 int ret;
808 struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
809
810 i = 0;
Al Viro1f072c92006-11-30 19:26:53 -0800811 while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 i++;
813 if (i == NF_BR_NUMHOOKS) {
814 BUGPRINT("No valid hooks specified\n");
815 return -EINVAL;
816 }
Al Viro1f072c92006-11-30 19:26:53 -0800817 if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 BUGPRINT("Chains don't start at beginning\n");
819 return -EINVAL;
820 }
821 /* make sure chains are ordered after each other in same order
822 as their corresponding hooks */
823 for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
Al Viro1f072c92006-11-30 19:26:53 -0800824 if (!newinfo->hook_entry[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 continue;
Al Viro1f072c92006-11-30 19:26:53 -0800826 if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 BUGPRINT("Hook order must be followed\n");
828 return -EINVAL;
829 }
830 i = j;
831 }
832
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 /* do some early checkings and initialize some things */
834 i = 0; /* holds the expected nr. of entries for the chain */
835 j = 0; /* holds the up to now counted entries for the chain */
836 k = 0; /* holds the total nr. of entries, should equal
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900837 newinfo->nentries afterwards */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
839 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro0e795532006-11-30 19:27:13 -0800840 ebt_check_entry_size_and_hooks, newinfo,
841 &i, &j, &k, &udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842
843 if (ret != 0)
844 return ret;
845
846 if (i != j) {
847 BUGPRINT("nentries does not equal the nr of entries in the "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900848 "(last) chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 return -EINVAL;
850 }
851 if (k != newinfo->nentries) {
852 BUGPRINT("Total nentries is wrong\n");
853 return -EINVAL;
854 }
855
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 /* get the location of the udc, put them in an array
857 while we're at it, allocate the chainstack */
858 if (udc_cnt) {
859 /* this will get free'd in do_replace()/ebt_register_table()
860 if an error occurs */
Jayachandran C7ad4d2f2006-04-11 17:25:38 -0700861 newinfo->chainstack =
Christoph Lameter53b8a312007-02-20 13:57:51 -0800862 vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 if (!newinfo->chainstack)
864 return -ENOMEM;
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700865 for_each_possible_cpu(i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 newinfo->chainstack[i] =
Jayachandran C18bc89a2006-04-20 00:14:49 -0700867 vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 if (!newinfo->chainstack[i]) {
869 while (i)
870 vfree(newinfo->chainstack[--i]);
871 vfree(newinfo->chainstack);
872 newinfo->chainstack = NULL;
873 return -ENOMEM;
874 }
875 }
876
Jayachandran C18bc89a2006-04-20 00:14:49 -0700877 cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 if (!cl_s)
879 return -ENOMEM;
880 i = 0; /* the i'th udc */
881 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro177abc32006-11-30 19:27:32 -0800882 ebt_get_udc_positions, newinfo, &i, cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 /* sanity check */
884 if (i != udc_cnt) {
885 BUGPRINT("i != udc_cnt\n");
886 vfree(cl_s);
887 return -EFAULT;
888 }
889 }
890
891 /* Check for loops */
892 for (i = 0; i < NF_BR_NUMHOOKS; i++)
Al Viro1f072c92006-11-30 19:26:53 -0800893 if (newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 if (check_chainloops(newinfo->hook_entry[i],
895 cl_s, udc_cnt, i, newinfo->entries)) {
James Lamanna68d31872005-06-22 22:12:57 -0700896 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 return -EINVAL;
898 }
899
Jan Engelhardt96de0e22007-10-19 23:21:04 +0200900 /* we now know the following (along with E=mc²):
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 - the nr of entries in each chain is right
902 - the size of the allocated space is right
903 - all valid hooks have a corresponding chain
904 - there are no loops
905 - wrong data can still be on the level of a single entry
906 - could be there are jumps to places that are not the
907 beginning of a chain. This can only occur in chains that
908 are not accessible from any base chains, so we don't care. */
909
910 /* used to know what we need to clean up if something goes wrong */
911 i = 0;
912 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro1bc23262006-11-30 19:28:08 -0800913 ebt_check_entry, newinfo, name, &i, cl_s, udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 if (ret != 0) {
915 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
916 ebt_cleanup_entry, &i);
917 }
James Lamanna68d31872005-06-22 22:12:57 -0700918 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 return ret;
920}
921
922/* called under write_lock */
923static void get_counters(struct ebt_counter *oldcounters,
924 struct ebt_counter *counters, unsigned int nentries)
925{
926 int i, cpu;
927 struct ebt_counter *counter_base;
928
929 /* counters of cpu 0 */
930 memcpy(counters, oldcounters,
David S. Millerc8923c62005-10-13 14:41:23 -0700931 sizeof(struct ebt_counter) * nentries);
932
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 /* add other counters to those of cpu 0 */
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700934 for_each_possible_cpu(cpu) {
David S. Millerc8923c62005-10-13 14:41:23 -0700935 if (cpu == 0)
936 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
938 for (i = 0; i < nentries; i++) {
939 counters[i].pcnt += counter_base[i].pcnt;
940 counters[i].bcnt += counter_base[i].bcnt;
941 }
942 }
943}
944
945/* replace the table */
946static int do_replace(void __user *user, unsigned int len)
947{
948 int ret, i, countersize;
949 struct ebt_table_info *newinfo;
950 struct ebt_replace tmp;
951 struct ebt_table *t;
952 struct ebt_counter *counterstmp = NULL;
953 /* used to be able to unlock earlier */
954 struct ebt_table_info *table;
955
956 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
957 return -EFAULT;
958
959 if (len != sizeof(tmp) + tmp.entries_size) {
960 BUGPRINT("Wrong len argument\n");
961 return -EINVAL;
962 }
963
964 if (tmp.entries_size == 0) {
965 BUGPRINT("Entries_size never zero\n");
966 return -EINVAL;
967 }
Kirill Korotaevee4bb812006-02-04 02:16:56 -0800968 /* overflow check */
969 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
970 SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
971 return -ENOMEM;
972 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
973 return -ENOMEM;
974
Christoph Lameter53b8a312007-02-20 13:57:51 -0800975 countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -0700976 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 if (!newinfo)
978 return -ENOMEM;
979
980 if (countersize)
981 memset(newinfo->counters, 0, countersize);
982
Kris Katterjohn8b3a7002006-01-11 15:56:43 -0800983 newinfo->entries = vmalloc(tmp.entries_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 if (!newinfo->entries) {
985 ret = -ENOMEM;
986 goto free_newinfo;
987 }
988 if (copy_from_user(
989 newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
990 BUGPRINT("Couldn't copy entries from userspace\n");
991 ret = -EFAULT;
992 goto free_entries;
993 }
994
995 /* the user wants counters back
996 the check on the size is done later, when we have the lock */
997 if (tmp.num_counters) {
Jayachandran C18bc89a2006-04-20 00:14:49 -0700998 counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 if (!counterstmp) {
1000 ret = -ENOMEM;
1001 goto free_entries;
1002 }
1003 }
1004 else
1005 counterstmp = NULL;
1006
1007 /* this can get initialized by translate_table() */
1008 newinfo->chainstack = NULL;
Al Viro1bc23262006-11-30 19:28:08 -08001009 ret = ebt_verify_pointers(&tmp, newinfo);
1010 if (ret != 0)
1011 goto free_counterstmp;
1012
1013 ret = translate_table(tmp.name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014
1015 if (ret != 0)
1016 goto free_counterstmp;
1017
1018 t = find_table_lock(tmp.name, &ret, &ebt_mutex);
1019 if (!t) {
1020 ret = -ENOENT;
1021 goto free_iterate;
1022 }
1023
1024 /* the table doesn't like it */
1025 if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
1026 goto free_unlock;
1027
1028 if (tmp.num_counters && tmp.num_counters != t->private->nentries) {
1029 BUGPRINT("Wrong nr. of counters requested\n");
1030 ret = -EINVAL;
1031 goto free_unlock;
1032 }
1033
1034 /* we have the mutex lock, so no danger in reading this pointer */
1035 table = t->private;
1036 /* make sure the table can only be rmmod'ed if it contains no rules */
1037 if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) {
1038 ret = -ENOENT;
1039 goto free_unlock;
1040 } else if (table->nentries && !newinfo->nentries)
1041 module_put(t->me);
1042 /* we need an atomic snapshot of the counters */
1043 write_lock_bh(&t->lock);
1044 if (tmp.num_counters)
1045 get_counters(t->private->counters, counterstmp,
1046 t->private->nentries);
1047
1048 t->private = newinfo;
1049 write_unlock_bh(&t->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001050 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 /* so, a user can change the chains while having messed up her counter
1052 allocation. Only reason why this is done is because this way the lock
1053 is held only once, while this doesn't bring the kernel into a
1054 dangerous state. */
1055 if (tmp.num_counters &&
1056 copy_to_user(tmp.counters, counterstmp,
1057 tmp.num_counters * sizeof(struct ebt_counter))) {
1058 BUGPRINT("Couldn't copy counters to userspace\n");
1059 ret = -EFAULT;
1060 }
1061 else
1062 ret = 0;
1063
1064 /* decrease module count and free resources */
1065 EBT_ENTRY_ITERATE(table->entries, table->entries_size,
1066 ebt_cleanup_entry, NULL);
1067
1068 vfree(table->entries);
1069 if (table->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001070 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 vfree(table->chainstack[i]);
1072 vfree(table->chainstack);
1073 }
1074 vfree(table);
1075
James Lamanna68d31872005-06-22 22:12:57 -07001076 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 return ret;
1078
1079free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001080 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081free_iterate:
1082 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
1083 ebt_cleanup_entry, NULL);
1084free_counterstmp:
James Lamanna68d31872005-06-22 22:12:57 -07001085 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 /* can be initialized in translate_table() */
1087 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001088 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 vfree(newinfo->chainstack[i]);
1090 vfree(newinfo->chainstack);
1091 }
1092free_entries:
James Lamanna68d31872005-06-22 22:12:57 -07001093 vfree(newinfo->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094free_newinfo:
James Lamanna68d31872005-06-22 22:12:57 -07001095 vfree(newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 return ret;
1097}
1098
1099int ebt_register_target(struct ebt_target *target)
1100{
Patrick McHardydf0933d2006-09-20 11:57:53 -07001101 struct ebt_target *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 int ret;
1103
Ingo Molnar57b47a52006-03-20 22:35:41 -08001104 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 if (ret != 0)
1106 return ret;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001107 list_for_each_entry(t, &ebt_targets, list) {
1108 if (strcmp(t->name, target->name) == 0) {
1109 mutex_unlock(&ebt_mutex);
1110 return -EEXIST;
1111 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 }
Patrick McHardydf0933d2006-09-20 11:57:53 -07001113 list_add(&target->list, &ebt_targets);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001114 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115
1116 return 0;
1117}
1118
1119void ebt_unregister_target(struct ebt_target *target)
1120{
Ingo Molnar57b47a52006-03-20 22:35:41 -08001121 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001122 list_del(&target->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001123 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124}
1125
1126int ebt_register_match(struct ebt_match *match)
1127{
Patrick McHardydf0933d2006-09-20 11:57:53 -07001128 struct ebt_match *m;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 int ret;
1130
Ingo Molnar57b47a52006-03-20 22:35:41 -08001131 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 if (ret != 0)
1133 return ret;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001134 list_for_each_entry(m, &ebt_matches, list) {
1135 if (strcmp(m->name, match->name) == 0) {
1136 mutex_unlock(&ebt_mutex);
1137 return -EEXIST;
1138 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 }
Patrick McHardydf0933d2006-09-20 11:57:53 -07001140 list_add(&match->list, &ebt_matches);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001141 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142
1143 return 0;
1144}
1145
1146void ebt_unregister_match(struct ebt_match *match)
1147{
Ingo Molnar57b47a52006-03-20 22:35:41 -08001148 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001149 list_del(&match->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001150 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151}
1152
1153int ebt_register_watcher(struct ebt_watcher *watcher)
1154{
Patrick McHardydf0933d2006-09-20 11:57:53 -07001155 struct ebt_watcher *w;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 int ret;
1157
Ingo Molnar57b47a52006-03-20 22:35:41 -08001158 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 if (ret != 0)
1160 return ret;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001161 list_for_each_entry(w, &ebt_watchers, list) {
1162 if (strcmp(w->name, watcher->name) == 0) {
1163 mutex_unlock(&ebt_mutex);
1164 return -EEXIST;
1165 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 }
Patrick McHardydf0933d2006-09-20 11:57:53 -07001167 list_add(&watcher->list, &ebt_watchers);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001168 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169
1170 return 0;
1171}
1172
1173void ebt_unregister_watcher(struct ebt_watcher *watcher)
1174{
Ingo Molnar57b47a52006-03-20 22:35:41 -08001175 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001176 list_del(&watcher->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001177 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178}
1179
1180int ebt_register_table(struct ebt_table *table)
1181{
1182 struct ebt_table_info *newinfo;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001183 struct ebt_table *t;
Al Viro1e419cd2006-11-30 19:28:48 -08001184 struct ebt_replace_kernel *repl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 int ret, i, countersize;
Al Virodf07a812006-11-30 19:28:25 -08001186 void *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187
Al Virodf07a812006-11-30 19:28:25 -08001188 if (!table || !(repl = table->table) || !repl->entries ||
1189 repl->entries_size == 0 ||
1190 repl->counters || table->private) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 BUGPRINT("Bad table data for ebt_register_table!!!\n");
1192 return -EINVAL;
1193 }
1194
Christoph Lameter53b8a312007-02-20 13:57:51 -08001195 countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -07001196 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 ret = -ENOMEM;
1198 if (!newinfo)
1199 return -ENOMEM;
1200
Al Virodf07a812006-11-30 19:28:25 -08001201 p = vmalloc(repl->entries_size);
1202 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 goto free_newinfo;
1204
Al Virodf07a812006-11-30 19:28:25 -08001205 memcpy(p, repl->entries, repl->entries_size);
1206 newinfo->entries = p;
1207
1208 newinfo->entries_size = repl->entries_size;
1209 newinfo->nentries = repl->nentries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
1211 if (countersize)
1212 memset(newinfo->counters, 0, countersize);
1213
1214 /* fill in newinfo and parse the entries */
1215 newinfo->chainstack = NULL;
Al Virodf07a812006-11-30 19:28:25 -08001216 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1217 if ((repl->valid_hooks & (1 << i)) == 0)
1218 newinfo->hook_entry[i] = NULL;
1219 else
1220 newinfo->hook_entry[i] = p +
1221 ((char *)repl->hook_entry[i] - repl->entries);
1222 }
1223 ret = translate_table(repl->name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 if (ret != 0) {
1225 BUGPRINT("Translate_table failed\n");
1226 goto free_chainstack;
1227 }
1228
1229 if (table->check && table->check(newinfo, table->valid_hooks)) {
1230 BUGPRINT("The table doesn't like its own initial data, lol\n");
1231 return -EINVAL;
1232 }
1233
1234 table->private = newinfo;
1235 rwlock_init(&table->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001236 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 if (ret != 0)
1238 goto free_chainstack;
1239
Patrick McHardydf0933d2006-09-20 11:57:53 -07001240 list_for_each_entry(t, &ebt_tables, list) {
1241 if (strcmp(t->name, table->name) == 0) {
1242 ret = -EEXIST;
1243 BUGPRINT("Table name already exists\n");
1244 goto free_unlock;
1245 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 }
1247
1248 /* Hold a reference count if the chains aren't empty */
1249 if (newinfo->nentries && !try_module_get(table->me)) {
1250 ret = -ENOENT;
1251 goto free_unlock;
1252 }
Patrick McHardydf0933d2006-09-20 11:57:53 -07001253 list_add(&table->list, &ebt_tables);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001254 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 return 0;
1256free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001257 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258free_chainstack:
1259 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001260 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 vfree(newinfo->chainstack[i]);
1262 vfree(newinfo->chainstack);
1263 }
1264 vfree(newinfo->entries);
1265free_newinfo:
1266 vfree(newinfo);
1267 return ret;
1268}
1269
1270void ebt_unregister_table(struct ebt_table *table)
1271{
1272 int i;
1273
1274 if (!table) {
1275 BUGPRINT("Request to unregister NULL table!!!\n");
1276 return;
1277 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001278 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001279 list_del(&table->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001280 mutex_unlock(&ebt_mutex);
James Lamanna68d31872005-06-22 22:12:57 -07001281 vfree(table->private->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 if (table->private->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001283 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 vfree(table->private->chainstack[i]);
1285 vfree(table->private->chainstack);
1286 }
1287 vfree(table->private);
1288}
1289
1290/* userspace just supplied us with counters */
1291static int update_counters(void __user *user, unsigned int len)
1292{
1293 int i, ret;
1294 struct ebt_counter *tmp;
1295 struct ebt_replace hlp;
1296 struct ebt_table *t;
1297
1298 if (copy_from_user(&hlp, user, sizeof(hlp)))
1299 return -EFAULT;
1300
1301 if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
1302 return -EINVAL;
1303 if (hlp.num_counters == 0)
1304 return -EINVAL;
1305
Jayachandran C18bc89a2006-04-20 00:14:49 -07001306 if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 MEMPRINT("Update_counters && nomemory\n");
1308 return -ENOMEM;
1309 }
1310
1311 t = find_table_lock(hlp.name, &ret, &ebt_mutex);
1312 if (!t)
1313 goto free_tmp;
1314
1315 if (hlp.num_counters != t->private->nentries) {
1316 BUGPRINT("Wrong nr of counters\n");
1317 ret = -EINVAL;
1318 goto unlock_mutex;
1319 }
1320
1321 if ( copy_from_user(tmp, hlp.counters,
1322 hlp.num_counters * sizeof(struct ebt_counter)) ) {
1323 BUGPRINT("Updata_counters && !cfu\n");
1324 ret = -EFAULT;
1325 goto unlock_mutex;
1326 }
1327
1328 /* we want an atomic add of the counters */
1329 write_lock_bh(&t->lock);
1330
1331 /* we add to the counters of the first cpu */
1332 for (i = 0; i < hlp.num_counters; i++) {
1333 t->private->counters[i].pcnt += tmp[i].pcnt;
1334 t->private->counters[i].bcnt += tmp[i].bcnt;
1335 }
1336
1337 write_unlock_bh(&t->lock);
1338 ret = 0;
1339unlock_mutex:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001340 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341free_tmp:
1342 vfree(tmp);
1343 return ret;
1344}
1345
1346static inline int ebt_make_matchname(struct ebt_entry_match *m,
Al Viro1e419cd2006-11-30 19:28:48 -08001347 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348{
Al Viro1e419cd2006-11-30 19:28:48 -08001349 char __user *hlp = ubase + ((char *)m - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
1351 return -EFAULT;
1352 return 0;
1353}
1354
1355static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
Al Viro1e419cd2006-11-30 19:28:48 -08001356 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357{
Al Viro1e419cd2006-11-30 19:28:48 -08001358 char __user *hlp = ubase + ((char *)w - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
1360 return -EFAULT;
1361 return 0;
1362}
1363
Al Viro1e419cd2006-11-30 19:28:48 -08001364static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365{
1366 int ret;
Al Viro1e419cd2006-11-30 19:28:48 -08001367 char __user *hlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 struct ebt_entry_target *t;
1369
Al Viro40642f92006-11-30 19:24:12 -08001370 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 return 0;
1372
Al Viro1e419cd2006-11-30 19:28:48 -08001373 hlp = ubase + (((char *)e + e->target_offset) - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +09001375
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
1377 if (ret != 0)
1378 return ret;
1379 ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
1380 if (ret != 0)
1381 return ret;
1382 if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
1383 return -EFAULT;
1384 return 0;
1385}
1386
Ingo Molnar57b47a52006-03-20 22:35:41 -08001387/* called with ebt_mutex locked */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388static int copy_everything_to_user(struct ebt_table *t, void __user *user,
1389 int *len, int cmd)
1390{
1391 struct ebt_replace tmp;
1392 struct ebt_counter *counterstmp, *oldcounters;
1393 unsigned int entries_size, nentries;
1394 char *entries;
1395
1396 if (cmd == EBT_SO_GET_ENTRIES) {
1397 entries_size = t->private->entries_size;
1398 nentries = t->private->nentries;
1399 entries = t->private->entries;
1400 oldcounters = t->private->counters;
1401 } else {
1402 entries_size = t->table->entries_size;
1403 nentries = t->table->nentries;
1404 entries = t->table->entries;
1405 oldcounters = t->table->counters;
1406 }
1407
1408 if (copy_from_user(&tmp, user, sizeof(tmp))) {
1409 BUGPRINT("Cfu didn't work\n");
1410 return -EFAULT;
1411 }
1412
1413 if (*len != sizeof(struct ebt_replace) + entries_size +
1414 (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
1415 BUGPRINT("Wrong size\n");
1416 return -EINVAL;
1417 }
1418
1419 if (tmp.nentries != nentries) {
1420 BUGPRINT("Nentries wrong\n");
1421 return -EINVAL;
1422 }
1423
1424 if (tmp.entries_size != entries_size) {
1425 BUGPRINT("Wrong size\n");
1426 return -EINVAL;
1427 }
1428
1429 /* userspace might not need the counters */
1430 if (tmp.num_counters) {
1431 if (tmp.num_counters != nentries) {
1432 BUGPRINT("Num_counters wrong\n");
1433 return -EINVAL;
1434 }
Jayachandran C18bc89a2006-04-20 00:14:49 -07001435 counterstmp = vmalloc(nentries * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 if (!counterstmp) {
1437 MEMPRINT("Couldn't copy counters, out of memory\n");
1438 return -ENOMEM;
1439 }
1440 write_lock_bh(&t->lock);
1441 get_counters(oldcounters, counterstmp, nentries);
1442 write_unlock_bh(&t->lock);
1443
1444 if (copy_to_user(tmp.counters, counterstmp,
1445 nentries * sizeof(struct ebt_counter))) {
1446 BUGPRINT("Couldn't copy counters to userspace\n");
1447 vfree(counterstmp);
1448 return -EFAULT;
1449 }
1450 vfree(counterstmp);
1451 }
1452
1453 if (copy_to_user(tmp.entries, entries, entries_size)) {
1454 BUGPRINT("Couldn't copy entries to userspace\n");
1455 return -EFAULT;
1456 }
1457 /* set the match/watcher/target names right */
1458 return EBT_ENTRY_ITERATE(entries, entries_size,
1459 ebt_make_names, entries, tmp.entries);
1460}
1461
1462static int do_ebt_set_ctl(struct sock *sk,
1463 int cmd, void __user *user, unsigned int len)
1464{
1465 int ret;
1466
1467 switch(cmd) {
1468 case EBT_SO_SET_ENTRIES:
1469 ret = do_replace(user, len);
1470 break;
1471 case EBT_SO_SET_COUNTERS:
1472 ret = update_counters(user, len);
1473 break;
1474 default:
1475 ret = -EINVAL;
1476 }
1477 return ret;
1478}
1479
1480static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1481{
1482 int ret;
1483 struct ebt_replace tmp;
1484 struct ebt_table *t;
1485
1486 if (copy_from_user(&tmp, user, sizeof(tmp)))
1487 return -EFAULT;
1488
1489 t = find_table_lock(tmp.name, &ret, &ebt_mutex);
1490 if (!t)
1491 return ret;
1492
1493 switch(cmd) {
1494 case EBT_SO_GET_INFO:
1495 case EBT_SO_GET_INIT_INFO:
1496 if (*len != sizeof(struct ebt_replace)){
1497 ret = -EINVAL;
Ingo Molnar57b47a52006-03-20 22:35:41 -08001498 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 break;
1500 }
1501 if (cmd == EBT_SO_GET_INFO) {
1502 tmp.nentries = t->private->nentries;
1503 tmp.entries_size = t->private->entries_size;
1504 tmp.valid_hooks = t->valid_hooks;
1505 } else {
1506 tmp.nentries = t->table->nentries;
1507 tmp.entries_size = t->table->entries_size;
1508 tmp.valid_hooks = t->table->valid_hooks;
1509 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001510 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 if (copy_to_user(user, &tmp, *len) != 0){
1512 BUGPRINT("c2u Didn't work\n");
1513 ret = -EFAULT;
1514 break;
1515 }
1516 ret = 0;
1517 break;
1518
1519 case EBT_SO_GET_ENTRIES:
1520 case EBT_SO_GET_INIT_ENTRIES:
1521 ret = copy_everything_to_user(t, user, len, cmd);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001522 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 break;
1524
1525 default:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001526 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 ret = -EINVAL;
1528 }
1529
1530 return ret;
1531}
1532
1533static struct nf_sockopt_ops ebt_sockopts =
Andrew Morton74ca4e5a2006-03-20 22:55:02 -08001534{
1535 .pf = PF_INET,
1536 .set_optmin = EBT_BASE_CTL,
1537 .set_optmax = EBT_SO_SET_MAX + 1,
1538 .set = do_ebt_set_ctl,
1539 .get_optmin = EBT_BASE_CTL,
1540 .get_optmax = EBT_SO_GET_MAX + 1,
1541 .get = do_ebt_get_ctl,
Neil Horman16fcec32007-09-11 11:28:26 +02001542 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543};
1544
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001545static int __init ebtables_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546{
1547 int ret;
1548
Jan Engelhardt043ef462008-10-08 11:35:15 +02001549 ret = xt_register_target(&ebt_standard_target);
1550 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 return ret;
Jan Engelhardt043ef462008-10-08 11:35:15 +02001552 ret = nf_register_sockopt(&ebt_sockopts);
1553 if (ret < 0) {
1554 xt_unregister_target(&ebt_standard_target);
1555 return ret;
1556 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557
Patrick McHardya887c1c2007-07-14 20:46:15 -07001558 printk(KERN_INFO "Ebtables v2.0 registered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 return 0;
1560}
1561
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001562static void __exit ebtables_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563{
1564 nf_unregister_sockopt(&ebt_sockopts);
Jan Engelhardt043ef462008-10-08 11:35:15 +02001565 xt_unregister_target(&ebt_standard_target);
Patrick McHardya887c1c2007-07-14 20:46:15 -07001566 printk(KERN_INFO "Ebtables v2.0 unregistered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567}
1568
1569EXPORT_SYMBOL(ebt_register_table);
1570EXPORT_SYMBOL(ebt_unregister_table);
1571EXPORT_SYMBOL(ebt_register_match);
1572EXPORT_SYMBOL(ebt_unregister_match);
1573EXPORT_SYMBOL(ebt_register_watcher);
1574EXPORT_SYMBOL(ebt_unregister_watcher);
1575EXPORT_SYMBOL(ebt_register_target);
1576EXPORT_SYMBOL(ebt_unregister_target);
1577EXPORT_SYMBOL(ebt_do_table);
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001578module_init(ebtables_init);
1579module_exit(ebtables_fini);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580MODULE_LICENSE("GPL");