blob: 12beb580aa21851dd1dd071e1ab100cfa8b93ba1 [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
Jan Engelhardt98e86402009-04-15 21:06:05 +0200145static inline __pure
146struct ebt_entry *ebt_next_entry(const struct ebt_entry *entry)
147{
148 return (void *)entry + entry->next_offset;
149}
150
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151/* Do some firewalling */
Herbert Xu3db05fe2007-10-15 00:53:15 -0700152unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 const struct net_device *in, const struct net_device *out,
154 struct ebt_table *table)
155{
156 int i, nentries;
157 struct ebt_entry *point;
158 struct ebt_counter *counter_base, *cb_base;
159 struct ebt_entry_target *t;
160 int verdict, sp = 0;
161 struct ebt_chainstack *cs;
162 struct ebt_entries *chaininfo;
163 char *base;
164 struct ebt_table_info *private;
Jan Engelhardt5365f802008-10-08 11:35:16 +0200165 bool hotdrop = false;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200166 struct xt_match_param mtpar;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200167 struct xt_target_param tgpar;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200168
Jan Engelhardt916a9172008-10-08 11:35:20 +0200169 mtpar.family = tgpar.family = NFPROTO_BRIDGE;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200170 mtpar.in = tgpar.in = in;
171 mtpar.out = tgpar.out = out;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200172 mtpar.hotdrop = &hotdrop;
Evgeniy Polyakova5e78822009-06-04 16:54:42 +0200173 mtpar.hooknum = tgpar.hooknum = hook;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174
175 read_lock_bh(&table->lock);
176 private = table->private;
177 cb_base = COUNTER_BASE(private->counters, private->nentries,
178 smp_processor_id());
179 if (private->chainstack)
180 cs = private->chainstack[smp_processor_id()];
181 else
182 cs = NULL;
183 chaininfo = private->hook_entry[hook];
184 nentries = private->hook_entry[hook]->nentries;
185 point = (struct ebt_entry *)(private->hook_entry[hook]->data);
186 counter_base = cb_base + private->hook_entry[hook]->counter_offset;
187 /* base for chain jumps */
188 base = private->entries;
189 i = 0;
190 while (i < nentries) {
Herbert Xu3db05fe2007-10-15 00:53:15 -0700191 if (ebt_basic_match(point, eth_hdr(skb), in, out))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 goto letscontinue;
193
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200194 if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, &mtpar) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 goto letscontinue;
Jan Engelhardt5365f802008-10-08 11:35:16 +0200196 if (hotdrop) {
197 read_unlock_bh(&table->lock);
198 return NF_DROP;
199 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
201 /* increase counter */
202 (*(counter_base + i)).pcnt++;
Herbert Xu3db05fe2007-10-15 00:53:15 -0700203 (*(counter_base + i)).bcnt += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
205 /* these should only watch: not modify, nor tell us
206 what to do with the packet */
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200207 EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, &tgpar);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
209 t = (struct ebt_entry_target *)
210 (((char *)point) + point->target_offset);
211 /* standard target */
212 if (!t->u.target->target)
213 verdict = ((struct ebt_standard_target *)t)->verdict;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200214 else {
215 tgpar.target = t->u.target;
216 tgpar.targinfo = t->data;
217 verdict = t->u.target->target(skb, &tgpar);
218 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 if (verdict == EBT_ACCEPT) {
220 read_unlock_bh(&table->lock);
221 return NF_ACCEPT;
222 }
223 if (verdict == EBT_DROP) {
224 read_unlock_bh(&table->lock);
225 return NF_DROP;
226 }
227 if (verdict == EBT_RETURN) {
228letsreturn:
229#ifdef CONFIG_NETFILTER_DEBUG
230 if (sp == 0) {
231 BUGPRINT("RETURN on base chain");
232 /* act like this is EBT_CONTINUE */
233 goto letscontinue;
234 }
235#endif
236 sp--;
237 /* put all the local variables right */
238 i = cs[sp].n;
239 chaininfo = cs[sp].chaininfo;
240 nentries = chaininfo->nentries;
241 point = cs[sp].e;
242 counter_base = cb_base +
243 chaininfo->counter_offset;
244 continue;
245 }
246 if (verdict == EBT_CONTINUE)
247 goto letscontinue;
248#ifdef CONFIG_NETFILTER_DEBUG
249 if (verdict < 0) {
250 BUGPRINT("bogus standard verdict\n");
251 read_unlock_bh(&table->lock);
252 return NF_DROP;
253 }
254#endif
255 /* jump to a udc */
256 cs[sp].n = i + 1;
257 cs[sp].chaininfo = chaininfo;
Jan Engelhardt98e86402009-04-15 21:06:05 +0200258 cs[sp].e = ebt_next_entry(point);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 i = 0;
260 chaininfo = (struct ebt_entries *) (base + verdict);
261#ifdef CONFIG_NETFILTER_DEBUG
262 if (chaininfo->distinguisher) {
263 BUGPRINT("jump to non-chain\n");
264 read_unlock_bh(&table->lock);
265 return NF_DROP;
266 }
267#endif
268 nentries = chaininfo->nentries;
269 point = (struct ebt_entry *)chaininfo->data;
270 counter_base = cb_base + chaininfo->counter_offset;
271 sp++;
272 continue;
273letscontinue:
Jan Engelhardt98e86402009-04-15 21:06:05 +0200274 point = ebt_next_entry(point);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 i++;
276 }
277
278 /* I actually like this :) */
279 if (chaininfo->policy == EBT_RETURN)
280 goto letsreturn;
281 if (chaininfo->policy == EBT_ACCEPT) {
282 read_unlock_bh(&table->lock);
283 return NF_ACCEPT;
284 }
285 read_unlock_bh(&table->lock);
286 return NF_DROP;
287}
288
289/* If it succeeds, returns element and locks mutex */
290static inline void *
291find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800292 struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293{
Patrick McHardydf0933d2006-09-20 11:57:53 -0700294 struct {
295 struct list_head list;
296 char name[EBT_FUNCTION_MAXNAMELEN];
297 } *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
Ingo Molnar57b47a52006-03-20 22:35:41 -0800299 *error = mutex_lock_interruptible(mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 if (*error != 0)
301 return NULL;
302
Patrick McHardydf0933d2006-09-20 11:57:53 -0700303 list_for_each_entry(e, head, list) {
304 if (strcmp(e->name, name) == 0)
305 return e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 }
Patrick McHardydf0933d2006-09-20 11:57:53 -0700307 *error = -ENOENT;
308 mutex_unlock(mutex);
309 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310}
311
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312static void *
313find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800314 int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315{
Johannes Berg95a5afc2008-10-16 15:24:51 -0700316 return try_then_request_module(
317 find_inlist_lock_noload(head, name, error, mutex),
318 "%s%s", prefix, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
321static inline struct ebt_table *
Alexey Dobriyan511061e2008-11-04 14:22:55 +0100322find_table_lock(struct net *net, const char *name, int *error,
323 struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324{
Alexey Dobriyan511061e2008-11-04 14:22:55 +0100325 return find_inlist_lock(&net->xt.tables[NFPROTO_BRIDGE], name,
326 "ebtable_", error, mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327}
328
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329static inline int
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200330ebt_check_match(struct ebt_entry_match *m, struct xt_mtchk_param *par,
331 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332{
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200333 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200334 struct xt_match *match;
Al Viro14197d52006-11-30 19:25:21 -0800335 size_t left = ((char *)e + e->watchers_offset) - (char *)m;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 int ret;
337
Al Viro14197d52006-11-30 19:25:21 -0800338 if (left < sizeof(struct ebt_entry_match) ||
339 left - sizeof(struct ebt_entry_match) < m->match_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200341
342 match = try_then_request_module(xt_find_match(NFPROTO_BRIDGE,
343 m->u.name, 0), "ebt_%s", m->u.name);
344 if (IS_ERR(match))
345 return PTR_ERR(match);
346 if (match == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200348 m->u.match = match;
349
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200350 par->match = match;
351 par->matchinfo = m->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200352 ret = xt_check_match(par, m->match_size,
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200353 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200354 if (ret < 0) {
355 module_put(match->me);
356 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200358
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 (*cnt)++;
360 return 0;
361}
362
363static inline int
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200364ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
365 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366{
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200367 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200368 struct xt_target *watcher;
Al Viro14197d52006-11-30 19:25:21 -0800369 size_t left = ((char *)e + e->target_offset) - (char *)w;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 int ret;
371
Al Viro14197d52006-11-30 19:25:21 -0800372 if (left < sizeof(struct ebt_entry_watcher) ||
373 left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200375
376 watcher = try_then_request_module(
377 xt_find_target(NFPROTO_BRIDGE, w->u.name, 0),
378 "ebt_%s", w->u.name);
379 if (IS_ERR(watcher))
380 return PTR_ERR(watcher);
381 if (watcher == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200383 w->u.watcher = watcher;
384
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200385 par->target = watcher;
386 par->targinfo = w->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200387 ret = xt_check_target(par, w->watcher_size,
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200388 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200389 if (ret < 0) {
390 module_put(watcher->me);
391 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200393
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 (*cnt)++;
395 return 0;
396}
397
Al Viro70fe9af2006-11-30 19:26:14 -0800398static int ebt_verify_pointers(struct ebt_replace *repl,
399 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400{
Al Viro70fe9af2006-11-30 19:26:14 -0800401 unsigned int limit = repl->entries_size;
402 unsigned int valid_hooks = repl->valid_hooks;
403 unsigned int offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 int i;
405
Al Viroe4fd77d2006-11-30 19:26:35 -0800406 for (i = 0; i < NF_BR_NUMHOOKS; i++)
407 newinfo->hook_entry[i] = NULL;
408
409 newinfo->entries_size = repl->entries_size;
410 newinfo->nentries = repl->nentries;
411
Al Viro70fe9af2006-11-30 19:26:14 -0800412 while (offset < limit) {
413 size_t left = limit - offset;
414 struct ebt_entry *e = (void *)newinfo->entries + offset;
Al Virobb2ef252006-11-30 19:22:42 -0800415
Al Viro70fe9af2006-11-30 19:26:14 -0800416 if (left < sizeof(unsigned int))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 break;
Al Viro22b440b2006-11-30 19:25:51 -0800418
Al Viro70fe9af2006-11-30 19:26:14 -0800419 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
420 if ((valid_hooks & (1 << i)) == 0)
421 continue;
Al Viro1e419cd2006-11-30 19:28:48 -0800422 if ((char __user *)repl->hook_entry[i] ==
423 repl->entries + offset)
Al Viro70fe9af2006-11-30 19:26:14 -0800424 break;
425 }
426
427 if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
428 if (e->bitmask != 0) {
429 /* we make userspace set this right,
430 so there is no misunderstanding */
431 BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
432 "in distinguisher\n");
433 return -EINVAL;
434 }
435 if (i != NF_BR_NUMHOOKS)
436 newinfo->hook_entry[i] = (struct ebt_entries *)e;
437 if (left < sizeof(struct ebt_entries))
438 break;
439 offset += sizeof(struct ebt_entries);
440 } else {
441 if (left < sizeof(struct ebt_entry))
442 break;
443 if (left < e->next_offset)
444 break;
445 offset += e->next_offset;
446 }
447 }
448 if (offset != limit) {
449 BUGPRINT("entries_size too small\n");
450 return -EINVAL;
451 }
Al Viroe4fd77d2006-11-30 19:26:35 -0800452
453 /* check if all valid hooks have a chain */
454 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
455 if (!newinfo->hook_entry[i] &&
456 (valid_hooks & (1 << i))) {
457 BUGPRINT("Valid hook without chain\n");
458 return -EINVAL;
459 }
460 }
Al Viro70fe9af2006-11-30 19:26:14 -0800461 return 0;
Al Viro22b440b2006-11-30 19:25:51 -0800462}
463
464/*
465 * this one is very careful, as it is the first function
466 * to parse the userspace data
467 */
468static inline int
469ebt_check_entry_size_and_hooks(struct ebt_entry *e,
Al Viro0e795532006-11-30 19:27:13 -0800470 struct ebt_table_info *newinfo,
471 unsigned int *n, unsigned int *cnt,
472 unsigned int *totalcnt, unsigned int *udc_cnt)
Al Viro22b440b2006-11-30 19:25:51 -0800473{
Al Viro22b440b2006-11-30 19:25:51 -0800474 int i;
475
476 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Viro0e795532006-11-30 19:27:13 -0800477 if ((void *)e == (void *)newinfo->hook_entry[i])
Al Viro22b440b2006-11-30 19:25:51 -0800478 break;
479 }
480 /* beginning of a new chain
481 if i == NF_BR_NUMHOOKS it must be a user defined chain */
482 if (i != NF_BR_NUMHOOKS || !e->bitmask) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 /* this checks if the previous chain has as many entries
484 as it said it has */
485 if (*n != *cnt) {
486 BUGPRINT("nentries does not equal the nr of entries "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900487 "in the chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 return -EINVAL;
489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 if (((struct ebt_entries *)e)->policy != EBT_DROP &&
491 ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
492 /* only RETURN from udc */
493 if (i != NF_BR_NUMHOOKS ||
494 ((struct ebt_entries *)e)->policy != EBT_RETURN) {
495 BUGPRINT("bad policy\n");
496 return -EINVAL;
497 }
498 }
499 if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
500 (*udc_cnt)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
502 BUGPRINT("counter_offset != totalcnt");
503 return -EINVAL;
504 }
505 *n = ((struct ebt_entries *)e)->nentries;
506 *cnt = 0;
507 return 0;
508 }
509 /* a plain old entry, heh */
510 if (sizeof(struct ebt_entry) > e->watchers_offset ||
511 e->watchers_offset > e->target_offset ||
512 e->target_offset >= e->next_offset) {
513 BUGPRINT("entry offsets not in right order\n");
514 return -EINVAL;
515 }
516 /* this is not checked anywhere else */
517 if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
518 BUGPRINT("target size too small\n");
519 return -EINVAL;
520 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 (*cnt)++;
522 (*totalcnt)++;
523 return 0;
524}
525
526struct ebt_cl_stack
527{
528 struct ebt_chainstack cs;
529 int from;
530 unsigned int hookmask;
531};
532
533/*
534 * we need these positions to check that the jumps to a different part of the
535 * entries is a jump to the beginning of a new chain.
536 */
537static inline int
538ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Viro177abc32006-11-30 19:27:32 -0800539 unsigned int *n, struct ebt_cl_stack *udc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540{
541 int i;
542
543 /* we're only interested in chain starts */
Al Viro40642f92006-11-30 19:24:12 -0800544 if (e->bitmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 return 0;
546 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
548 break;
549 }
550 /* only care about udc */
551 if (i != NF_BR_NUMHOOKS)
552 return 0;
553
554 udc[*n].cs.chaininfo = (struct ebt_entries *)e;
555 /* these initialisations are depended on later in check_chainloops() */
556 udc[*n].cs.n = 0;
557 udc[*n].hookmask = 0;
558
559 (*n)++;
560 return 0;
561}
562
563static inline int
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100564ebt_cleanup_match(struct ebt_entry_match *m, struct net *net, unsigned int *i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565{
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200566 struct xt_mtdtor_param par;
567
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 if (i && (*i)-- == 0)
569 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100571 par.net = net;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200572 par.match = m->u.match;
573 par.matchinfo = m->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200574 par.family = NFPROTO_BRIDGE;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200575 if (par.match->destroy != NULL)
576 par.match->destroy(&par);
577 module_put(par.match->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 return 0;
579}
580
581static inline int
Patrick McHardyadd67462010-02-03 13:45:12 +0100582ebt_cleanup_watcher(struct ebt_entry_watcher *w, struct net *net, unsigned int *i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200584 struct xt_tgdtor_param par;
585
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 if (i && (*i)-- == 0)
587 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
Patrick McHardyadd67462010-02-03 13:45:12 +0100589 par.net = net;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200590 par.target = w->u.watcher;
591 par.targinfo = w->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200592 par.family = NFPROTO_BRIDGE;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200593 if (par.target->destroy != NULL)
594 par.target->destroy(&par);
595 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 return 0;
597}
598
599static inline int
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100600ebt_cleanup_entry(struct ebt_entry *e, struct net *net, unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200602 struct xt_tgdtor_param par;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 struct ebt_entry_target *t;
604
Al Viro40642f92006-11-30 19:24:12 -0800605 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 return 0;
607 /* we're done */
608 if (cnt && (*cnt)-- == 0)
609 return 1;
Patrick McHardyadd67462010-02-03 13:45:12 +0100610 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, net, NULL);
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100611 EBT_MATCH_ITERATE(e, ebt_cleanup_match, net, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613
Patrick McHardyadd67462010-02-03 13:45:12 +0100614 par.net = net;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200615 par.target = t->u.target;
616 par.targinfo = t->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200617 par.family = NFPROTO_BRIDGE;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200618 if (par.target->destroy != NULL)
619 par.target->destroy(&par);
620 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 return 0;
622}
623
624static inline int
Alexey Dobriyana83d8e82010-01-18 08:21:13 +0100625ebt_check_entry(struct ebt_entry *e,
626 struct net *net,
627 struct ebt_table_info *newinfo,
Al Virof7da79d2006-11-30 19:27:48 -0800628 const char *name, unsigned int *cnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
630{
631 struct ebt_entry_target *t;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200632 struct xt_target *target;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 unsigned int i, j, hook = 0, hookmask = 0;
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800634 size_t gap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 int ret;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200636 struct xt_mtchk_param mtpar;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200637 struct xt_tgchk_param tgpar;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
639 /* don't mess with the struct ebt_entries */
Al Viro40642f92006-11-30 19:24:12 -0800640 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 return 0;
642
643 if (e->bitmask & ~EBT_F_MASK) {
644 BUGPRINT("Unknown flag for bitmask\n");
645 return -EINVAL;
646 }
647 if (e->invflags & ~EBT_INV_MASK) {
648 BUGPRINT("Unknown flag for inv bitmask\n");
649 return -EINVAL;
650 }
651 if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
652 BUGPRINT("NOPROTO & 802_3 not allowed\n");
653 return -EINVAL;
654 }
655 /* what hook do we belong to? */
656 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Virof7da79d2006-11-30 19:27:48 -0800657 if (!newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 continue;
659 if ((char *)newinfo->hook_entry[i] < (char *)e)
660 hook = i;
661 else
662 break;
663 }
664 /* (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
665 a base chain */
666 if (i < NF_BR_NUMHOOKS)
667 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
668 else {
669 for (i = 0; i < udc_cnt; i++)
670 if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
671 break;
672 if (i == 0)
673 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
674 else
675 hookmask = cl_s[i - 1].hookmask;
676 }
677 i = 0;
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200678
Patrick McHardyadd67462010-02-03 13:45:12 +0100679 mtpar.net = tgpar.net = net;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200680 mtpar.table = tgpar.table = name;
681 mtpar.entryinfo = tgpar.entryinfo = e;
682 mtpar.hook_mask = tgpar.hook_mask = hookmask;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200683 mtpar.family = tgpar.family = NFPROTO_BRIDGE;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200684 ret = EBT_MATCH_ITERATE(e, ebt_check_match, &mtpar, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 if (ret != 0)
686 goto cleanup_matches;
687 j = 0;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200688 ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, &tgpar, &j);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 if (ret != 0)
690 goto cleanup_watchers;
691 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800692 gap = e->next_offset - e->target_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
Jan Engelhardt043ef462008-10-08 11:35:15 +0200694 target = try_then_request_module(
695 xt_find_target(NFPROTO_BRIDGE, t->u.name, 0),
696 "ebt_%s", t->u.name);
697 if (IS_ERR(target)) {
698 ret = PTR_ERR(target);
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200699 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200700 } else if (target == NULL) {
701 ret = -ENOENT;
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200702 goto cleanup_watchers;
703 }
704
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 t->u.target = target;
706 if (t->u.target == &ebt_standard_target) {
Al Viro14197d52006-11-30 19:25:21 -0800707 if (gap < sizeof(struct ebt_standard_target)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 BUGPRINT("Standard target size too big\n");
709 ret = -EFAULT;
710 goto cleanup_watchers;
711 }
712 if (((struct ebt_standard_target *)t)->verdict <
713 -NUM_STANDARD_TARGETS) {
714 BUGPRINT("Invalid standard target\n");
715 ret = -EFAULT;
716 goto cleanup_watchers;
717 }
Jan Engelhardt18219d32008-10-08 11:35:13 +0200718 } else if (t->target_size > gap - sizeof(struct ebt_entry_target)) {
719 module_put(t->u.target->me);
720 ret = -EFAULT;
721 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200722 }
723
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200724 tgpar.target = target;
725 tgpar.targinfo = t->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200726 ret = xt_check_target(&tgpar, t->target_size,
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200727 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200728 if (ret < 0) {
729 module_put(target->me);
Jan Engelhardt18219d32008-10-08 11:35:13 +0200730 goto cleanup_watchers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 }
732 (*cnt)++;
733 return 0;
734cleanup_watchers:
Patrick McHardyadd67462010-02-03 13:45:12 +0100735 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, net, &j);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736cleanup_matches:
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100737 EBT_MATCH_ITERATE(e, ebt_cleanup_match, net, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 return ret;
739}
740
741/*
742 * checks for loops and sets the hook mask for udc
743 * the hook mask for udc tells us from which base chains the udc can be
744 * accessed. This mask is a parameter to the check() functions of the extensions
745 */
746static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
747 unsigned int udc_cnt, unsigned int hooknr, char *base)
748{
749 int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
750 struct ebt_entry *e = (struct ebt_entry *)chain->data;
751 struct ebt_entry_target *t;
752
753 while (pos < nentries || chain_nr != -1) {
754 /* end of udc, go back one 'recursion' step */
755 if (pos == nentries) {
756 /* put back values of the time when this chain was called */
757 e = cl_s[chain_nr].cs.e;
758 if (cl_s[chain_nr].from != -1)
759 nentries =
760 cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
761 else
762 nentries = chain->nentries;
763 pos = cl_s[chain_nr].cs.n;
764 /* make sure we won't see a loop that isn't one */
765 cl_s[chain_nr].cs.n = 0;
766 chain_nr = cl_s[chain_nr].from;
767 if (pos == nentries)
768 continue;
769 }
770 t = (struct ebt_entry_target *)
771 (((char *)e) + e->target_offset);
772 if (strcmp(t->u.name, EBT_STANDARD_TARGET))
773 goto letscontinue;
774 if (e->target_offset + sizeof(struct ebt_standard_target) >
775 e->next_offset) {
776 BUGPRINT("Standard target size too big\n");
777 return -1;
778 }
779 verdict = ((struct ebt_standard_target *)t)->verdict;
780 if (verdict >= 0) { /* jump to another chain */
781 struct ebt_entries *hlp2 =
782 (struct ebt_entries *)(base + verdict);
783 for (i = 0; i < udc_cnt; i++)
784 if (hlp2 == cl_s[i].cs.chaininfo)
785 break;
786 /* bad destination or loop */
787 if (i == udc_cnt) {
788 BUGPRINT("bad destination\n");
789 return -1;
790 }
791 if (cl_s[i].cs.n) {
792 BUGPRINT("loop\n");
793 return -1;
794 }
Al Viro98a08242006-11-30 19:24:49 -0800795 if (cl_s[i].hookmask & (1 << hooknr))
796 goto letscontinue;
797 /* this can't be 0, so the loop test is correct */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 cl_s[i].cs.n = pos + 1;
799 pos = 0;
Jan Engelhardt98e86402009-04-15 21:06:05 +0200800 cl_s[i].cs.e = ebt_next_entry(e);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 e = (struct ebt_entry *)(hlp2->data);
802 nentries = hlp2->nentries;
803 cl_s[i].from = chain_nr;
804 chain_nr = i;
805 /* this udc is accessible from the base chain for hooknr */
806 cl_s[i].hookmask |= (1 << hooknr);
807 continue;
808 }
809letscontinue:
Jan Engelhardt98e86402009-04-15 21:06:05 +0200810 e = ebt_next_entry(e);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 pos++;
812 }
813 return 0;
814}
815
816/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
Alexey Dobriyana83d8e82010-01-18 08:21:13 +0100817static int translate_table(struct net *net, char *name,
818 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819{
820 unsigned int i, j, k, udc_cnt;
821 int ret;
822 struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
823
824 i = 0;
Al Viro1f072c92006-11-30 19:26:53 -0800825 while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 i++;
827 if (i == NF_BR_NUMHOOKS) {
828 BUGPRINT("No valid hooks specified\n");
829 return -EINVAL;
830 }
Al Viro1f072c92006-11-30 19:26:53 -0800831 if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 BUGPRINT("Chains don't start at beginning\n");
833 return -EINVAL;
834 }
835 /* make sure chains are ordered after each other in same order
836 as their corresponding hooks */
837 for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
Al Viro1f072c92006-11-30 19:26:53 -0800838 if (!newinfo->hook_entry[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 continue;
Al Viro1f072c92006-11-30 19:26:53 -0800840 if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 BUGPRINT("Hook order must be followed\n");
842 return -EINVAL;
843 }
844 i = j;
845 }
846
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 /* do some early checkings and initialize some things */
848 i = 0; /* holds the expected nr. of entries for the chain */
849 j = 0; /* holds the up to now counted entries for the chain */
850 k = 0; /* holds the total nr. of entries, should equal
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900851 newinfo->nentries afterwards */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
853 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro0e795532006-11-30 19:27:13 -0800854 ebt_check_entry_size_and_hooks, newinfo,
855 &i, &j, &k, &udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856
857 if (ret != 0)
858 return ret;
859
860 if (i != j) {
861 BUGPRINT("nentries does not equal the nr of entries in the "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900862 "(last) chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 return -EINVAL;
864 }
865 if (k != newinfo->nentries) {
866 BUGPRINT("Total nentries is wrong\n");
867 return -EINVAL;
868 }
869
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 /* get the location of the udc, put them in an array
871 while we're at it, allocate the chainstack */
872 if (udc_cnt) {
873 /* this will get free'd in do_replace()/ebt_register_table()
874 if an error occurs */
Jayachandran C7ad4d2f2006-04-11 17:25:38 -0700875 newinfo->chainstack =
Christoph Lameter53b8a312007-02-20 13:57:51 -0800876 vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 if (!newinfo->chainstack)
878 return -ENOMEM;
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700879 for_each_possible_cpu(i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 newinfo->chainstack[i] =
Jayachandran C18bc89a2006-04-20 00:14:49 -0700881 vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 if (!newinfo->chainstack[i]) {
883 while (i)
884 vfree(newinfo->chainstack[--i]);
885 vfree(newinfo->chainstack);
886 newinfo->chainstack = NULL;
887 return -ENOMEM;
888 }
889 }
890
Jayachandran C18bc89a2006-04-20 00:14:49 -0700891 cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 if (!cl_s)
893 return -ENOMEM;
894 i = 0; /* the i'th udc */
895 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro177abc32006-11-30 19:27:32 -0800896 ebt_get_udc_positions, newinfo, &i, cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 /* sanity check */
898 if (i != udc_cnt) {
899 BUGPRINT("i != udc_cnt\n");
900 vfree(cl_s);
901 return -EFAULT;
902 }
903 }
904
905 /* Check for loops */
906 for (i = 0; i < NF_BR_NUMHOOKS; i++)
Al Viro1f072c92006-11-30 19:26:53 -0800907 if (newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 if (check_chainloops(newinfo->hook_entry[i],
909 cl_s, udc_cnt, i, newinfo->entries)) {
James Lamanna68d31872005-06-22 22:12:57 -0700910 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 return -EINVAL;
912 }
913
Jan Engelhardt96de0e22007-10-19 23:21:04 +0200914 /* we now know the following (along with E=mc²):
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 - the nr of entries in each chain is right
916 - the size of the allocated space is right
917 - all valid hooks have a corresponding chain
918 - there are no loops
919 - wrong data can still be on the level of a single entry
920 - could be there are jumps to places that are not the
921 beginning of a chain. This can only occur in chains that
922 are not accessible from any base chains, so we don't care. */
923
924 /* used to know what we need to clean up if something goes wrong */
925 i = 0;
926 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Alexey Dobriyana83d8e82010-01-18 08:21:13 +0100927 ebt_check_entry, net, newinfo, name, &i, cl_s, udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 if (ret != 0) {
929 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100930 ebt_cleanup_entry, net, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 }
James Lamanna68d31872005-06-22 22:12:57 -0700932 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 return ret;
934}
935
936/* called under write_lock */
937static void get_counters(struct ebt_counter *oldcounters,
938 struct ebt_counter *counters, unsigned int nentries)
939{
940 int i, cpu;
941 struct ebt_counter *counter_base;
942
943 /* counters of cpu 0 */
944 memcpy(counters, oldcounters,
David S. Millerc8923c62005-10-13 14:41:23 -0700945 sizeof(struct ebt_counter) * nentries);
946
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 /* add other counters to those of cpu 0 */
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700948 for_each_possible_cpu(cpu) {
David S. Millerc8923c62005-10-13 14:41:23 -0700949 if (cpu == 0)
950 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
952 for (i = 0; i < nentries; i++) {
953 counters[i].pcnt += counter_base[i].pcnt;
954 counters[i].bcnt += counter_base[i].bcnt;
955 }
956 }
957}
958
959/* replace the table */
Alexey Dobriyan511061e2008-11-04 14:22:55 +0100960static int do_replace(struct net *net, void __user *user, unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961{
962 int ret, i, countersize;
963 struct ebt_table_info *newinfo;
964 struct ebt_replace tmp;
965 struct ebt_table *t;
966 struct ebt_counter *counterstmp = NULL;
967 /* used to be able to unlock earlier */
968 struct ebt_table_info *table;
969
970 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
971 return -EFAULT;
972
973 if (len != sizeof(tmp) + tmp.entries_size) {
974 BUGPRINT("Wrong len argument\n");
975 return -EINVAL;
976 }
977
978 if (tmp.entries_size == 0) {
979 BUGPRINT("Entries_size never zero\n");
980 return -EINVAL;
981 }
Kirill Korotaevee4bb812006-02-04 02:16:56 -0800982 /* overflow check */
983 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
984 SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
985 return -ENOMEM;
986 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
987 return -ENOMEM;
988
Christoph Lameter53b8a312007-02-20 13:57:51 -0800989 countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -0700990 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 if (!newinfo)
992 return -ENOMEM;
993
994 if (countersize)
995 memset(newinfo->counters, 0, countersize);
996
Kris Katterjohn8b3a7002006-01-11 15:56:43 -0800997 newinfo->entries = vmalloc(tmp.entries_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 if (!newinfo->entries) {
999 ret = -ENOMEM;
1000 goto free_newinfo;
1001 }
1002 if (copy_from_user(
1003 newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
1004 BUGPRINT("Couldn't copy entries from userspace\n");
1005 ret = -EFAULT;
1006 goto free_entries;
1007 }
1008
1009 /* the user wants counters back
1010 the check on the size is done later, when we have the lock */
1011 if (tmp.num_counters) {
Jayachandran C18bc89a2006-04-20 00:14:49 -07001012 counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 if (!counterstmp) {
1014 ret = -ENOMEM;
1015 goto free_entries;
1016 }
1017 }
1018 else
1019 counterstmp = NULL;
1020
1021 /* this can get initialized by translate_table() */
1022 newinfo->chainstack = NULL;
Al Viro1bc23262006-11-30 19:28:08 -08001023 ret = ebt_verify_pointers(&tmp, newinfo);
1024 if (ret != 0)
1025 goto free_counterstmp;
1026
Alexey Dobriyana83d8e82010-01-18 08:21:13 +01001027 ret = translate_table(net, tmp.name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028
1029 if (ret != 0)
1030 goto free_counterstmp;
1031
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001032 t = find_table_lock(net, tmp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 if (!t) {
1034 ret = -ENOENT;
1035 goto free_iterate;
1036 }
1037
1038 /* the table doesn't like it */
1039 if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
1040 goto free_unlock;
1041
1042 if (tmp.num_counters && tmp.num_counters != t->private->nentries) {
1043 BUGPRINT("Wrong nr. of counters requested\n");
1044 ret = -EINVAL;
1045 goto free_unlock;
1046 }
1047
1048 /* we have the mutex lock, so no danger in reading this pointer */
1049 table = t->private;
1050 /* make sure the table can only be rmmod'ed if it contains no rules */
1051 if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) {
1052 ret = -ENOENT;
1053 goto free_unlock;
1054 } else if (table->nentries && !newinfo->nentries)
1055 module_put(t->me);
1056 /* we need an atomic snapshot of the counters */
1057 write_lock_bh(&t->lock);
1058 if (tmp.num_counters)
1059 get_counters(t->private->counters, counterstmp,
1060 t->private->nentries);
1061
1062 t->private = newinfo;
1063 write_unlock_bh(&t->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001064 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 /* so, a user can change the chains while having messed up her counter
1066 allocation. Only reason why this is done is because this way the lock
1067 is held only once, while this doesn't bring the kernel into a
1068 dangerous state. */
1069 if (tmp.num_counters &&
1070 copy_to_user(tmp.counters, counterstmp,
1071 tmp.num_counters * sizeof(struct ebt_counter))) {
1072 BUGPRINT("Couldn't copy counters to userspace\n");
1073 ret = -EFAULT;
1074 }
1075 else
1076 ret = 0;
1077
1078 /* decrease module count and free resources */
1079 EBT_ENTRY_ITERATE(table->entries, table->entries_size,
Alexey Dobriyanf54e9362010-01-18 08:25:47 +01001080 ebt_cleanup_entry, net, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
1082 vfree(table->entries);
1083 if (table->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001084 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 vfree(table->chainstack[i]);
1086 vfree(table->chainstack);
1087 }
1088 vfree(table);
1089
James Lamanna68d31872005-06-22 22:12:57 -07001090 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 return ret;
1092
1093free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001094 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095free_iterate:
1096 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Alexey Dobriyanf54e9362010-01-18 08:25:47 +01001097 ebt_cleanup_entry, net, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098free_counterstmp:
James Lamanna68d31872005-06-22 22:12:57 -07001099 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 /* can be initialized in translate_table() */
1101 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001102 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 vfree(newinfo->chainstack[i]);
1104 vfree(newinfo->chainstack);
1105 }
1106free_entries:
James Lamanna68d31872005-06-22 22:12:57 -07001107 vfree(newinfo->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108free_newinfo:
James Lamanna68d31872005-06-22 22:12:57 -07001109 vfree(newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 return ret;
1111}
1112
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001113struct ebt_table *
1114ebt_register_table(struct net *net, const struct ebt_table *input_table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115{
1116 struct ebt_table_info *newinfo;
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001117 struct ebt_table *t, *table;
Al Viro1e419cd2006-11-30 19:28:48 -08001118 struct ebt_replace_kernel *repl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 int ret, i, countersize;
Al Virodf07a812006-11-30 19:28:25 -08001120 void *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001122 if (input_table == NULL || (repl = input_table->table) == NULL ||
1123 repl->entries == 0 || repl->entries_size == 0 ||
1124 repl->counters != NULL || input_table->private != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 BUGPRINT("Bad table data for ebt_register_table!!!\n");
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001126 return ERR_PTR(-EINVAL);
1127 }
1128
1129 /* Don't add one table to multiple lists. */
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001130 table = kmemdup(input_table, sizeof(struct ebt_table), GFP_KERNEL);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001131 if (!table) {
1132 ret = -ENOMEM;
1133 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 }
1135
Christoph Lameter53b8a312007-02-20 13:57:51 -08001136 countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -07001137 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 ret = -ENOMEM;
1139 if (!newinfo)
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001140 goto free_table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
Al Virodf07a812006-11-30 19:28:25 -08001142 p = vmalloc(repl->entries_size);
1143 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 goto free_newinfo;
1145
Al Virodf07a812006-11-30 19:28:25 -08001146 memcpy(p, repl->entries, repl->entries_size);
1147 newinfo->entries = p;
1148
1149 newinfo->entries_size = repl->entries_size;
1150 newinfo->nentries = repl->nentries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151
1152 if (countersize)
1153 memset(newinfo->counters, 0, countersize);
1154
1155 /* fill in newinfo and parse the entries */
1156 newinfo->chainstack = NULL;
Al Virodf07a812006-11-30 19:28:25 -08001157 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1158 if ((repl->valid_hooks & (1 << i)) == 0)
1159 newinfo->hook_entry[i] = NULL;
1160 else
1161 newinfo->hook_entry[i] = p +
1162 ((char *)repl->hook_entry[i] - repl->entries);
1163 }
Alexey Dobriyana83d8e82010-01-18 08:21:13 +01001164 ret = translate_table(net, repl->name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 if (ret != 0) {
1166 BUGPRINT("Translate_table failed\n");
1167 goto free_chainstack;
1168 }
1169
1170 if (table->check && table->check(newinfo, table->valid_hooks)) {
1171 BUGPRINT("The table doesn't like its own initial data, lol\n");
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001172 return ERR_PTR(-EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 }
1174
1175 table->private = newinfo;
1176 rwlock_init(&table->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001177 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 if (ret != 0)
1179 goto free_chainstack;
1180
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001181 list_for_each_entry(t, &net->xt.tables[NFPROTO_BRIDGE], list) {
Patrick McHardydf0933d2006-09-20 11:57:53 -07001182 if (strcmp(t->name, table->name) == 0) {
1183 ret = -EEXIST;
1184 BUGPRINT("Table name already exists\n");
1185 goto free_unlock;
1186 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 }
1188
1189 /* Hold a reference count if the chains aren't empty */
1190 if (newinfo->nentries && !try_module_get(table->me)) {
1191 ret = -ENOENT;
1192 goto free_unlock;
1193 }
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001194 list_add(&table->list, &net->xt.tables[NFPROTO_BRIDGE]);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001195 mutex_unlock(&ebt_mutex);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001196 return table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001198 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199free_chainstack:
1200 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001201 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 vfree(newinfo->chainstack[i]);
1203 vfree(newinfo->chainstack);
1204 }
1205 vfree(newinfo->entries);
1206free_newinfo:
1207 vfree(newinfo);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001208free_table:
1209 kfree(table);
1210out:
1211 return ERR_PTR(ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212}
1213
Alexey Dobriyanf54e9362010-01-18 08:25:47 +01001214void ebt_unregister_table(struct net *net, struct ebt_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215{
1216 int i;
1217
1218 if (!table) {
1219 BUGPRINT("Request to unregister NULL table!!!\n");
1220 return;
1221 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001222 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001223 list_del(&table->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001224 mutex_unlock(&ebt_mutex);
Alexey Dobriyandbcdf852008-11-04 14:28:04 +01001225 EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size,
Alexey Dobriyanf54e9362010-01-18 08:25:47 +01001226 ebt_cleanup_entry, net, NULL);
Alexey Dobriyandbcdf852008-11-04 14:28:04 +01001227 if (table->private->nentries)
1228 module_put(table->me);
James Lamanna68d31872005-06-22 22:12:57 -07001229 vfree(table->private->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 if (table->private->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001231 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 vfree(table->private->chainstack[i]);
1233 vfree(table->private->chainstack);
1234 }
1235 vfree(table->private);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001236 kfree(table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237}
1238
1239/* userspace just supplied us with counters */
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001240static int update_counters(struct net *net, void __user *user, unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241{
1242 int i, ret;
1243 struct ebt_counter *tmp;
1244 struct ebt_replace hlp;
1245 struct ebt_table *t;
1246
1247 if (copy_from_user(&hlp, user, sizeof(hlp)))
1248 return -EFAULT;
1249
1250 if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
1251 return -EINVAL;
1252 if (hlp.num_counters == 0)
1253 return -EINVAL;
1254
Jayachandran C18bc89a2006-04-20 00:14:49 -07001255 if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 MEMPRINT("Update_counters && nomemory\n");
1257 return -ENOMEM;
1258 }
1259
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001260 t = find_table_lock(net, hlp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 if (!t)
1262 goto free_tmp;
1263
1264 if (hlp.num_counters != t->private->nentries) {
1265 BUGPRINT("Wrong nr of counters\n");
1266 ret = -EINVAL;
1267 goto unlock_mutex;
1268 }
1269
1270 if ( copy_from_user(tmp, hlp.counters,
1271 hlp.num_counters * sizeof(struct ebt_counter)) ) {
1272 BUGPRINT("Updata_counters && !cfu\n");
1273 ret = -EFAULT;
1274 goto unlock_mutex;
1275 }
1276
1277 /* we want an atomic add of the counters */
1278 write_lock_bh(&t->lock);
1279
1280 /* we add to the counters of the first cpu */
1281 for (i = 0; i < hlp.num_counters; i++) {
1282 t->private->counters[i].pcnt += tmp[i].pcnt;
1283 t->private->counters[i].bcnt += tmp[i].bcnt;
1284 }
1285
1286 write_unlock_bh(&t->lock);
1287 ret = 0;
1288unlock_mutex:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001289 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290free_tmp:
1291 vfree(tmp);
1292 return ret;
1293}
1294
1295static inline int ebt_make_matchname(struct ebt_entry_match *m,
Al Viro1e419cd2006-11-30 19:28:48 -08001296 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297{
Al Viro1e419cd2006-11-30 19:28:48 -08001298 char __user *hlp = ubase + ((char *)m - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
1300 return -EFAULT;
1301 return 0;
1302}
1303
1304static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
Al Viro1e419cd2006-11-30 19:28:48 -08001305 char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306{
Al Viro1e419cd2006-11-30 19:28:48 -08001307 char __user *hlp = ubase + ((char *)w - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
1309 return -EFAULT;
1310 return 0;
1311}
1312
Al Viro1e419cd2006-11-30 19:28:48 -08001313static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314{
1315 int ret;
Al Viro1e419cd2006-11-30 19:28:48 -08001316 char __user *hlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 struct ebt_entry_target *t;
1318
Al Viro40642f92006-11-30 19:24:12 -08001319 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 return 0;
1321
Al Viro1e419cd2006-11-30 19:28:48 -08001322 hlp = ubase + (((char *)e + e->target_offset) - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +09001324
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
1326 if (ret != 0)
1327 return ret;
1328 ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
1329 if (ret != 0)
1330 return ret;
1331 if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
1332 return -EFAULT;
1333 return 0;
1334}
1335
Ingo Molnar57b47a52006-03-20 22:35:41 -08001336/* called with ebt_mutex locked */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337static int copy_everything_to_user(struct ebt_table *t, void __user *user,
1338 int *len, int cmd)
1339{
1340 struct ebt_replace tmp;
1341 struct ebt_counter *counterstmp, *oldcounters;
1342 unsigned int entries_size, nentries;
1343 char *entries;
1344
1345 if (cmd == EBT_SO_GET_ENTRIES) {
1346 entries_size = t->private->entries_size;
1347 nentries = t->private->nentries;
1348 entries = t->private->entries;
1349 oldcounters = t->private->counters;
1350 } else {
1351 entries_size = t->table->entries_size;
1352 nentries = t->table->nentries;
1353 entries = t->table->entries;
1354 oldcounters = t->table->counters;
1355 }
1356
1357 if (copy_from_user(&tmp, user, sizeof(tmp))) {
1358 BUGPRINT("Cfu didn't work\n");
1359 return -EFAULT;
1360 }
1361
1362 if (*len != sizeof(struct ebt_replace) + entries_size +
1363 (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
1364 BUGPRINT("Wrong size\n");
1365 return -EINVAL;
1366 }
1367
1368 if (tmp.nentries != nentries) {
1369 BUGPRINT("Nentries wrong\n");
1370 return -EINVAL;
1371 }
1372
1373 if (tmp.entries_size != entries_size) {
1374 BUGPRINT("Wrong size\n");
1375 return -EINVAL;
1376 }
1377
1378 /* userspace might not need the counters */
1379 if (tmp.num_counters) {
1380 if (tmp.num_counters != nentries) {
1381 BUGPRINT("Num_counters wrong\n");
1382 return -EINVAL;
1383 }
Jayachandran C18bc89a2006-04-20 00:14:49 -07001384 counterstmp = vmalloc(nentries * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 if (!counterstmp) {
1386 MEMPRINT("Couldn't copy counters, out of memory\n");
1387 return -ENOMEM;
1388 }
1389 write_lock_bh(&t->lock);
1390 get_counters(oldcounters, counterstmp, nentries);
1391 write_unlock_bh(&t->lock);
1392
1393 if (copy_to_user(tmp.counters, counterstmp,
1394 nentries * sizeof(struct ebt_counter))) {
1395 BUGPRINT("Couldn't copy counters to userspace\n");
1396 vfree(counterstmp);
1397 return -EFAULT;
1398 }
1399 vfree(counterstmp);
1400 }
1401
1402 if (copy_to_user(tmp.entries, entries, entries_size)) {
1403 BUGPRINT("Couldn't copy entries to userspace\n");
1404 return -EFAULT;
1405 }
1406 /* set the match/watcher/target names right */
1407 return EBT_ENTRY_ITERATE(entries, entries_size,
1408 ebt_make_names, entries, tmp.entries);
1409}
1410
1411static int do_ebt_set_ctl(struct sock *sk,
1412 int cmd, void __user *user, unsigned int len)
1413{
1414 int ret;
1415
1416 switch(cmd) {
1417 case EBT_SO_SET_ENTRIES:
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001418 ret = do_replace(sock_net(sk), user, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 break;
1420 case EBT_SO_SET_COUNTERS:
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001421 ret = update_counters(sock_net(sk), user, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 break;
1423 default:
1424 ret = -EINVAL;
1425 }
1426 return ret;
1427}
1428
1429static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1430{
1431 int ret;
1432 struct ebt_replace tmp;
1433 struct ebt_table *t;
1434
1435 if (copy_from_user(&tmp, user, sizeof(tmp)))
1436 return -EFAULT;
1437
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001438 t = find_table_lock(sock_net(sk), tmp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 if (!t)
1440 return ret;
1441
1442 switch(cmd) {
1443 case EBT_SO_GET_INFO:
1444 case EBT_SO_GET_INIT_INFO:
1445 if (*len != sizeof(struct ebt_replace)){
1446 ret = -EINVAL;
Ingo Molnar57b47a52006-03-20 22:35:41 -08001447 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 break;
1449 }
1450 if (cmd == EBT_SO_GET_INFO) {
1451 tmp.nentries = t->private->nentries;
1452 tmp.entries_size = t->private->entries_size;
1453 tmp.valid_hooks = t->valid_hooks;
1454 } else {
1455 tmp.nentries = t->table->nentries;
1456 tmp.entries_size = t->table->entries_size;
1457 tmp.valid_hooks = t->table->valid_hooks;
1458 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001459 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 if (copy_to_user(user, &tmp, *len) != 0){
1461 BUGPRINT("c2u Didn't work\n");
1462 ret = -EFAULT;
1463 break;
1464 }
1465 ret = 0;
1466 break;
1467
1468 case EBT_SO_GET_ENTRIES:
1469 case EBT_SO_GET_INIT_ENTRIES:
1470 ret = copy_everything_to_user(t, user, len, cmd);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001471 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 break;
1473
1474 default:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001475 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 ret = -EINVAL;
1477 }
1478
1479 return ret;
1480}
1481
1482static struct nf_sockopt_ops ebt_sockopts =
Andrew Morton74ca4e5a2006-03-20 22:55:02 -08001483{
1484 .pf = PF_INET,
1485 .set_optmin = EBT_BASE_CTL,
1486 .set_optmax = EBT_SO_SET_MAX + 1,
1487 .set = do_ebt_set_ctl,
1488 .get_optmin = EBT_BASE_CTL,
1489 .get_optmax = EBT_SO_GET_MAX + 1,
1490 .get = do_ebt_get_ctl,
Neil Horman16fcec32007-09-11 11:28:26 +02001491 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492};
1493
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001494static int __init ebtables_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495{
1496 int ret;
1497
Jan Engelhardt043ef462008-10-08 11:35:15 +02001498 ret = xt_register_target(&ebt_standard_target);
1499 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 return ret;
Jan Engelhardt043ef462008-10-08 11:35:15 +02001501 ret = nf_register_sockopt(&ebt_sockopts);
1502 if (ret < 0) {
1503 xt_unregister_target(&ebt_standard_target);
1504 return ret;
1505 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506
Patrick McHardya887c1c2007-07-14 20:46:15 -07001507 printk(KERN_INFO "Ebtables v2.0 registered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 return 0;
1509}
1510
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001511static void __exit ebtables_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512{
1513 nf_unregister_sockopt(&ebt_sockopts);
Jan Engelhardt043ef462008-10-08 11:35:15 +02001514 xt_unregister_target(&ebt_standard_target);
Patrick McHardya887c1c2007-07-14 20:46:15 -07001515 printk(KERN_INFO "Ebtables v2.0 unregistered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516}
1517
1518EXPORT_SYMBOL(ebt_register_table);
1519EXPORT_SYMBOL(ebt_unregister_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520EXPORT_SYMBOL(ebt_do_table);
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001521module_init(ebtables_init);
1522module_exit(ebtables_fini);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523MODULE_LICENSE("GPL");