blob: 4370e96804872f4a6583e1010bb3a7a87c9489ac [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
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +020085static inline int
86ebt_dev_check(const char *entry, const struct net_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -070087{
88 int i = 0;
Julia Lawallf3d8b2e2009-01-09 10:22:22 +000089 const char *devname;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
91 if (*entry == '\0')
92 return 0;
93 if (!device)
94 return 1;
Julia Lawallf3d8b2e2009-01-09 10:22:22 +000095 devname = device->name;
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 /* 1 is the wildcard token */
97 while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i])
98 i++;
99 return (devname[i] != entry[i] && entry[i] != 1);
100}
101
102#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
103/* process standard matches */
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200104static inline int
105ebt_basic_match(const struct ebt_entry *e, const struct ethhdr *h,
106 const struct net_device *in, const struct net_device *out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107{
108 int verdict, i;
109
110 if (e->bitmask & EBT_802_3) {
111 if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO))
112 return 1;
113 } else if (!(e->bitmask & EBT_NOPROTO) &&
114 FWINV2(e->ethproto != h->h_proto, EBT_IPROTO))
115 return 1;
116
117 if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
118 return 1;
119 if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
120 return 1;
121 if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check(
122 e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN))
123 return 1;
124 if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check(
125 e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT))
126 return 1;
127
128 if (e->bitmask & EBT_SOURCEMAC) {
129 verdict = 0;
130 for (i = 0; i < 6; i++)
131 verdict |= (h->h_source[i] ^ e->sourcemac[i]) &
132 e->sourcemsk[i];
133 if (FWINV2(verdict != 0, EBT_ISOURCE) )
134 return 1;
135 }
136 if (e->bitmask & EBT_DESTMAC) {
137 verdict = 0;
138 for (i = 0; i < 6; i++)
139 verdict |= (h->h_dest[i] ^ e->destmac[i]) &
140 e->destmsk[i];
141 if (FWINV2(verdict != 0, EBT_IDEST) )
142 return 1;
143 }
144 return 0;
145}
146
Jan Engelhardt98e86402009-04-15 21:06:05 +0200147static inline __pure
148struct ebt_entry *ebt_next_entry(const struct ebt_entry *entry)
149{
150 return (void *)entry + entry->next_offset;
151}
152
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153/* Do some firewalling */
Herbert Xu3db05fe2007-10-15 00:53:15 -0700154unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 const struct net_device *in, const struct net_device *out,
156 struct ebt_table *table)
157{
158 int i, nentries;
159 struct ebt_entry *point;
160 struct ebt_counter *counter_base, *cb_base;
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200161 const struct ebt_entry_target *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 int verdict, sp = 0;
163 struct ebt_chainstack *cs;
164 struct ebt_entries *chaininfo;
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200165 const char *base;
166 const struct ebt_table_info *private;
Jan Engelhardt5365f802008-10-08 11:35:16 +0200167 bool hotdrop = false;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200168 struct xt_match_param mtpar;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200169 struct xt_target_param tgpar;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200170
Jan Engelhardt916a9172008-10-08 11:35:20 +0200171 mtpar.family = tgpar.family = NFPROTO_BRIDGE;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200172 mtpar.in = tgpar.in = in;
173 mtpar.out = tgpar.out = out;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200174 mtpar.hotdrop = &hotdrop;
Evgeniy Polyakova5e78822009-06-04 16:54:42 +0200175 mtpar.hooknum = tgpar.hooknum = hook;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
177 read_lock_bh(&table->lock);
178 private = table->private;
179 cb_base = COUNTER_BASE(private->counters, private->nentries,
180 smp_processor_id());
181 if (private->chainstack)
182 cs = private->chainstack[smp_processor_id()];
183 else
184 cs = NULL;
185 chaininfo = private->hook_entry[hook];
186 nentries = private->hook_entry[hook]->nentries;
187 point = (struct ebt_entry *)(private->hook_entry[hook]->data);
188 counter_base = cb_base + private->hook_entry[hook]->counter_offset;
189 /* base for chain jumps */
190 base = private->entries;
191 i = 0;
192 while (i < nentries) {
Herbert Xu3db05fe2007-10-15 00:53:15 -0700193 if (ebt_basic_match(point, eth_hdr(skb), in, out))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 goto letscontinue;
195
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200196 if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, &mtpar) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 goto letscontinue;
Jan Engelhardt5365f802008-10-08 11:35:16 +0200198 if (hotdrop) {
199 read_unlock_bh(&table->lock);
200 return NF_DROP;
201 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
203 /* increase counter */
204 (*(counter_base + i)).pcnt++;
Herbert Xu3db05fe2007-10-15 00:53:15 -0700205 (*(counter_base + i)).bcnt += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
207 /* these should only watch: not modify, nor tell us
208 what to do with the packet */
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200209 EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, &tgpar);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210
211 t = (struct ebt_entry_target *)
212 (((char *)point) + point->target_offset);
213 /* standard target */
214 if (!t->u.target->target)
215 verdict = ((struct ebt_standard_target *)t)->verdict;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200216 else {
217 tgpar.target = t->u.target;
218 tgpar.targinfo = t->data;
219 verdict = t->u.target->target(skb, &tgpar);
220 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 if (verdict == EBT_ACCEPT) {
222 read_unlock_bh(&table->lock);
223 return NF_ACCEPT;
224 }
225 if (verdict == EBT_DROP) {
226 read_unlock_bh(&table->lock);
227 return NF_DROP;
228 }
229 if (verdict == EBT_RETURN) {
230letsreturn:
231#ifdef CONFIG_NETFILTER_DEBUG
232 if (sp == 0) {
233 BUGPRINT("RETURN on base chain");
234 /* act like this is EBT_CONTINUE */
235 goto letscontinue;
236 }
237#endif
238 sp--;
239 /* put all the local variables right */
240 i = cs[sp].n;
241 chaininfo = cs[sp].chaininfo;
242 nentries = chaininfo->nentries;
243 point = cs[sp].e;
244 counter_base = cb_base +
245 chaininfo->counter_offset;
246 continue;
247 }
248 if (verdict == EBT_CONTINUE)
249 goto letscontinue;
250#ifdef CONFIG_NETFILTER_DEBUG
251 if (verdict < 0) {
252 BUGPRINT("bogus standard verdict\n");
253 read_unlock_bh(&table->lock);
254 return NF_DROP;
255 }
256#endif
257 /* jump to a udc */
258 cs[sp].n = i + 1;
259 cs[sp].chaininfo = chaininfo;
Jan Engelhardt98e86402009-04-15 21:06:05 +0200260 cs[sp].e = ebt_next_entry(point);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 i = 0;
262 chaininfo = (struct ebt_entries *) (base + verdict);
263#ifdef CONFIG_NETFILTER_DEBUG
264 if (chaininfo->distinguisher) {
265 BUGPRINT("jump to non-chain\n");
266 read_unlock_bh(&table->lock);
267 return NF_DROP;
268 }
269#endif
270 nentries = chaininfo->nentries;
271 point = (struct ebt_entry *)chaininfo->data;
272 counter_base = cb_base + chaininfo->counter_offset;
273 sp++;
274 continue;
275letscontinue:
Jan Engelhardt98e86402009-04-15 21:06:05 +0200276 point = ebt_next_entry(point);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 i++;
278 }
279
280 /* I actually like this :) */
281 if (chaininfo->policy == EBT_RETURN)
282 goto letsreturn;
283 if (chaininfo->policy == EBT_ACCEPT) {
284 read_unlock_bh(&table->lock);
285 return NF_ACCEPT;
286 }
287 read_unlock_bh(&table->lock);
288 return NF_DROP;
289}
290
291/* If it succeeds, returns element and locks mutex */
292static inline void *
293find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800294 struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295{
Patrick McHardydf0933d2006-09-20 11:57:53 -0700296 struct {
297 struct list_head list;
298 char name[EBT_FUNCTION_MAXNAMELEN];
299 } *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
Ingo Molnar57b47a52006-03-20 22:35:41 -0800301 *error = mutex_lock_interruptible(mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 if (*error != 0)
303 return NULL;
304
Patrick McHardydf0933d2006-09-20 11:57:53 -0700305 list_for_each_entry(e, head, list) {
306 if (strcmp(e->name, name) == 0)
307 return e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 }
Patrick McHardydf0933d2006-09-20 11:57:53 -0700309 *error = -ENOENT;
310 mutex_unlock(mutex);
311 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312}
313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314static void *
315find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800316 int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317{
Johannes Berg95a5afc2008-10-16 15:24:51 -0700318 return try_then_request_module(
319 find_inlist_lock_noload(head, name, error, mutex),
320 "%s%s", prefix, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
323static inline struct ebt_table *
Alexey Dobriyan511061e2008-11-04 14:22:55 +0100324find_table_lock(struct net *net, const char *name, int *error,
325 struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326{
Alexey Dobriyan511061e2008-11-04 14:22:55 +0100327 return find_inlist_lock(&net->xt.tables[NFPROTO_BRIDGE], name,
328 "ebtable_", error, mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329}
330
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331static inline int
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200332ebt_check_match(struct ebt_entry_match *m, struct xt_mtchk_param *par,
333 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200335 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200336 struct xt_match *match;
Al Viro14197d52006-11-30 19:25:21 -0800337 size_t left = ((char *)e + e->watchers_offset) - (char *)m;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 int ret;
339
Al Viro14197d52006-11-30 19:25:21 -0800340 if (left < sizeof(struct ebt_entry_match) ||
341 left - sizeof(struct ebt_entry_match) < m->match_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200343
344 match = try_then_request_module(xt_find_match(NFPROTO_BRIDGE,
345 m->u.name, 0), "ebt_%s", m->u.name);
346 if (IS_ERR(match))
347 return PTR_ERR(match);
348 if (match == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200350 m->u.match = match;
351
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200352 par->match = match;
353 par->matchinfo = m->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200354 ret = xt_check_match(par, m->match_size,
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200355 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200356 if (ret < 0) {
357 module_put(match->me);
358 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200360
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 (*cnt)++;
362 return 0;
363}
364
365static inline int
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200366ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
367 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368{
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200369 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200370 struct xt_target *watcher;
Al Viro14197d52006-11-30 19:25:21 -0800371 size_t left = ((char *)e + e->target_offset) - (char *)w;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 int ret;
373
Al Viro14197d52006-11-30 19:25:21 -0800374 if (left < sizeof(struct ebt_entry_watcher) ||
375 left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200377
378 watcher = try_then_request_module(
379 xt_find_target(NFPROTO_BRIDGE, w->u.name, 0),
380 "ebt_%s", w->u.name);
381 if (IS_ERR(watcher))
382 return PTR_ERR(watcher);
383 if (watcher == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200385 w->u.watcher = watcher;
386
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200387 par->target = watcher;
388 par->targinfo = w->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200389 ret = xt_check_target(par, w->watcher_size,
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200390 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200391 if (ret < 0) {
392 module_put(watcher->me);
393 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200395
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 (*cnt)++;
397 return 0;
398}
399
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200400static int ebt_verify_pointers(const struct ebt_replace *repl,
Al Viro70fe9af2006-11-30 19:26:14 -0800401 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402{
Al Viro70fe9af2006-11-30 19:26:14 -0800403 unsigned int limit = repl->entries_size;
404 unsigned int valid_hooks = repl->valid_hooks;
405 unsigned int offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 int i;
407
Al Viroe4fd77d2006-11-30 19:26:35 -0800408 for (i = 0; i < NF_BR_NUMHOOKS; i++)
409 newinfo->hook_entry[i] = NULL;
410
411 newinfo->entries_size = repl->entries_size;
412 newinfo->nentries = repl->nentries;
413
Al Viro70fe9af2006-11-30 19:26:14 -0800414 while (offset < limit) {
415 size_t left = limit - offset;
416 struct ebt_entry *e = (void *)newinfo->entries + offset;
Al Virobb2ef252006-11-30 19:22:42 -0800417
Al Viro70fe9af2006-11-30 19:26:14 -0800418 if (left < sizeof(unsigned int))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 break;
Al Viro22b440b2006-11-30 19:25:51 -0800420
Al Viro70fe9af2006-11-30 19:26:14 -0800421 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
422 if ((valid_hooks & (1 << i)) == 0)
423 continue;
Al Viro1e419cd2006-11-30 19:28:48 -0800424 if ((char __user *)repl->hook_entry[i] ==
425 repl->entries + offset)
Al Viro70fe9af2006-11-30 19:26:14 -0800426 break;
427 }
428
429 if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
430 if (e->bitmask != 0) {
431 /* we make userspace set this right,
432 so there is no misunderstanding */
433 BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
434 "in distinguisher\n");
435 return -EINVAL;
436 }
437 if (i != NF_BR_NUMHOOKS)
438 newinfo->hook_entry[i] = (struct ebt_entries *)e;
439 if (left < sizeof(struct ebt_entries))
440 break;
441 offset += sizeof(struct ebt_entries);
442 } else {
443 if (left < sizeof(struct ebt_entry))
444 break;
445 if (left < e->next_offset)
446 break;
Florian Westphal1756de22010-02-15 18:15:55 +0100447 if (e->next_offset < sizeof(struct ebt_entry))
448 return -EINVAL;
Al Viro70fe9af2006-11-30 19:26:14 -0800449 offset += e->next_offset;
450 }
451 }
452 if (offset != limit) {
453 BUGPRINT("entries_size too small\n");
454 return -EINVAL;
455 }
Al Viroe4fd77d2006-11-30 19:26:35 -0800456
457 /* check if all valid hooks have a chain */
458 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
459 if (!newinfo->hook_entry[i] &&
460 (valid_hooks & (1 << i))) {
461 BUGPRINT("Valid hook without chain\n");
462 return -EINVAL;
463 }
464 }
Al Viro70fe9af2006-11-30 19:26:14 -0800465 return 0;
Al Viro22b440b2006-11-30 19:25:51 -0800466}
467
468/*
469 * this one is very careful, as it is the first function
470 * to parse the userspace data
471 */
472static inline int
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200473ebt_check_entry_size_and_hooks(const struct ebt_entry *e,
474 const struct ebt_table_info *newinfo,
Al Viro0e795532006-11-30 19:27:13 -0800475 unsigned int *n, unsigned int *cnt,
476 unsigned int *totalcnt, unsigned int *udc_cnt)
Al Viro22b440b2006-11-30 19:25:51 -0800477{
Al Viro22b440b2006-11-30 19:25:51 -0800478 int i;
479
480 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Viro0e795532006-11-30 19:27:13 -0800481 if ((void *)e == (void *)newinfo->hook_entry[i])
Al Viro22b440b2006-11-30 19:25:51 -0800482 break;
483 }
484 /* beginning of a new chain
485 if i == NF_BR_NUMHOOKS it must be a user defined chain */
486 if (i != NF_BR_NUMHOOKS || !e->bitmask) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 /* this checks if the previous chain has as many entries
488 as it said it has */
489 if (*n != *cnt) {
490 BUGPRINT("nentries does not equal the nr of entries "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900491 "in the chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 return -EINVAL;
493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 if (((struct ebt_entries *)e)->policy != EBT_DROP &&
495 ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
496 /* only RETURN from udc */
497 if (i != NF_BR_NUMHOOKS ||
498 ((struct ebt_entries *)e)->policy != EBT_RETURN) {
499 BUGPRINT("bad policy\n");
500 return -EINVAL;
501 }
502 }
503 if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
504 (*udc_cnt)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
506 BUGPRINT("counter_offset != totalcnt");
507 return -EINVAL;
508 }
509 *n = ((struct ebt_entries *)e)->nentries;
510 *cnt = 0;
511 return 0;
512 }
513 /* a plain old entry, heh */
514 if (sizeof(struct ebt_entry) > e->watchers_offset ||
515 e->watchers_offset > e->target_offset ||
516 e->target_offset >= e->next_offset) {
517 BUGPRINT("entry offsets not in right order\n");
518 return -EINVAL;
519 }
520 /* this is not checked anywhere else */
521 if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
522 BUGPRINT("target size too small\n");
523 return -EINVAL;
524 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 (*cnt)++;
526 (*totalcnt)++;
527 return 0;
528}
529
530struct ebt_cl_stack
531{
532 struct ebt_chainstack cs;
533 int from;
534 unsigned int hookmask;
535};
536
537/*
538 * we need these positions to check that the jumps to a different part of the
539 * entries is a jump to the beginning of a new chain.
540 */
541static inline int
542ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Viro177abc32006-11-30 19:27:32 -0800543 unsigned int *n, struct ebt_cl_stack *udc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544{
545 int i;
546
547 /* we're only interested in chain starts */
Al Viro40642f92006-11-30 19:24:12 -0800548 if (e->bitmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 return 0;
550 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
552 break;
553 }
554 /* only care about udc */
555 if (i != NF_BR_NUMHOOKS)
556 return 0;
557
558 udc[*n].cs.chaininfo = (struct ebt_entries *)e;
559 /* these initialisations are depended on later in check_chainloops() */
560 udc[*n].cs.n = 0;
561 udc[*n].hookmask = 0;
562
563 (*n)++;
564 return 0;
565}
566
567static inline int
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100568ebt_cleanup_match(struct ebt_entry_match *m, struct net *net, unsigned int *i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569{
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200570 struct xt_mtdtor_param par;
571
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 if (i && (*i)-- == 0)
573 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100575 par.net = net;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200576 par.match = m->u.match;
577 par.matchinfo = m->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200578 par.family = NFPROTO_BRIDGE;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200579 if (par.match->destroy != NULL)
580 par.match->destroy(&par);
581 module_put(par.match->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 return 0;
583}
584
585static inline int
Patrick McHardyadd67462010-02-03 13:45:12 +0100586ebt_cleanup_watcher(struct ebt_entry_watcher *w, struct net *net, unsigned int *i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200588 struct xt_tgdtor_param par;
589
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 if (i && (*i)-- == 0)
591 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
Patrick McHardyadd67462010-02-03 13:45:12 +0100593 par.net = net;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200594 par.target = w->u.watcher;
595 par.targinfo = w->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200596 par.family = NFPROTO_BRIDGE;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200597 if (par.target->destroy != NULL)
598 par.target->destroy(&par);
599 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 return 0;
601}
602
603static inline int
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100604ebt_cleanup_entry(struct ebt_entry *e, struct net *net, unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200606 struct xt_tgdtor_param par;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 struct ebt_entry_target *t;
608
Al Viro40642f92006-11-30 19:24:12 -0800609 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 return 0;
611 /* we're done */
612 if (cnt && (*cnt)-- == 0)
613 return 1;
Patrick McHardyadd67462010-02-03 13:45:12 +0100614 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, net, NULL);
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100615 EBT_MATCH_ITERATE(e, ebt_cleanup_match, net, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
Patrick McHardyadd67462010-02-03 13:45:12 +0100618 par.net = net;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200619 par.target = t->u.target;
620 par.targinfo = t->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200621 par.family = NFPROTO_BRIDGE;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200622 if (par.target->destroy != NULL)
623 par.target->destroy(&par);
624 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 return 0;
626}
627
628static inline int
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200629ebt_check_entry(struct ebt_entry *e, struct net *net,
630 const struct ebt_table_info *newinfo,
Al Virof7da79d2006-11-30 19:27:48 -0800631 const char *name, unsigned int *cnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
633{
634 struct ebt_entry_target *t;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200635 struct xt_target *target;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 unsigned int i, j, hook = 0, hookmask = 0;
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800637 size_t gap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 int ret;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200639 struct xt_mtchk_param mtpar;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200640 struct xt_tgchk_param tgpar;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
642 /* don't mess with the struct ebt_entries */
Al Viro40642f92006-11-30 19:24:12 -0800643 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 return 0;
645
646 if (e->bitmask & ~EBT_F_MASK) {
647 BUGPRINT("Unknown flag for bitmask\n");
648 return -EINVAL;
649 }
650 if (e->invflags & ~EBT_INV_MASK) {
651 BUGPRINT("Unknown flag for inv bitmask\n");
652 return -EINVAL;
653 }
654 if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
655 BUGPRINT("NOPROTO & 802_3 not allowed\n");
656 return -EINVAL;
657 }
658 /* what hook do we belong to? */
659 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Virof7da79d2006-11-30 19:27:48 -0800660 if (!newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 continue;
662 if ((char *)newinfo->hook_entry[i] < (char *)e)
663 hook = i;
664 else
665 break;
666 }
667 /* (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
668 a base chain */
669 if (i < NF_BR_NUMHOOKS)
670 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
671 else {
672 for (i = 0; i < udc_cnt; i++)
673 if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
674 break;
675 if (i == 0)
676 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
677 else
678 hookmask = cl_s[i - 1].hookmask;
679 }
680 i = 0;
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200681
Patrick McHardyadd67462010-02-03 13:45:12 +0100682 mtpar.net = tgpar.net = net;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200683 mtpar.table = tgpar.table = name;
684 mtpar.entryinfo = tgpar.entryinfo = e;
685 mtpar.hook_mask = tgpar.hook_mask = hookmask;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200686 mtpar.family = tgpar.family = NFPROTO_BRIDGE;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200687 ret = EBT_MATCH_ITERATE(e, ebt_check_match, &mtpar, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 if (ret != 0)
689 goto cleanup_matches;
690 j = 0;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200691 ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, &tgpar, &j);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 if (ret != 0)
693 goto cleanup_watchers;
694 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800695 gap = e->next_offset - e->target_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696
Jan Engelhardt043ef462008-10-08 11:35:15 +0200697 target = try_then_request_module(
698 xt_find_target(NFPROTO_BRIDGE, t->u.name, 0),
699 "ebt_%s", t->u.name);
700 if (IS_ERR(target)) {
701 ret = PTR_ERR(target);
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200702 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200703 } else if (target == NULL) {
704 ret = -ENOENT;
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200705 goto cleanup_watchers;
706 }
707
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 t->u.target = target;
709 if (t->u.target == &ebt_standard_target) {
Al Viro14197d52006-11-30 19:25:21 -0800710 if (gap < sizeof(struct ebt_standard_target)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 BUGPRINT("Standard target size too big\n");
712 ret = -EFAULT;
713 goto cleanup_watchers;
714 }
715 if (((struct ebt_standard_target *)t)->verdict <
716 -NUM_STANDARD_TARGETS) {
717 BUGPRINT("Invalid standard target\n");
718 ret = -EFAULT;
719 goto cleanup_watchers;
720 }
Jan Engelhardt18219d32008-10-08 11:35:13 +0200721 } else if (t->target_size > gap - sizeof(struct ebt_entry_target)) {
722 module_put(t->u.target->me);
723 ret = -EFAULT;
724 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200725 }
726
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200727 tgpar.target = target;
728 tgpar.targinfo = t->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200729 ret = xt_check_target(&tgpar, t->target_size,
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200730 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200731 if (ret < 0) {
732 module_put(target->me);
Jan Engelhardt18219d32008-10-08 11:35:13 +0200733 goto cleanup_watchers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 }
735 (*cnt)++;
736 return 0;
737cleanup_watchers:
Patrick McHardyadd67462010-02-03 13:45:12 +0100738 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, net, &j);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739cleanup_matches:
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100740 EBT_MATCH_ITERATE(e, ebt_cleanup_match, net, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 return ret;
742}
743
744/*
745 * checks for loops and sets the hook mask for udc
746 * the hook mask for udc tells us from which base chains the udc can be
747 * accessed. This mask is a parameter to the check() functions of the extensions
748 */
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200749static int check_chainloops(const struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 unsigned int udc_cnt, unsigned int hooknr, char *base)
751{
752 int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200753 const struct ebt_entry *e = (struct ebt_entry *)chain->data;
754 const struct ebt_entry_target *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755
756 while (pos < nentries || chain_nr != -1) {
757 /* end of udc, go back one 'recursion' step */
758 if (pos == nentries) {
759 /* put back values of the time when this chain was called */
760 e = cl_s[chain_nr].cs.e;
761 if (cl_s[chain_nr].from != -1)
762 nentries =
763 cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
764 else
765 nentries = chain->nentries;
766 pos = cl_s[chain_nr].cs.n;
767 /* make sure we won't see a loop that isn't one */
768 cl_s[chain_nr].cs.n = 0;
769 chain_nr = cl_s[chain_nr].from;
770 if (pos == nentries)
771 continue;
772 }
773 t = (struct ebt_entry_target *)
774 (((char *)e) + e->target_offset);
775 if (strcmp(t->u.name, EBT_STANDARD_TARGET))
776 goto letscontinue;
777 if (e->target_offset + sizeof(struct ebt_standard_target) >
778 e->next_offset) {
779 BUGPRINT("Standard target size too big\n");
780 return -1;
781 }
782 verdict = ((struct ebt_standard_target *)t)->verdict;
783 if (verdict >= 0) { /* jump to another chain */
784 struct ebt_entries *hlp2 =
785 (struct ebt_entries *)(base + verdict);
786 for (i = 0; i < udc_cnt; i++)
787 if (hlp2 == cl_s[i].cs.chaininfo)
788 break;
789 /* bad destination or loop */
790 if (i == udc_cnt) {
791 BUGPRINT("bad destination\n");
792 return -1;
793 }
794 if (cl_s[i].cs.n) {
795 BUGPRINT("loop\n");
796 return -1;
797 }
Al Viro98a08242006-11-30 19:24:49 -0800798 if (cl_s[i].hookmask & (1 << hooknr))
799 goto letscontinue;
800 /* this can't be 0, so the loop test is correct */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 cl_s[i].cs.n = pos + 1;
802 pos = 0;
Jan Engelhardt98e86402009-04-15 21:06:05 +0200803 cl_s[i].cs.e = ebt_next_entry(e);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 e = (struct ebt_entry *)(hlp2->data);
805 nentries = hlp2->nentries;
806 cl_s[i].from = chain_nr;
807 chain_nr = i;
808 /* this udc is accessible from the base chain for hooknr */
809 cl_s[i].hookmask |= (1 << hooknr);
810 continue;
811 }
812letscontinue:
Jan Engelhardt98e86402009-04-15 21:06:05 +0200813 e = ebt_next_entry(e);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 pos++;
815 }
816 return 0;
817}
818
819/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200820static int translate_table(struct net *net, const char *name,
Alexey Dobriyana83d8e82010-01-18 08:21:13 +0100821 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822{
823 unsigned int i, j, k, udc_cnt;
824 int ret;
825 struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
826
827 i = 0;
Al Viro1f072c92006-11-30 19:26:53 -0800828 while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 i++;
830 if (i == NF_BR_NUMHOOKS) {
831 BUGPRINT("No valid hooks specified\n");
832 return -EINVAL;
833 }
Al Viro1f072c92006-11-30 19:26:53 -0800834 if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 BUGPRINT("Chains don't start at beginning\n");
836 return -EINVAL;
837 }
838 /* make sure chains are ordered after each other in same order
839 as their corresponding hooks */
840 for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
Al Viro1f072c92006-11-30 19:26:53 -0800841 if (!newinfo->hook_entry[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 continue;
Al Viro1f072c92006-11-30 19:26:53 -0800843 if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 BUGPRINT("Hook order must be followed\n");
845 return -EINVAL;
846 }
847 i = j;
848 }
849
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 /* do some early checkings and initialize some things */
851 i = 0; /* holds the expected nr. of entries for the chain */
852 j = 0; /* holds the up to now counted entries for the chain */
853 k = 0; /* holds the total nr. of entries, should equal
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900854 newinfo->nentries afterwards */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
856 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro0e795532006-11-30 19:27:13 -0800857 ebt_check_entry_size_and_hooks, newinfo,
858 &i, &j, &k, &udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859
860 if (ret != 0)
861 return ret;
862
863 if (i != j) {
864 BUGPRINT("nentries does not equal the nr of entries in the "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900865 "(last) chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 return -EINVAL;
867 }
868 if (k != newinfo->nentries) {
869 BUGPRINT("Total nentries is wrong\n");
870 return -EINVAL;
871 }
872
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 /* get the location of the udc, put them in an array
874 while we're at it, allocate the chainstack */
875 if (udc_cnt) {
876 /* this will get free'd in do_replace()/ebt_register_table()
877 if an error occurs */
Jayachandran C7ad4d2f2006-04-11 17:25:38 -0700878 newinfo->chainstack =
Christoph Lameter53b8a312007-02-20 13:57:51 -0800879 vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 if (!newinfo->chainstack)
881 return -ENOMEM;
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700882 for_each_possible_cpu(i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 newinfo->chainstack[i] =
Jayachandran C18bc89a2006-04-20 00:14:49 -0700884 vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 if (!newinfo->chainstack[i]) {
886 while (i)
887 vfree(newinfo->chainstack[--i]);
888 vfree(newinfo->chainstack);
889 newinfo->chainstack = NULL;
890 return -ENOMEM;
891 }
892 }
893
Jayachandran C18bc89a2006-04-20 00:14:49 -0700894 cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 if (!cl_s)
896 return -ENOMEM;
897 i = 0; /* the i'th udc */
898 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro177abc32006-11-30 19:27:32 -0800899 ebt_get_udc_positions, newinfo, &i, cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 /* sanity check */
901 if (i != udc_cnt) {
902 BUGPRINT("i != udc_cnt\n");
903 vfree(cl_s);
904 return -EFAULT;
905 }
906 }
907
908 /* Check for loops */
909 for (i = 0; i < NF_BR_NUMHOOKS; i++)
Al Viro1f072c92006-11-30 19:26:53 -0800910 if (newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 if (check_chainloops(newinfo->hook_entry[i],
912 cl_s, udc_cnt, i, newinfo->entries)) {
James Lamanna68d31872005-06-22 22:12:57 -0700913 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 return -EINVAL;
915 }
916
Jan Engelhardt96de0e22007-10-19 23:21:04 +0200917 /* we now know the following (along with E=mc²):
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 - the nr of entries in each chain is right
919 - the size of the allocated space is right
920 - all valid hooks have a corresponding chain
921 - there are no loops
922 - wrong data can still be on the level of a single entry
923 - could be there are jumps to places that are not the
924 beginning of a chain. This can only occur in chains that
925 are not accessible from any base chains, so we don't care. */
926
927 /* used to know what we need to clean up if something goes wrong */
928 i = 0;
929 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Alexey Dobriyana83d8e82010-01-18 08:21:13 +0100930 ebt_check_entry, net, newinfo, name, &i, cl_s, udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 if (ret != 0) {
932 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100933 ebt_cleanup_entry, net, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 }
James Lamanna68d31872005-06-22 22:12:57 -0700935 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 return ret;
937}
938
939/* called under write_lock */
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200940static void get_counters(const struct ebt_counter *oldcounters,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 struct ebt_counter *counters, unsigned int nentries)
942{
943 int i, cpu;
944 struct ebt_counter *counter_base;
945
946 /* counters of cpu 0 */
947 memcpy(counters, oldcounters,
David S. Millerc8923c62005-10-13 14:41:23 -0700948 sizeof(struct ebt_counter) * nentries);
949
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 /* add other counters to those of cpu 0 */
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700951 for_each_possible_cpu(cpu) {
David S. Millerc8923c62005-10-13 14:41:23 -0700952 if (cpu == 0)
953 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
955 for (i = 0; i < nentries; i++) {
956 counters[i].pcnt += counter_base[i].pcnt;
957 counters[i].bcnt += counter_base[i].bcnt;
958 }
959 }
960}
961
962/* replace the table */
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200963static int do_replace(struct net *net, const void __user *user,
964 unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965{
966 int ret, i, countersize;
967 struct ebt_table_info *newinfo;
968 struct ebt_replace tmp;
969 struct ebt_table *t;
970 struct ebt_counter *counterstmp = NULL;
971 /* used to be able to unlock earlier */
972 struct ebt_table_info *table;
973
974 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
975 return -EFAULT;
976
977 if (len != sizeof(tmp) + tmp.entries_size) {
978 BUGPRINT("Wrong len argument\n");
979 return -EINVAL;
980 }
981
982 if (tmp.entries_size == 0) {
983 BUGPRINT("Entries_size never zero\n");
984 return -EINVAL;
985 }
Kirill Korotaevee4bb812006-02-04 02:16:56 -0800986 /* overflow check */
987 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
988 SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
989 return -ENOMEM;
990 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
991 return -ENOMEM;
992
Christoph Lameter53b8a312007-02-20 13:57:51 -0800993 countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -0700994 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 if (!newinfo)
996 return -ENOMEM;
997
998 if (countersize)
999 memset(newinfo->counters, 0, countersize);
1000
Kris Katterjohn8b3a7002006-01-11 15:56:43 -08001001 newinfo->entries = vmalloc(tmp.entries_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 if (!newinfo->entries) {
1003 ret = -ENOMEM;
1004 goto free_newinfo;
1005 }
1006 if (copy_from_user(
1007 newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
1008 BUGPRINT("Couldn't copy entries from userspace\n");
1009 ret = -EFAULT;
1010 goto free_entries;
1011 }
1012
1013 /* the user wants counters back
1014 the check on the size is done later, when we have the lock */
1015 if (tmp.num_counters) {
Jayachandran C18bc89a2006-04-20 00:14:49 -07001016 counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 if (!counterstmp) {
1018 ret = -ENOMEM;
1019 goto free_entries;
1020 }
1021 }
1022 else
1023 counterstmp = NULL;
1024
1025 /* this can get initialized by translate_table() */
1026 newinfo->chainstack = NULL;
Al Viro1bc23262006-11-30 19:28:08 -08001027 ret = ebt_verify_pointers(&tmp, newinfo);
1028 if (ret != 0)
1029 goto free_counterstmp;
1030
Alexey Dobriyana83d8e82010-01-18 08:21:13 +01001031 ret = translate_table(net, tmp.name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
1033 if (ret != 0)
1034 goto free_counterstmp;
1035
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001036 t = find_table_lock(net, tmp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 if (!t) {
1038 ret = -ENOENT;
1039 goto free_iterate;
1040 }
1041
1042 /* the table doesn't like it */
1043 if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
1044 goto free_unlock;
1045
1046 if (tmp.num_counters && tmp.num_counters != t->private->nentries) {
1047 BUGPRINT("Wrong nr. of counters requested\n");
1048 ret = -EINVAL;
1049 goto free_unlock;
1050 }
1051
1052 /* we have the mutex lock, so no danger in reading this pointer */
1053 table = t->private;
1054 /* make sure the table can only be rmmod'ed if it contains no rules */
1055 if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) {
1056 ret = -ENOENT;
1057 goto free_unlock;
1058 } else if (table->nentries && !newinfo->nentries)
1059 module_put(t->me);
1060 /* we need an atomic snapshot of the counters */
1061 write_lock_bh(&t->lock);
1062 if (tmp.num_counters)
1063 get_counters(t->private->counters, counterstmp,
1064 t->private->nentries);
1065
1066 t->private = newinfo;
1067 write_unlock_bh(&t->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001068 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 /* so, a user can change the chains while having messed up her counter
1070 allocation. Only reason why this is done is because this way the lock
1071 is held only once, while this doesn't bring the kernel into a
1072 dangerous state. */
1073 if (tmp.num_counters &&
1074 copy_to_user(tmp.counters, counterstmp,
1075 tmp.num_counters * sizeof(struct ebt_counter))) {
1076 BUGPRINT("Couldn't copy counters to userspace\n");
1077 ret = -EFAULT;
1078 }
1079 else
1080 ret = 0;
1081
1082 /* decrease module count and free resources */
1083 EBT_ENTRY_ITERATE(table->entries, table->entries_size,
Alexey Dobriyanf54e9362010-01-18 08:25:47 +01001084 ebt_cleanup_entry, net, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085
1086 vfree(table->entries);
1087 if (table->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001088 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 vfree(table->chainstack[i]);
1090 vfree(table->chainstack);
1091 }
1092 vfree(table);
1093
James Lamanna68d31872005-06-22 22:12:57 -07001094 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 return ret;
1096
1097free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001098 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099free_iterate:
1100 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Alexey Dobriyanf54e9362010-01-18 08:25:47 +01001101 ebt_cleanup_entry, net, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102free_counterstmp:
James Lamanna68d31872005-06-22 22:12:57 -07001103 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 /* can be initialized in translate_table() */
1105 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001106 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 vfree(newinfo->chainstack[i]);
1108 vfree(newinfo->chainstack);
1109 }
1110free_entries:
James Lamanna68d31872005-06-22 22:12:57 -07001111 vfree(newinfo->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112free_newinfo:
James Lamanna68d31872005-06-22 22:12:57 -07001113 vfree(newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 return ret;
1115}
1116
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001117struct ebt_table *
1118ebt_register_table(struct net *net, const struct ebt_table *input_table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119{
1120 struct ebt_table_info *newinfo;
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001121 struct ebt_table *t, *table;
Al Viro1e419cd2006-11-30 19:28:48 -08001122 struct ebt_replace_kernel *repl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 int ret, i, countersize;
Al Virodf07a812006-11-30 19:28:25 -08001124 void *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001126 if (input_table == NULL || (repl = input_table->table) == NULL ||
1127 repl->entries == 0 || repl->entries_size == 0 ||
1128 repl->counters != NULL || input_table->private != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 BUGPRINT("Bad table data for ebt_register_table!!!\n");
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001130 return ERR_PTR(-EINVAL);
1131 }
1132
1133 /* Don't add one table to multiple lists. */
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001134 table = kmemdup(input_table, sizeof(struct ebt_table), GFP_KERNEL);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001135 if (!table) {
1136 ret = -ENOMEM;
1137 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 }
1139
Christoph Lameter53b8a312007-02-20 13:57:51 -08001140 countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -07001141 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 ret = -ENOMEM;
1143 if (!newinfo)
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001144 goto free_table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145
Al Virodf07a812006-11-30 19:28:25 -08001146 p = vmalloc(repl->entries_size);
1147 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 goto free_newinfo;
1149
Al Virodf07a812006-11-30 19:28:25 -08001150 memcpy(p, repl->entries, repl->entries_size);
1151 newinfo->entries = p;
1152
1153 newinfo->entries_size = repl->entries_size;
1154 newinfo->nentries = repl->nentries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155
1156 if (countersize)
1157 memset(newinfo->counters, 0, countersize);
1158
1159 /* fill in newinfo and parse the entries */
1160 newinfo->chainstack = NULL;
Al Virodf07a812006-11-30 19:28:25 -08001161 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1162 if ((repl->valid_hooks & (1 << i)) == 0)
1163 newinfo->hook_entry[i] = NULL;
1164 else
1165 newinfo->hook_entry[i] = p +
1166 ((char *)repl->hook_entry[i] - repl->entries);
1167 }
Alexey Dobriyana83d8e82010-01-18 08:21:13 +01001168 ret = translate_table(net, repl->name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 if (ret != 0) {
1170 BUGPRINT("Translate_table failed\n");
1171 goto free_chainstack;
1172 }
1173
1174 if (table->check && table->check(newinfo, table->valid_hooks)) {
1175 BUGPRINT("The table doesn't like its own initial data, lol\n");
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001176 return ERR_PTR(-EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 }
1178
1179 table->private = newinfo;
1180 rwlock_init(&table->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001181 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 if (ret != 0)
1183 goto free_chainstack;
1184
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001185 list_for_each_entry(t, &net->xt.tables[NFPROTO_BRIDGE], list) {
Patrick McHardydf0933d2006-09-20 11:57:53 -07001186 if (strcmp(t->name, table->name) == 0) {
1187 ret = -EEXIST;
1188 BUGPRINT("Table name already exists\n");
1189 goto free_unlock;
1190 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 }
1192
1193 /* Hold a reference count if the chains aren't empty */
1194 if (newinfo->nentries && !try_module_get(table->me)) {
1195 ret = -ENOENT;
1196 goto free_unlock;
1197 }
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001198 list_add(&table->list, &net->xt.tables[NFPROTO_BRIDGE]);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001199 mutex_unlock(&ebt_mutex);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001200 return table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001202 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203free_chainstack:
1204 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001205 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 vfree(newinfo->chainstack[i]);
1207 vfree(newinfo->chainstack);
1208 }
1209 vfree(newinfo->entries);
1210free_newinfo:
1211 vfree(newinfo);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001212free_table:
1213 kfree(table);
1214out:
1215 return ERR_PTR(ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216}
1217
Alexey Dobriyanf54e9362010-01-18 08:25:47 +01001218void ebt_unregister_table(struct net *net, struct ebt_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219{
1220 int i;
1221
1222 if (!table) {
1223 BUGPRINT("Request to unregister NULL table!!!\n");
1224 return;
1225 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001226 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001227 list_del(&table->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001228 mutex_unlock(&ebt_mutex);
Alexey Dobriyandbcdf852008-11-04 14:28:04 +01001229 EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size,
Alexey Dobriyanf54e9362010-01-18 08:25:47 +01001230 ebt_cleanup_entry, net, NULL);
Alexey Dobriyandbcdf852008-11-04 14:28:04 +01001231 if (table->private->nentries)
1232 module_put(table->me);
James Lamanna68d31872005-06-22 22:12:57 -07001233 vfree(table->private->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 if (table->private->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001235 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 vfree(table->private->chainstack[i]);
1237 vfree(table->private->chainstack);
1238 }
1239 vfree(table->private);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001240 kfree(table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241}
1242
1243/* userspace just supplied us with counters */
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +02001244static int update_counters(struct net *net, const void __user *user,
1245 unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246{
1247 int i, ret;
1248 struct ebt_counter *tmp;
1249 struct ebt_replace hlp;
1250 struct ebt_table *t;
1251
1252 if (copy_from_user(&hlp, user, sizeof(hlp)))
1253 return -EFAULT;
1254
1255 if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
1256 return -EINVAL;
1257 if (hlp.num_counters == 0)
1258 return -EINVAL;
1259
Jayachandran C18bc89a2006-04-20 00:14:49 -07001260 if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 MEMPRINT("Update_counters && nomemory\n");
1262 return -ENOMEM;
1263 }
1264
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001265 t = find_table_lock(net, hlp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 if (!t)
1267 goto free_tmp;
1268
1269 if (hlp.num_counters != t->private->nentries) {
1270 BUGPRINT("Wrong nr of counters\n");
1271 ret = -EINVAL;
1272 goto unlock_mutex;
1273 }
1274
1275 if ( copy_from_user(tmp, hlp.counters,
1276 hlp.num_counters * sizeof(struct ebt_counter)) ) {
1277 BUGPRINT("Updata_counters && !cfu\n");
1278 ret = -EFAULT;
1279 goto unlock_mutex;
1280 }
1281
1282 /* we want an atomic add of the counters */
1283 write_lock_bh(&t->lock);
1284
1285 /* we add to the counters of the first cpu */
1286 for (i = 0; i < hlp.num_counters; i++) {
1287 t->private->counters[i].pcnt += tmp[i].pcnt;
1288 t->private->counters[i].bcnt += tmp[i].bcnt;
1289 }
1290
1291 write_unlock_bh(&t->lock);
1292 ret = 0;
1293unlock_mutex:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001294 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295free_tmp:
1296 vfree(tmp);
1297 return ret;
1298}
1299
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +02001300static inline int ebt_make_matchname(const struct ebt_entry_match *m,
1301 const char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302{
Al Viro1e419cd2006-11-30 19:28:48 -08001303 char __user *hlp = ubase + ((char *)m - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
1305 return -EFAULT;
1306 return 0;
1307}
1308
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +02001309static inline int ebt_make_watchername(const struct ebt_entry_watcher *w,
1310 const char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311{
Al Viro1e419cd2006-11-30 19:28:48 -08001312 char __user *hlp = ubase + ((char *)w - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
1314 return -EFAULT;
1315 return 0;
1316}
1317
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +02001318static inline int
1319ebt_make_names(struct ebt_entry *e, const char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320{
1321 int ret;
Al Viro1e419cd2006-11-30 19:28:48 -08001322 char __user *hlp;
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +02001323 const struct ebt_entry_target *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324
Al Viro40642f92006-11-30 19:24:12 -08001325 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 return 0;
1327
Al Viro1e419cd2006-11-30 19:28:48 -08001328 hlp = ubase + (((char *)e + e->target_offset) - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +09001330
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
1332 if (ret != 0)
1333 return ret;
1334 ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
1335 if (ret != 0)
1336 return ret;
1337 if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
1338 return -EFAULT;
1339 return 0;
1340}
1341
Ingo Molnar57b47a52006-03-20 22:35:41 -08001342/* called with ebt_mutex locked */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343static int copy_everything_to_user(struct ebt_table *t, void __user *user,
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +02001344 const int *len, int cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345{
1346 struct ebt_replace tmp;
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +02001347 struct ebt_counter *counterstmp;
1348 const struct ebt_counter *oldcounters;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 unsigned int entries_size, nentries;
1350 char *entries;
1351
1352 if (cmd == EBT_SO_GET_ENTRIES) {
1353 entries_size = t->private->entries_size;
1354 nentries = t->private->nentries;
1355 entries = t->private->entries;
1356 oldcounters = t->private->counters;
1357 } else {
1358 entries_size = t->table->entries_size;
1359 nentries = t->table->nentries;
1360 entries = t->table->entries;
1361 oldcounters = t->table->counters;
1362 }
1363
1364 if (copy_from_user(&tmp, user, sizeof(tmp))) {
1365 BUGPRINT("Cfu didn't work\n");
1366 return -EFAULT;
1367 }
1368
1369 if (*len != sizeof(struct ebt_replace) + entries_size +
1370 (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
1371 BUGPRINT("Wrong size\n");
1372 return -EINVAL;
1373 }
1374
1375 if (tmp.nentries != nentries) {
1376 BUGPRINT("Nentries wrong\n");
1377 return -EINVAL;
1378 }
1379
1380 if (tmp.entries_size != entries_size) {
1381 BUGPRINT("Wrong size\n");
1382 return -EINVAL;
1383 }
1384
1385 /* userspace might not need the counters */
1386 if (tmp.num_counters) {
1387 if (tmp.num_counters != nentries) {
1388 BUGPRINT("Num_counters wrong\n");
1389 return -EINVAL;
1390 }
Jayachandran C18bc89a2006-04-20 00:14:49 -07001391 counterstmp = vmalloc(nentries * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 if (!counterstmp) {
1393 MEMPRINT("Couldn't copy counters, out of memory\n");
1394 return -ENOMEM;
1395 }
1396 write_lock_bh(&t->lock);
1397 get_counters(oldcounters, counterstmp, nentries);
1398 write_unlock_bh(&t->lock);
1399
1400 if (copy_to_user(tmp.counters, counterstmp,
1401 nentries * sizeof(struct ebt_counter))) {
1402 BUGPRINT("Couldn't copy counters to userspace\n");
1403 vfree(counterstmp);
1404 return -EFAULT;
1405 }
1406 vfree(counterstmp);
1407 }
1408
1409 if (copy_to_user(tmp.entries, entries, entries_size)) {
1410 BUGPRINT("Couldn't copy entries to userspace\n");
1411 return -EFAULT;
1412 }
1413 /* set the match/watcher/target names right */
1414 return EBT_ENTRY_ITERATE(entries, entries_size,
1415 ebt_make_names, entries, tmp.entries);
1416}
1417
1418static int do_ebt_set_ctl(struct sock *sk,
1419 int cmd, void __user *user, unsigned int len)
1420{
1421 int ret;
1422
Florian Westphaldce766a2010-01-08 17:31:24 +01001423 if (!capable(CAP_NET_ADMIN))
1424 return -EPERM;
1425
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 switch(cmd) {
1427 case EBT_SO_SET_ENTRIES:
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001428 ret = do_replace(sock_net(sk), user, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 break;
1430 case EBT_SO_SET_COUNTERS:
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001431 ret = update_counters(sock_net(sk), user, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 break;
1433 default:
1434 ret = -EINVAL;
1435 }
1436 return ret;
1437}
1438
1439static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1440{
1441 int ret;
1442 struct ebt_replace tmp;
1443 struct ebt_table *t;
1444
Florian Westphaldce766a2010-01-08 17:31:24 +01001445 if (!capable(CAP_NET_ADMIN))
1446 return -EPERM;
1447
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 if (copy_from_user(&tmp, user, sizeof(tmp)))
1449 return -EFAULT;
1450
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001451 t = find_table_lock(sock_net(sk), tmp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 if (!t)
1453 return ret;
1454
1455 switch(cmd) {
1456 case EBT_SO_GET_INFO:
1457 case EBT_SO_GET_INIT_INFO:
1458 if (*len != sizeof(struct ebt_replace)){
1459 ret = -EINVAL;
Ingo Molnar57b47a52006-03-20 22:35:41 -08001460 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 break;
1462 }
1463 if (cmd == EBT_SO_GET_INFO) {
1464 tmp.nentries = t->private->nentries;
1465 tmp.entries_size = t->private->entries_size;
1466 tmp.valid_hooks = t->valid_hooks;
1467 } else {
1468 tmp.nentries = t->table->nentries;
1469 tmp.entries_size = t->table->entries_size;
1470 tmp.valid_hooks = t->table->valid_hooks;
1471 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001472 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 if (copy_to_user(user, &tmp, *len) != 0){
1474 BUGPRINT("c2u Didn't work\n");
1475 ret = -EFAULT;
1476 break;
1477 }
1478 ret = 0;
1479 break;
1480
1481 case EBT_SO_GET_ENTRIES:
1482 case EBT_SO_GET_INIT_ENTRIES:
1483 ret = copy_everything_to_user(t, user, len, cmd);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001484 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 break;
1486
1487 default:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001488 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 ret = -EINVAL;
1490 }
1491
1492 return ret;
1493}
1494
1495static struct nf_sockopt_ops ebt_sockopts =
Andrew Morton74ca4e5a2006-03-20 22:55:02 -08001496{
1497 .pf = PF_INET,
1498 .set_optmin = EBT_BASE_CTL,
1499 .set_optmax = EBT_SO_SET_MAX + 1,
1500 .set = do_ebt_set_ctl,
1501 .get_optmin = EBT_BASE_CTL,
1502 .get_optmax = EBT_SO_GET_MAX + 1,
1503 .get = do_ebt_get_ctl,
Neil Horman16fcec32007-09-11 11:28:26 +02001504 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505};
1506
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001507static int __init ebtables_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508{
1509 int ret;
1510
Jan Engelhardt043ef462008-10-08 11:35:15 +02001511 ret = xt_register_target(&ebt_standard_target);
1512 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 return ret;
Jan Engelhardt043ef462008-10-08 11:35:15 +02001514 ret = nf_register_sockopt(&ebt_sockopts);
1515 if (ret < 0) {
1516 xt_unregister_target(&ebt_standard_target);
1517 return ret;
1518 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519
Patrick McHardya887c1c2007-07-14 20:46:15 -07001520 printk(KERN_INFO "Ebtables v2.0 registered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 return 0;
1522}
1523
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001524static void __exit ebtables_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525{
1526 nf_unregister_sockopt(&ebt_sockopts);
Jan Engelhardt043ef462008-10-08 11:35:15 +02001527 xt_unregister_target(&ebt_standard_target);
Patrick McHardya887c1c2007-07-14 20:46:15 -07001528 printk(KERN_INFO "Ebtables v2.0 unregistered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529}
1530
1531EXPORT_SYMBOL(ebt_register_table);
1532EXPORT_SYMBOL(ebt_unregister_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533EXPORT_SYMBOL(ebt_do_table);
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001534module_init(ebtables_init);
1535module_exit(ebtables_fini);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536MODULE_LICENSE("GPL");