blob: 820252aee81f1c1f59bba3cf3e666c2e494b5812 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * ebtables
3 *
4 * Author:
5 * Bart De Schuymer <bdschuym@pandora.be>
6 *
7 * ebtables.c,v 2.0, July, 2002
8 *
9 * This code is stongly inspired on the iptables code which is
10 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version
15 * 2 of the License, or (at your option) any later version.
16 */
17
Linus Torvalds1da177e2005-04-16 15:20:36 -070018
19#include <linux/kmod.h>
20#include <linux/module.h>
21#include <linux/vmalloc.h>
Jan Engelhardt18219d32008-10-08 11:35:13 +020022#include <linux/netfilter/x_tables.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/netfilter_bridge/ebtables.h>
24#include <linux/spinlock.h>
Patrick McHardydf0933d2006-09-20 11:57:53 -070025#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <asm/uaccess.h>
27#include <linux/smp.h>
David S. Millerc8923c62005-10-13 14:41:23 -070028#include <linux/cpumask.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <net/sock.h>
30/* needed for logical [in,out]-dev filtering */
31#include "../br_private.h"
32
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +090034 "report to author: "format, ## args)
Linus Torvalds1da177e2005-04-16 15:20:36 -070035/* #define BUGPRINT(format, args...) */
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#define MEMPRINT(format, args...) printk("kernel msg: ebtables "\
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +090037 ": out of memory: "format, ## args)
Linus Torvalds1da177e2005-04-16 15:20:36 -070038/* #define MEMPRINT(format, args...) */
39
40
41
42/*
43 * Each cpu has its own set of counters, so there is no need for write_lock in
44 * the softirq
45 * For reading or updating the counters, the user context needs to
46 * get a write_lock
47 */
48
49/* The size of each set of counters is altered to get cache alignment */
50#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
51#define COUNTER_OFFSET(n) (SMP_ALIGN(n * sizeof(struct ebt_counter)))
52#define COUNTER_BASE(c, n, cpu) ((struct ebt_counter *)(((char *)c) + \
53 COUNTER_OFFSET(n) * cpu))
54
55
56
Ingo Molnar57b47a52006-03-20 22:35:41 -080057static DEFINE_MUTEX(ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
Jan Engelhardt043ef462008-10-08 11:35:15 +020059static struct xt_target ebt_standard_target = {
Jan Engelhardt001a18d2008-10-08 11:35:14 +020060 .name = "standard",
61 .revision = 0,
62 .family = NFPROTO_BRIDGE,
Jan Engelhardt043ef462008-10-08 11:35:15 +020063 .targetsize = sizeof(int),
Jan Engelhardt18219d32008-10-08 11:35:13 +020064};
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
Jan Engelhardt7eb35582008-10-08 11:35:19 +020066static inline int
67ebt_do_watcher(const struct ebt_entry_watcher *w, struct sk_buff *skb,
68 struct xt_target_param *par)
Linus Torvalds1da177e2005-04-16 15:20:36 -070069{
Jan Engelhardt7eb35582008-10-08 11:35:19 +020070 par->target = w->u.watcher;
71 par->targinfo = w->data;
72 w->u.watcher->target(skb, par);
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 /* watchers don't give a verdict */
74 return 0;
75}
76
77static inline int ebt_do_match (struct ebt_entry_match *m,
Jan Engelhardtf7108a22008-10-08 11:35:18 +020078 const struct sk_buff *skb, struct xt_match_param *par)
Linus Torvalds1da177e2005-04-16 15:20:36 -070079{
Jan Engelhardtf7108a22008-10-08 11:35:18 +020080 par->match = m->u.match;
81 par->matchinfo = m->data;
Jan Engelhardtd61ba9f2009-01-12 00:06:06 +000082 return m->u.match->match(skb, par) ? EBT_MATCH : EBT_NOMATCH;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083}
84
85static inline int ebt_dev_check(char *entry, const struct net_device *device)
86{
87 int i = 0;
Julia Lawallf3d8b2e2009-01-09 10:22:22 +000088 const char *devname;
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90 if (*entry == '\0')
91 return 0;
92 if (!device)
93 return 1;
Julia Lawallf3d8b2e2009-01-09 10:22:22 +000094 devname = device->name;
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 /* 1 is the wildcard token */
96 while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i])
97 i++;
98 return (devname[i] != entry[i] && entry[i] != 1);
99}
100
101#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
102/* process standard matches */
103static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h,
104 const struct net_device *in, const struct net_device *out)
105{
106 int verdict, i;
107
108 if (e->bitmask & EBT_802_3) {
109 if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO))
110 return 1;
111 } else if (!(e->bitmask & EBT_NOPROTO) &&
112 FWINV2(e->ethproto != h->h_proto, EBT_IPROTO))
113 return 1;
114
115 if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
116 return 1;
117 if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
118 return 1;
119 if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check(
120 e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN))
121 return 1;
122 if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check(
123 e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT))
124 return 1;
125
126 if (e->bitmask & EBT_SOURCEMAC) {
127 verdict = 0;
128 for (i = 0; i < 6; i++)
129 verdict |= (h->h_source[i] ^ e->sourcemac[i]) &
130 e->sourcemsk[i];
131 if (FWINV2(verdict != 0, EBT_ISOURCE) )
132 return 1;
133 }
134 if (e->bitmask & EBT_DESTMAC) {
135 verdict = 0;
136 for (i = 0; i < 6; i++)
137 verdict |= (h->h_dest[i] ^ e->destmac[i]) &
138 e->destmsk[i];
139 if (FWINV2(verdict != 0, EBT_IDEST) )
140 return 1;
141 }
142 return 0;
143}
144
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;
Jan Engelhardt5365f802008-10-08 11:35:16 +0200159 bool hotdrop = false;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200160 struct xt_match_param mtpar;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200161 struct xt_target_param tgpar;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200162
Jan Engelhardt916a9172008-10-08 11:35:20 +0200163 mtpar.family = tgpar.family = NFPROTO_BRIDGE;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200164 mtpar.in = tgpar.in = in;
165 mtpar.out = tgpar.out = out;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200166 mtpar.hotdrop = &hotdrop;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200167 tgpar.hooknum = hook;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
169 read_lock_bh(&table->lock);
170 private = table->private;
171 cb_base = COUNTER_BASE(private->counters, private->nentries,
172 smp_processor_id());
173 if (private->chainstack)
174 cs = private->chainstack[smp_processor_id()];
175 else
176 cs = NULL;
177 chaininfo = private->hook_entry[hook];
178 nentries = private->hook_entry[hook]->nentries;
179 point = (struct ebt_entry *)(private->hook_entry[hook]->data);
180 counter_base = cb_base + private->hook_entry[hook]->counter_offset;
181 /* base for chain jumps */
182 base = private->entries;
183 i = 0;
184 while (i < nentries) {
Herbert Xu3db05fe2007-10-15 00:53:15 -0700185 if (ebt_basic_match(point, eth_hdr(skb), in, out))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 goto letscontinue;
187
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200188 if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, &mtpar) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 goto letscontinue;
Jan Engelhardt5365f802008-10-08 11:35:16 +0200190 if (hotdrop) {
191 read_unlock_bh(&table->lock);
192 return NF_DROP;
193 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195 /* increase counter */
196 (*(counter_base + i)).pcnt++;
Herbert Xu3db05fe2007-10-15 00:53:15 -0700197 (*(counter_base + i)).bcnt += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
199 /* these should only watch: not modify, nor tell us
200 what to do with the packet */
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200201 EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, &tgpar);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
203 t = (struct ebt_entry_target *)
204 (((char *)point) + point->target_offset);
205 /* standard target */
206 if (!t->u.target->target)
207 verdict = ((struct ebt_standard_target *)t)->verdict;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200208 else {
209 tgpar.target = t->u.target;
210 tgpar.targinfo = t->data;
211 verdict = t->u.target->target(skb, &tgpar);
212 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 if (verdict == EBT_ACCEPT) {
214 read_unlock_bh(&table->lock);
215 return NF_ACCEPT;
216 }
217 if (verdict == EBT_DROP) {
218 read_unlock_bh(&table->lock);
219 return NF_DROP;
220 }
221 if (verdict == EBT_RETURN) {
222letsreturn:
223#ifdef CONFIG_NETFILTER_DEBUG
224 if (sp == 0) {
225 BUGPRINT("RETURN on base chain");
226 /* act like this is EBT_CONTINUE */
227 goto letscontinue;
228 }
229#endif
230 sp--;
231 /* put all the local variables right */
232 i = cs[sp].n;
233 chaininfo = cs[sp].chaininfo;
234 nentries = chaininfo->nentries;
235 point = cs[sp].e;
236 counter_base = cb_base +
237 chaininfo->counter_offset;
238 continue;
239 }
240 if (verdict == EBT_CONTINUE)
241 goto letscontinue;
242#ifdef CONFIG_NETFILTER_DEBUG
243 if (verdict < 0) {
244 BUGPRINT("bogus standard verdict\n");
245 read_unlock_bh(&table->lock);
246 return NF_DROP;
247 }
248#endif
249 /* jump to a udc */
250 cs[sp].n = i + 1;
251 cs[sp].chaininfo = chaininfo;
252 cs[sp].e = (struct ebt_entry *)
253 (((char *)point) + point->next_offset);
254 i = 0;
255 chaininfo = (struct ebt_entries *) (base + verdict);
256#ifdef CONFIG_NETFILTER_DEBUG
257 if (chaininfo->distinguisher) {
258 BUGPRINT("jump to non-chain\n");
259 read_unlock_bh(&table->lock);
260 return NF_DROP;
261 }
262#endif
263 nentries = chaininfo->nentries;
264 point = (struct ebt_entry *)chaininfo->data;
265 counter_base = cb_base + chaininfo->counter_offset;
266 sp++;
267 continue;
268letscontinue:
269 point = (struct ebt_entry *)
270 (((char *)point) + point->next_offset);
271 i++;
272 }
273
274 /* I actually like this :) */
275 if (chaininfo->policy == EBT_RETURN)
276 goto letsreturn;
277 if (chaininfo->policy == EBT_ACCEPT) {
278 read_unlock_bh(&table->lock);
279 return NF_ACCEPT;
280 }
281 read_unlock_bh(&table->lock);
282 return NF_DROP;
283}
284
285/* If it succeeds, returns element and locks mutex */
286static inline void *
287find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800288 struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289{
Patrick McHardydf0933d2006-09-20 11:57:53 -0700290 struct {
291 struct list_head list;
292 char name[EBT_FUNCTION_MAXNAMELEN];
293 } *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
Ingo Molnar57b47a52006-03-20 22:35:41 -0800295 *error = mutex_lock_interruptible(mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 if (*error != 0)
297 return NULL;
298
Patrick McHardydf0933d2006-09-20 11:57:53 -0700299 list_for_each_entry(e, head, list) {
300 if (strcmp(e->name, name) == 0)
301 return e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 }
Patrick McHardydf0933d2006-09-20 11:57:53 -0700303 *error = -ENOENT;
304 mutex_unlock(mutex);
305 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306}
307
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308static void *
309find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800310 int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311{
Johannes Berg95a5afc2008-10-16 15:24:51 -0700312 return try_then_request_module(
313 find_inlist_lock_noload(head, name, error, mutex),
314 "%s%s", prefix, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
317static inline struct ebt_table *
Alexey Dobriyan511061e2008-11-04 14:22:55 +0100318find_table_lock(struct net *net, const char *name, int *error,
319 struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320{
Alexey Dobriyan511061e2008-11-04 14:22:55 +0100321 return find_inlist_lock(&net->xt.tables[NFPROTO_BRIDGE], name,
322 "ebtable_", error, mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323}
324
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325static inline int
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200326ebt_check_match(struct ebt_entry_match *m, struct xt_mtchk_param *par,
327 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328{
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200329 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200330 struct xt_match *match;
Al Viro14197d52006-11-30 19:25:21 -0800331 size_t left = ((char *)e + e->watchers_offset) - (char *)m;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 int ret;
333
Al Viro14197d52006-11-30 19:25:21 -0800334 if (left < sizeof(struct ebt_entry_match) ||
335 left - sizeof(struct ebt_entry_match) < m->match_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200337
338 match = try_then_request_module(xt_find_match(NFPROTO_BRIDGE,
339 m->u.name, 0), "ebt_%s", m->u.name);
340 if (IS_ERR(match))
341 return PTR_ERR(match);
342 if (match == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200344 m->u.match = match;
345
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200346 par->match = match;
347 par->matchinfo = m->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200348 ret = xt_check_match(par, m->match_size,
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200349 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200350 if (ret < 0) {
351 module_put(match->me);
352 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200354
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 (*cnt)++;
356 return 0;
357}
358
359static inline int
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200360ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
361 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362{
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200363 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200364 struct xt_target *watcher;
Al Viro14197d52006-11-30 19:25:21 -0800365 size_t left = ((char *)e + e->target_offset) - (char *)w;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 int ret;
367
Al Viro14197d52006-11-30 19:25:21 -0800368 if (left < sizeof(struct ebt_entry_watcher) ||
369 left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200371
372 watcher = try_then_request_module(
373 xt_find_target(NFPROTO_BRIDGE, w->u.name, 0),
374 "ebt_%s", w->u.name);
375 if (IS_ERR(watcher))
376 return PTR_ERR(watcher);
377 if (watcher == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200379 w->u.watcher = watcher;
380
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200381 par->target = watcher;
382 par->targinfo = w->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200383 ret = xt_check_target(par, w->watcher_size,
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200384 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200385 if (ret < 0) {
386 module_put(watcher->me);
387 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200389
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 (*cnt)++;
391 return 0;
392}
393
Al Viro70fe9af2006-11-30 19:26:14 -0800394static int ebt_verify_pointers(struct ebt_replace *repl,
395 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396{
Al Viro70fe9af2006-11-30 19:26:14 -0800397 unsigned int limit = repl->entries_size;
398 unsigned int valid_hooks = repl->valid_hooks;
399 unsigned int offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 int i;
401
Al Viroe4fd77d2006-11-30 19:26:35 -0800402 for (i = 0; i < NF_BR_NUMHOOKS; i++)
403 newinfo->hook_entry[i] = NULL;
404
405 newinfo->entries_size = repl->entries_size;
406 newinfo->nentries = repl->nentries;
407
Al Viro70fe9af2006-11-30 19:26:14 -0800408 while (offset < limit) {
409 size_t left = limit - offset;
410 struct ebt_entry *e = (void *)newinfo->entries + offset;
Al Virobb2ef252006-11-30 19:22:42 -0800411
Al Viro70fe9af2006-11-30 19:26:14 -0800412 if (left < sizeof(unsigned int))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 break;
Al Viro22b440b2006-11-30 19:25:51 -0800414
Al Viro70fe9af2006-11-30 19:26:14 -0800415 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
416 if ((valid_hooks & (1 << i)) == 0)
417 continue;
Al Viro1e419cd2006-11-30 19:28:48 -0800418 if ((char __user *)repl->hook_entry[i] ==
419 repl->entries + offset)
Al Viro70fe9af2006-11-30 19:26:14 -0800420 break;
421 }
422
423 if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
424 if (e->bitmask != 0) {
425 /* we make userspace set this right,
426 so there is no misunderstanding */
427 BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
428 "in distinguisher\n");
429 return -EINVAL;
430 }
431 if (i != NF_BR_NUMHOOKS)
432 newinfo->hook_entry[i] = (struct ebt_entries *)e;
433 if (left < sizeof(struct ebt_entries))
434 break;
435 offset += sizeof(struct ebt_entries);
436 } else {
437 if (left < sizeof(struct ebt_entry))
438 break;
439 if (left < e->next_offset)
440 break;
441 offset += e->next_offset;
442 }
443 }
444 if (offset != limit) {
445 BUGPRINT("entries_size too small\n");
446 return -EINVAL;
447 }
Al Viroe4fd77d2006-11-30 19:26:35 -0800448
449 /* check if all valid hooks have a chain */
450 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
451 if (!newinfo->hook_entry[i] &&
452 (valid_hooks & (1 << i))) {
453 BUGPRINT("Valid hook without chain\n");
454 return -EINVAL;
455 }
456 }
Al Viro70fe9af2006-11-30 19:26:14 -0800457 return 0;
Al Viro22b440b2006-11-30 19:25:51 -0800458}
459
460/*
461 * this one is very careful, as it is the first function
462 * to parse the userspace data
463 */
464static inline int
465ebt_check_entry_size_and_hooks(struct ebt_entry *e,
Al Viro0e795532006-11-30 19:27:13 -0800466 struct ebt_table_info *newinfo,
467 unsigned int *n, unsigned int *cnt,
468 unsigned int *totalcnt, unsigned int *udc_cnt)
Al Viro22b440b2006-11-30 19:25:51 -0800469{
Al Viro22b440b2006-11-30 19:25:51 -0800470 int i;
471
472 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Viro0e795532006-11-30 19:27:13 -0800473 if ((void *)e == (void *)newinfo->hook_entry[i])
Al Viro22b440b2006-11-30 19:25:51 -0800474 break;
475 }
476 /* beginning of a new chain
477 if i == NF_BR_NUMHOOKS it must be a user defined chain */
478 if (i != NF_BR_NUMHOOKS || !e->bitmask) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 /* this checks if the previous chain has as many entries
480 as it said it has */
481 if (*n != *cnt) {
482 BUGPRINT("nentries does not equal the nr of entries "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900483 "in the chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 return -EINVAL;
485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 if (((struct ebt_entries *)e)->policy != EBT_DROP &&
487 ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
488 /* only RETURN from udc */
489 if (i != NF_BR_NUMHOOKS ||
490 ((struct ebt_entries *)e)->policy != EBT_RETURN) {
491 BUGPRINT("bad policy\n");
492 return -EINVAL;
493 }
494 }
495 if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
496 (*udc_cnt)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
498 BUGPRINT("counter_offset != totalcnt");
499 return -EINVAL;
500 }
501 *n = ((struct ebt_entries *)e)->nentries;
502 *cnt = 0;
503 return 0;
504 }
505 /* a plain old entry, heh */
506 if (sizeof(struct ebt_entry) > e->watchers_offset ||
507 e->watchers_offset > e->target_offset ||
508 e->target_offset >= e->next_offset) {
509 BUGPRINT("entry offsets not in right order\n");
510 return -EINVAL;
511 }
512 /* this is not checked anywhere else */
513 if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
514 BUGPRINT("target size too small\n");
515 return -EINVAL;
516 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 (*cnt)++;
518 (*totalcnt)++;
519 return 0;
520}
521
522struct ebt_cl_stack
523{
524 struct ebt_chainstack cs;
525 int from;
526 unsigned int hookmask;
527};
528
529/*
530 * we need these positions to check that the jumps to a different part of the
531 * entries is a jump to the beginning of a new chain.
532 */
533static inline int
534ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Viro177abc32006-11-30 19:27:32 -0800535 unsigned int *n, struct ebt_cl_stack *udc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536{
537 int i;
538
539 /* we're only interested in chain starts */
Al Viro40642f92006-11-30 19:24:12 -0800540 if (e->bitmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 return 0;
542 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
544 break;
545 }
546 /* only care about udc */
547 if (i != NF_BR_NUMHOOKS)
548 return 0;
549
550 udc[*n].cs.chaininfo = (struct ebt_entries *)e;
551 /* these initialisations are depended on later in check_chainloops() */
552 udc[*n].cs.n = 0;
553 udc[*n].hookmask = 0;
554
555 (*n)++;
556 return 0;
557}
558
559static inline int
560ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i)
561{
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200562 struct xt_mtdtor_param par;
563
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 if (i && (*i)-- == 0)
565 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200567 par.match = m->u.match;
568 par.matchinfo = m->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200569 par.family = NFPROTO_BRIDGE;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200570 if (par.match->destroy != NULL)
571 par.match->destroy(&par);
572 module_put(par.match->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 return 0;
574}
575
576static inline int
577ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
578{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200579 struct xt_tgdtor_param par;
580
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 if (i && (*i)-- == 0)
582 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583
Jan Engelhardta2df1642008-10-08 11:35:19 +0200584 par.target = w->u.watcher;
585 par.targinfo = w->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200586 par.family = NFPROTO_BRIDGE;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200587 if (par.target->destroy != NULL)
588 par.target->destroy(&par);
589 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 return 0;
591}
592
593static inline int
594ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
595{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200596 struct xt_tgdtor_param par;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 struct ebt_entry_target *t;
598
Al Viro40642f92006-11-30 19:24:12 -0800599 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 return 0;
601 /* we're done */
602 if (cnt && (*cnt)-- == 0)
603 return 1;
604 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
605 EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL);
606 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
Jan Engelhardta2df1642008-10-08 11:35:19 +0200608 par.target = t->u.target;
609 par.targinfo = t->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200610 par.family = NFPROTO_BRIDGE;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200611 if (par.target->destroy != NULL)
612 par.target->destroy(&par);
613 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 return 0;
615}
616
617static inline int
618ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Virof7da79d2006-11-30 19:27:48 -0800619 const char *name, unsigned int *cnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
621{
622 struct ebt_entry_target *t;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200623 struct xt_target *target;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 unsigned int i, j, hook = 0, hookmask = 0;
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800625 size_t gap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 int ret;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200627 struct xt_mtchk_param mtpar;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200628 struct xt_tgchk_param tgpar;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
630 /* don't mess with the struct ebt_entries */
Al Viro40642f92006-11-30 19:24:12 -0800631 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 return 0;
633
634 if (e->bitmask & ~EBT_F_MASK) {
635 BUGPRINT("Unknown flag for bitmask\n");
636 return -EINVAL;
637 }
638 if (e->invflags & ~EBT_INV_MASK) {
639 BUGPRINT("Unknown flag for inv bitmask\n");
640 return -EINVAL;
641 }
642 if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
643 BUGPRINT("NOPROTO & 802_3 not allowed\n");
644 return -EINVAL;
645 }
646 /* what hook do we belong to? */
647 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Virof7da79d2006-11-30 19:27:48 -0800648 if (!newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 continue;
650 if ((char *)newinfo->hook_entry[i] < (char *)e)
651 hook = i;
652 else
653 break;
654 }
655 /* (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
656 a base chain */
657 if (i < NF_BR_NUMHOOKS)
658 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
659 else {
660 for (i = 0; i < udc_cnt; i++)
661 if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
662 break;
663 if (i == 0)
664 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
665 else
666 hookmask = cl_s[i - 1].hookmask;
667 }
668 i = 0;
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200669
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200670 mtpar.table = tgpar.table = name;
671 mtpar.entryinfo = tgpar.entryinfo = e;
672 mtpar.hook_mask = tgpar.hook_mask = hookmask;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200673 mtpar.family = tgpar.family = NFPROTO_BRIDGE;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200674 ret = EBT_MATCH_ITERATE(e, ebt_check_match, &mtpar, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 if (ret != 0)
676 goto cleanup_matches;
677 j = 0;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200678 ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, &tgpar, &j);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 if (ret != 0)
680 goto cleanup_watchers;
681 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800682 gap = e->next_offset - e->target_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
Jan Engelhardt043ef462008-10-08 11:35:15 +0200684 target = try_then_request_module(
685 xt_find_target(NFPROTO_BRIDGE, t->u.name, 0),
686 "ebt_%s", t->u.name);
687 if (IS_ERR(target)) {
688 ret = PTR_ERR(target);
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200689 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200690 } else if (target == NULL) {
691 ret = -ENOENT;
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200692 goto cleanup_watchers;
693 }
694
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 t->u.target = target;
696 if (t->u.target == &ebt_standard_target) {
Al Viro14197d52006-11-30 19:25:21 -0800697 if (gap < sizeof(struct ebt_standard_target)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 BUGPRINT("Standard target size too big\n");
699 ret = -EFAULT;
700 goto cleanup_watchers;
701 }
702 if (((struct ebt_standard_target *)t)->verdict <
703 -NUM_STANDARD_TARGETS) {
704 BUGPRINT("Invalid standard target\n");
705 ret = -EFAULT;
706 goto cleanup_watchers;
707 }
Jan Engelhardt18219d32008-10-08 11:35:13 +0200708 } else if (t->target_size > gap - sizeof(struct ebt_entry_target)) {
709 module_put(t->u.target->me);
710 ret = -EFAULT;
711 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200712 }
713
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200714 tgpar.target = target;
715 tgpar.targinfo = t->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200716 ret = xt_check_target(&tgpar, t->target_size,
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200717 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200718 if (ret < 0) {
719 module_put(target->me);
Jan Engelhardt18219d32008-10-08 11:35:13 +0200720 goto cleanup_watchers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 }
722 (*cnt)++;
723 return 0;
724cleanup_watchers:
725 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);
726cleanup_matches:
727 EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i);
728 return ret;
729}
730
731/*
732 * checks for loops and sets the hook mask for udc
733 * the hook mask for udc tells us from which base chains the udc can be
734 * accessed. This mask is a parameter to the check() functions of the extensions
735 */
736static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
737 unsigned int udc_cnt, unsigned int hooknr, char *base)
738{
739 int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
740 struct ebt_entry *e = (struct ebt_entry *)chain->data;
741 struct ebt_entry_target *t;
742
743 while (pos < nentries || chain_nr != -1) {
744 /* end of udc, go back one 'recursion' step */
745 if (pos == nentries) {
746 /* put back values of the time when this chain was called */
747 e = cl_s[chain_nr].cs.e;
748 if (cl_s[chain_nr].from != -1)
749 nentries =
750 cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
751 else
752 nentries = chain->nentries;
753 pos = cl_s[chain_nr].cs.n;
754 /* make sure we won't see a loop that isn't one */
755 cl_s[chain_nr].cs.n = 0;
756 chain_nr = cl_s[chain_nr].from;
757 if (pos == nentries)
758 continue;
759 }
760 t = (struct ebt_entry_target *)
761 (((char *)e) + e->target_offset);
762 if (strcmp(t->u.name, EBT_STANDARD_TARGET))
763 goto letscontinue;
764 if (e->target_offset + sizeof(struct ebt_standard_target) >
765 e->next_offset) {
766 BUGPRINT("Standard target size too big\n");
767 return -1;
768 }
769 verdict = ((struct ebt_standard_target *)t)->verdict;
770 if (verdict >= 0) { /* jump to another chain */
771 struct ebt_entries *hlp2 =
772 (struct ebt_entries *)(base + verdict);
773 for (i = 0; i < udc_cnt; i++)
774 if (hlp2 == cl_s[i].cs.chaininfo)
775 break;
776 /* bad destination or loop */
777 if (i == udc_cnt) {
778 BUGPRINT("bad destination\n");
779 return -1;
780 }
781 if (cl_s[i].cs.n) {
782 BUGPRINT("loop\n");
783 return -1;
784 }
Al Viro98a08242006-11-30 19:24:49 -0800785 if (cl_s[i].hookmask & (1 << hooknr))
786 goto letscontinue;
787 /* this can't be 0, so the loop test is correct */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 cl_s[i].cs.n = pos + 1;
789 pos = 0;
790 cl_s[i].cs.e = ((void *)e + e->next_offset);
791 e = (struct ebt_entry *)(hlp2->data);
792 nentries = hlp2->nentries;
793 cl_s[i].from = chain_nr;
794 chain_nr = i;
795 /* this udc is accessible from the base chain for hooknr */
796 cl_s[i].hookmask |= (1 << hooknr);
797 continue;
798 }
799letscontinue:
800 e = (void *)e + e->next_offset;
801 pos++;
802 }
803 return 0;
804}
805
806/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
Al Viro1bc23262006-11-30 19:28:08 -0800807static int translate_table(char *name, struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808{
809 unsigned int i, j, k, udc_cnt;
810 int ret;
811 struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
812
813 i = 0;
Al Viro1f072c92006-11-30 19:26:53 -0800814 while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 i++;
816 if (i == NF_BR_NUMHOOKS) {
817 BUGPRINT("No valid hooks specified\n");
818 return -EINVAL;
819 }
Al Viro1f072c92006-11-30 19:26:53 -0800820 if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 BUGPRINT("Chains don't start at beginning\n");
822 return -EINVAL;
823 }
824 /* make sure chains are ordered after each other in same order
825 as their corresponding hooks */
826 for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
Al Viro1f072c92006-11-30 19:26:53 -0800827 if (!newinfo->hook_entry[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 continue;
Al Viro1f072c92006-11-30 19:26:53 -0800829 if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 BUGPRINT("Hook order must be followed\n");
831 return -EINVAL;
832 }
833 i = j;
834 }
835
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 /* do some early checkings and initialize some things */
837 i = 0; /* holds the expected nr. of entries for the chain */
838 j = 0; /* holds the up to now counted entries for the chain */
839 k = 0; /* holds the total nr. of entries, should equal
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900840 newinfo->nentries afterwards */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
842 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro0e795532006-11-30 19:27:13 -0800843 ebt_check_entry_size_and_hooks, newinfo,
844 &i, &j, &k, &udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
846 if (ret != 0)
847 return ret;
848
849 if (i != j) {
850 BUGPRINT("nentries does not equal the nr of entries in the "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900851 "(last) chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 return -EINVAL;
853 }
854 if (k != newinfo->nentries) {
855 BUGPRINT("Total nentries is wrong\n");
856 return -EINVAL;
857 }
858
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 /* get the location of the udc, put them in an array
860 while we're at it, allocate the chainstack */
861 if (udc_cnt) {
862 /* this will get free'd in do_replace()/ebt_register_table()
863 if an error occurs */
Jayachandran C7ad4d2f2006-04-11 17:25:38 -0700864 newinfo->chainstack =
Christoph Lameter53b8a312007-02-20 13:57:51 -0800865 vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 if (!newinfo->chainstack)
867 return -ENOMEM;
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700868 for_each_possible_cpu(i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 newinfo->chainstack[i] =
Jayachandran C18bc89a2006-04-20 00:14:49 -0700870 vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 if (!newinfo->chainstack[i]) {
872 while (i)
873 vfree(newinfo->chainstack[--i]);
874 vfree(newinfo->chainstack);
875 newinfo->chainstack = NULL;
876 return -ENOMEM;
877 }
878 }
879
Jayachandran C18bc89a2006-04-20 00:14:49 -0700880 cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 if (!cl_s)
882 return -ENOMEM;
883 i = 0; /* the i'th udc */
884 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro177abc32006-11-30 19:27:32 -0800885 ebt_get_udc_positions, newinfo, &i, cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 /* sanity check */
887 if (i != udc_cnt) {
888 BUGPRINT("i != udc_cnt\n");
889 vfree(cl_s);
890 return -EFAULT;
891 }
892 }
893
894 /* Check for loops */
895 for (i = 0; i < NF_BR_NUMHOOKS; i++)
Al Viro1f072c92006-11-30 19:26:53 -0800896 if (newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 if (check_chainloops(newinfo->hook_entry[i],
898 cl_s, udc_cnt, i, newinfo->entries)) {
James Lamanna68d31872005-06-22 22:12:57 -0700899 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 return -EINVAL;
901 }
902
Jan Engelhardt96de0e22007-10-19 23:21:04 +0200903 /* we now know the following (along with E=mc²):
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 - the nr of entries in each chain is right
905 - the size of the allocated space is right
906 - all valid hooks have a corresponding chain
907 - there are no loops
908 - wrong data can still be on the level of a single entry
909 - could be there are jumps to places that are not the
910 beginning of a chain. This can only occur in chains that
911 are not accessible from any base chains, so we don't care. */
912
913 /* used to know what we need to clean up if something goes wrong */
914 i = 0;
915 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro1bc23262006-11-30 19:28:08 -0800916 ebt_check_entry, newinfo, name, &i, cl_s, udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 if (ret != 0) {
918 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
919 ebt_cleanup_entry, &i);
920 }
James Lamanna68d31872005-06-22 22:12:57 -0700921 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 return ret;
923}
924
925/* called under write_lock */
926static void get_counters(struct ebt_counter *oldcounters,
927 struct ebt_counter *counters, unsigned int nentries)
928{
929 int i, cpu;
930 struct ebt_counter *counter_base;
931
932 /* counters of cpu 0 */
933 memcpy(counters, oldcounters,
David S. Millerc8923c62005-10-13 14:41:23 -0700934 sizeof(struct ebt_counter) * nentries);
935
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 /* add other counters to those of cpu 0 */
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700937 for_each_possible_cpu(cpu) {
David S. Millerc8923c62005-10-13 14:41:23 -0700938 if (cpu == 0)
939 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
941 for (i = 0; i < nentries; i++) {
942 counters[i].pcnt += counter_base[i].pcnt;
943 counters[i].bcnt += counter_base[i].bcnt;
944 }
945 }
946}
947
948/* replace the table */
Alexey Dobriyan511061e2008-11-04 14:22:55 +0100949static int do_replace(struct net *net, void __user *user, unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950{
951 int ret, i, countersize;
952 struct ebt_table_info *newinfo;
953 struct ebt_replace tmp;
954 struct ebt_table *t;
955 struct ebt_counter *counterstmp = NULL;
956 /* used to be able to unlock earlier */
957 struct ebt_table_info *table;
958
959 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
960 return -EFAULT;
961
962 if (len != sizeof(tmp) + tmp.entries_size) {
963 BUGPRINT("Wrong len argument\n");
964 return -EINVAL;
965 }
966
967 if (tmp.entries_size == 0) {
968 BUGPRINT("Entries_size never zero\n");
969 return -EINVAL;
970 }
Kirill Korotaevee4bb812006-02-04 02:16:56 -0800971 /* overflow check */
972 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
973 SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
974 return -ENOMEM;
975 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
976 return -ENOMEM;
977
Christoph Lameter53b8a312007-02-20 13:57:51 -0800978 countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -0700979 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 if (!newinfo)
981 return -ENOMEM;
982
983 if (countersize)
984 memset(newinfo->counters, 0, countersize);
985
Kris Katterjohn8b3a7002006-01-11 15:56:43 -0800986 newinfo->entries = vmalloc(tmp.entries_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 if (!newinfo->entries) {
988 ret = -ENOMEM;
989 goto free_newinfo;
990 }
991 if (copy_from_user(
992 newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
993 BUGPRINT("Couldn't copy entries from userspace\n");
994 ret = -EFAULT;
995 goto free_entries;
996 }
997
998 /* the user wants counters back
999 the check on the size is done later, when we have the lock */
1000 if (tmp.num_counters) {
Jayachandran C18bc89a2006-04-20 00:14:49 -07001001 counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 if (!counterstmp) {
1003 ret = -ENOMEM;
1004 goto free_entries;
1005 }
1006 }
1007 else
1008 counterstmp = NULL;
1009
1010 /* this can get initialized by translate_table() */
1011 newinfo->chainstack = NULL;
Al Viro1bc23262006-11-30 19:28:08 -08001012 ret = ebt_verify_pointers(&tmp, newinfo);
1013 if (ret != 0)
1014 goto free_counterstmp;
1015
1016 ret = translate_table(tmp.name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
1018 if (ret != 0)
1019 goto free_counterstmp;
1020
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001021 t = find_table_lock(net, tmp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 if (!t) {
1023 ret = -ENOENT;
1024 goto free_iterate;
1025 }
1026
1027 /* the table doesn't like it */
1028 if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
1029 goto free_unlock;
1030
1031 if (tmp.num_counters && tmp.num_counters != t->private->nentries) {
1032 BUGPRINT("Wrong nr. of counters requested\n");
1033 ret = -EINVAL;
1034 goto free_unlock;
1035 }
1036
1037 /* we have the mutex lock, so no danger in reading this pointer */
1038 table = t->private;
1039 /* make sure the table can only be rmmod'ed if it contains no rules */
1040 if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) {
1041 ret = -ENOENT;
1042 goto free_unlock;
1043 } else if (table->nentries && !newinfo->nentries)
1044 module_put(t->me);
1045 /* we need an atomic snapshot of the counters */
1046 write_lock_bh(&t->lock);
1047 if (tmp.num_counters)
1048 get_counters(t->private->counters, counterstmp,
1049 t->private->nentries);
1050
1051 t->private = newinfo;
1052 write_unlock_bh(&t->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001053 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 /* so, a user can change the chains while having messed up her counter
1055 allocation. Only reason why this is done is because this way the lock
1056 is held only once, while this doesn't bring the kernel into a
1057 dangerous state. */
1058 if (tmp.num_counters &&
1059 copy_to_user(tmp.counters, counterstmp,
1060 tmp.num_counters * sizeof(struct ebt_counter))) {
1061 BUGPRINT("Couldn't copy counters to userspace\n");
1062 ret = -EFAULT;
1063 }
1064 else
1065 ret = 0;
1066
1067 /* decrease module count and free resources */
1068 EBT_ENTRY_ITERATE(table->entries, table->entries_size,
1069 ebt_cleanup_entry, NULL);
1070
1071 vfree(table->entries);
1072 if (table->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001073 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 vfree(table->chainstack[i]);
1075 vfree(table->chainstack);
1076 }
1077 vfree(table);
1078
James Lamanna68d31872005-06-22 22:12:57 -07001079 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 return ret;
1081
1082free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001083 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084free_iterate:
1085 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
1086 ebt_cleanup_entry, NULL);
1087free_counterstmp:
James Lamanna68d31872005-06-22 22:12:57 -07001088 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 /* can be initialized in translate_table() */
1090 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001091 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 vfree(newinfo->chainstack[i]);
1093 vfree(newinfo->chainstack);
1094 }
1095free_entries:
James Lamanna68d31872005-06-22 22:12:57 -07001096 vfree(newinfo->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097free_newinfo:
James Lamanna68d31872005-06-22 22:12:57 -07001098 vfree(newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 return ret;
1100}
1101
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001102struct ebt_table *ebt_register_table(struct net *net, struct ebt_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103{
1104 struct ebt_table_info *newinfo;
Patrick McHardydf0933d2006-09-20 11:57:53 -07001105 struct ebt_table *t;
Al Viro1e419cd2006-11-30 19:28:48 -08001106 struct ebt_replace_kernel *repl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 int ret, i, countersize;
Al Virodf07a812006-11-30 19:28:25 -08001108 void *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109
Al Virodf07a812006-11-30 19:28:25 -08001110 if (!table || !(repl = table->table) || !repl->entries ||
1111 repl->entries_size == 0 ||
1112 repl->counters || table->private) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 BUGPRINT("Bad table data for ebt_register_table!!!\n");
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001114 return ERR_PTR(-EINVAL);
1115 }
1116
1117 /* Don't add one table to multiple lists. */
1118 table = kmemdup(table, sizeof(struct ebt_table), GFP_KERNEL);
1119 if (!table) {
1120 ret = -ENOMEM;
1121 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 }
1123
Christoph Lameter53b8a312007-02-20 13:57:51 -08001124 countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -07001125 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 ret = -ENOMEM;
1127 if (!newinfo)
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001128 goto free_table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
Al Virodf07a812006-11-30 19:28:25 -08001130 p = vmalloc(repl->entries_size);
1131 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 goto free_newinfo;
1133
Al Virodf07a812006-11-30 19:28:25 -08001134 memcpy(p, repl->entries, repl->entries_size);
1135 newinfo->entries = p;
1136
1137 newinfo->entries_size = repl->entries_size;
1138 newinfo->nentries = repl->nentries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139
1140 if (countersize)
1141 memset(newinfo->counters, 0, countersize);
1142
1143 /* fill in newinfo and parse the entries */
1144 newinfo->chainstack = NULL;
Al Virodf07a812006-11-30 19:28:25 -08001145 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1146 if ((repl->valid_hooks & (1 << i)) == 0)
1147 newinfo->hook_entry[i] = NULL;
1148 else
1149 newinfo->hook_entry[i] = p +
1150 ((char *)repl->hook_entry[i] - repl->entries);
1151 }
1152 ret = translate_table(repl->name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 if (ret != 0) {
1154 BUGPRINT("Translate_table failed\n");
1155 goto free_chainstack;
1156 }
1157
1158 if (table->check && table->check(newinfo, table->valid_hooks)) {
1159 BUGPRINT("The table doesn't like its own initial data, lol\n");
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001160 return ERR_PTR(-EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 }
1162
1163 table->private = newinfo;
1164 rwlock_init(&table->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001165 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 if (ret != 0)
1167 goto free_chainstack;
1168
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001169 list_for_each_entry(t, &net->xt.tables[NFPROTO_BRIDGE], list) {
Patrick McHardydf0933d2006-09-20 11:57:53 -07001170 if (strcmp(t->name, table->name) == 0) {
1171 ret = -EEXIST;
1172 BUGPRINT("Table name already exists\n");
1173 goto free_unlock;
1174 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 }
1176
1177 /* Hold a reference count if the chains aren't empty */
1178 if (newinfo->nentries && !try_module_get(table->me)) {
1179 ret = -ENOENT;
1180 goto free_unlock;
1181 }
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001182 list_add(&table->list, &net->xt.tables[NFPROTO_BRIDGE]);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001183 mutex_unlock(&ebt_mutex);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001184 return table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001186 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187free_chainstack:
1188 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001189 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 vfree(newinfo->chainstack[i]);
1191 vfree(newinfo->chainstack);
1192 }
1193 vfree(newinfo->entries);
1194free_newinfo:
1195 vfree(newinfo);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001196free_table:
1197 kfree(table);
1198out:
1199 return ERR_PTR(ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200}
1201
1202void ebt_unregister_table(struct ebt_table *table)
1203{
1204 int i;
1205
1206 if (!table) {
1207 BUGPRINT("Request to unregister NULL table!!!\n");
1208 return;
1209 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001210 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001211 list_del(&table->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001212 mutex_unlock(&ebt_mutex);
Alexey Dobriyandbcdf852008-11-04 14:28:04 +01001213 EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size,
1214 ebt_cleanup_entry, NULL);
1215 if (table->private->nentries)
1216 module_put(table->me);
James Lamanna68d31872005-06-22 22:12:57 -07001217 vfree(table->private->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 if (table->private->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001219 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 vfree(table->private->chainstack[i]);
1221 vfree(table->private->chainstack);
1222 }
1223 vfree(table->private);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001224 kfree(table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225}
1226
1227/* userspace just supplied us with counters */
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001228static int update_counters(struct net *net, void __user *user, unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229{
1230 int i, ret;
1231 struct ebt_counter *tmp;
1232 struct ebt_replace hlp;
1233 struct ebt_table *t;
1234
1235 if (copy_from_user(&hlp, user, sizeof(hlp)))
1236 return -EFAULT;
1237
1238 if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
1239 return -EINVAL;
1240 if (hlp.num_counters == 0)
1241 return -EINVAL;
1242
Jayachandran C18bc89a2006-04-20 00:14:49 -07001243 if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 MEMPRINT("Update_counters && nomemory\n");
1245 return -ENOMEM;
1246 }
1247
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001248 t = find_table_lock(net, hlp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 if (!t)
1250 goto free_tmp;
1251
1252 if (hlp.num_counters != t->private->nentries) {
1253 BUGPRINT("Wrong nr of counters\n");
1254 ret = -EINVAL;
1255 goto unlock_mutex;
1256 }
1257
1258 if ( copy_from_user(tmp, hlp.counters,
1259 hlp.num_counters * sizeof(struct ebt_counter)) ) {
1260 BUGPRINT("Updata_counters && !cfu\n");
1261 ret = -EFAULT;
1262 goto unlock_mutex;
1263 }
1264
1265 /* we want an atomic add of the counters */
1266 write_lock_bh(&t->lock);
1267
1268 /* we add to the counters of the first cpu */
1269 for (i = 0; i < hlp.num_counters; i++) {
1270 t->private->counters[i].pcnt += tmp[i].pcnt;
1271 t->private->counters[i].bcnt += tmp[i].bcnt;
1272 }
1273
1274 write_unlock_bh(&t->lock);
1275 ret = 0;
1276unlock_mutex:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001277 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278free_tmp:
1279 vfree(tmp);
1280 return ret;
1281}
1282
1283static inline int ebt_make_matchname(struct ebt_entry_match *m,
Al Viro1e419cd2006-11-30 19:28:48 -08001284 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285{
Al Viro1e419cd2006-11-30 19:28:48 -08001286 char __user *hlp = ubase + ((char *)m - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
1288 return -EFAULT;
1289 return 0;
1290}
1291
1292static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
Al Viro1e419cd2006-11-30 19:28:48 -08001293 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294{
Al Viro1e419cd2006-11-30 19:28:48 -08001295 char __user *hlp = ubase + ((char *)w - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
1297 return -EFAULT;
1298 return 0;
1299}
1300
Al Viro1e419cd2006-11-30 19:28:48 -08001301static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302{
1303 int ret;
Al Viro1e419cd2006-11-30 19:28:48 -08001304 char __user *hlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 struct ebt_entry_target *t;
1306
Al Viro40642f92006-11-30 19:24:12 -08001307 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 return 0;
1309
Al Viro1e419cd2006-11-30 19:28:48 -08001310 hlp = ubase + (((char *)e + e->target_offset) - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +09001312
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
1314 if (ret != 0)
1315 return ret;
1316 ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
1317 if (ret != 0)
1318 return ret;
1319 if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
1320 return -EFAULT;
1321 return 0;
1322}
1323
Ingo Molnar57b47a52006-03-20 22:35:41 -08001324/* called with ebt_mutex locked */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325static int copy_everything_to_user(struct ebt_table *t, void __user *user,
1326 int *len, int cmd)
1327{
1328 struct ebt_replace tmp;
1329 struct ebt_counter *counterstmp, *oldcounters;
1330 unsigned int entries_size, nentries;
1331 char *entries;
1332
1333 if (cmd == EBT_SO_GET_ENTRIES) {
1334 entries_size = t->private->entries_size;
1335 nentries = t->private->nentries;
1336 entries = t->private->entries;
1337 oldcounters = t->private->counters;
1338 } else {
1339 entries_size = t->table->entries_size;
1340 nentries = t->table->nentries;
1341 entries = t->table->entries;
1342 oldcounters = t->table->counters;
1343 }
1344
1345 if (copy_from_user(&tmp, user, sizeof(tmp))) {
1346 BUGPRINT("Cfu didn't work\n");
1347 return -EFAULT;
1348 }
1349
1350 if (*len != sizeof(struct ebt_replace) + entries_size +
1351 (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
1352 BUGPRINT("Wrong size\n");
1353 return -EINVAL;
1354 }
1355
1356 if (tmp.nentries != nentries) {
1357 BUGPRINT("Nentries wrong\n");
1358 return -EINVAL;
1359 }
1360
1361 if (tmp.entries_size != entries_size) {
1362 BUGPRINT("Wrong size\n");
1363 return -EINVAL;
1364 }
1365
1366 /* userspace might not need the counters */
1367 if (tmp.num_counters) {
1368 if (tmp.num_counters != nentries) {
1369 BUGPRINT("Num_counters wrong\n");
1370 return -EINVAL;
1371 }
Jayachandran C18bc89a2006-04-20 00:14:49 -07001372 counterstmp = vmalloc(nentries * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 if (!counterstmp) {
1374 MEMPRINT("Couldn't copy counters, out of memory\n");
1375 return -ENOMEM;
1376 }
1377 write_lock_bh(&t->lock);
1378 get_counters(oldcounters, counterstmp, nentries);
1379 write_unlock_bh(&t->lock);
1380
1381 if (copy_to_user(tmp.counters, counterstmp,
1382 nentries * sizeof(struct ebt_counter))) {
1383 BUGPRINT("Couldn't copy counters to userspace\n");
1384 vfree(counterstmp);
1385 return -EFAULT;
1386 }
1387 vfree(counterstmp);
1388 }
1389
1390 if (copy_to_user(tmp.entries, entries, entries_size)) {
1391 BUGPRINT("Couldn't copy entries to userspace\n");
1392 return -EFAULT;
1393 }
1394 /* set the match/watcher/target names right */
1395 return EBT_ENTRY_ITERATE(entries, entries_size,
1396 ebt_make_names, entries, tmp.entries);
1397}
1398
1399static int do_ebt_set_ctl(struct sock *sk,
1400 int cmd, void __user *user, unsigned int len)
1401{
1402 int ret;
1403
1404 switch(cmd) {
1405 case EBT_SO_SET_ENTRIES:
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001406 ret = do_replace(sock_net(sk), user, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 break;
1408 case EBT_SO_SET_COUNTERS:
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001409 ret = update_counters(sock_net(sk), user, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 break;
1411 default:
1412 ret = -EINVAL;
1413 }
1414 return ret;
1415}
1416
1417static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1418{
1419 int ret;
1420 struct ebt_replace tmp;
1421 struct ebt_table *t;
1422
1423 if (copy_from_user(&tmp, user, sizeof(tmp)))
1424 return -EFAULT;
1425
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001426 t = find_table_lock(sock_net(sk), tmp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 if (!t)
1428 return ret;
1429
1430 switch(cmd) {
1431 case EBT_SO_GET_INFO:
1432 case EBT_SO_GET_INIT_INFO:
1433 if (*len != sizeof(struct ebt_replace)){
1434 ret = -EINVAL;
Ingo Molnar57b47a52006-03-20 22:35:41 -08001435 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 break;
1437 }
1438 if (cmd == EBT_SO_GET_INFO) {
1439 tmp.nentries = t->private->nentries;
1440 tmp.entries_size = t->private->entries_size;
1441 tmp.valid_hooks = t->valid_hooks;
1442 } else {
1443 tmp.nentries = t->table->nentries;
1444 tmp.entries_size = t->table->entries_size;
1445 tmp.valid_hooks = t->table->valid_hooks;
1446 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001447 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 if (copy_to_user(user, &tmp, *len) != 0){
1449 BUGPRINT("c2u Didn't work\n");
1450 ret = -EFAULT;
1451 break;
1452 }
1453 ret = 0;
1454 break;
1455
1456 case EBT_SO_GET_ENTRIES:
1457 case EBT_SO_GET_INIT_ENTRIES:
1458 ret = copy_everything_to_user(t, user, len, cmd);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001459 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 break;
1461
1462 default:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001463 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 ret = -EINVAL;
1465 }
1466
1467 return ret;
1468}
1469
1470static struct nf_sockopt_ops ebt_sockopts =
Andrew Morton74ca4e5a2006-03-20 22:55:02 -08001471{
1472 .pf = PF_INET,
1473 .set_optmin = EBT_BASE_CTL,
1474 .set_optmax = EBT_SO_SET_MAX + 1,
1475 .set = do_ebt_set_ctl,
1476 .get_optmin = EBT_BASE_CTL,
1477 .get_optmax = EBT_SO_GET_MAX + 1,
1478 .get = do_ebt_get_ctl,
Neil Horman16fcec32007-09-11 11:28:26 +02001479 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480};
1481
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001482static int __init ebtables_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483{
1484 int ret;
1485
Jan Engelhardt043ef462008-10-08 11:35:15 +02001486 ret = xt_register_target(&ebt_standard_target);
1487 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 return ret;
Jan Engelhardt043ef462008-10-08 11:35:15 +02001489 ret = nf_register_sockopt(&ebt_sockopts);
1490 if (ret < 0) {
1491 xt_unregister_target(&ebt_standard_target);
1492 return ret;
1493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494
Patrick McHardya887c1c2007-07-14 20:46:15 -07001495 printk(KERN_INFO "Ebtables v2.0 registered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 return 0;
1497}
1498
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001499static void __exit ebtables_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500{
1501 nf_unregister_sockopt(&ebt_sockopts);
Jan Engelhardt043ef462008-10-08 11:35:15 +02001502 xt_unregister_target(&ebt_standard_target);
Patrick McHardya887c1c2007-07-14 20:46:15 -07001503 printk(KERN_INFO "Ebtables v2.0 unregistered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504}
1505
1506EXPORT_SYMBOL(ebt_register_table);
1507EXPORT_SYMBOL(ebt_unregister_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508EXPORT_SYMBOL(ebt_do_table);
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001509module_init(ebtables_init);
1510module_exit(ebtables_fini);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511MODULE_LICENSE("GPL");