blob: bcdf02d866b8d879f658ea20a635ed0a51836b08 [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;
447 offset += e->next_offset;
448 }
449 }
450 if (offset != limit) {
451 BUGPRINT("entries_size too small\n");
452 return -EINVAL;
453 }
Al Viroe4fd77d2006-11-30 19:26:35 -0800454
455 /* check if all valid hooks have a chain */
456 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
457 if (!newinfo->hook_entry[i] &&
458 (valid_hooks & (1 << i))) {
459 BUGPRINT("Valid hook without chain\n");
460 return -EINVAL;
461 }
462 }
Al Viro70fe9af2006-11-30 19:26:14 -0800463 return 0;
Al Viro22b440b2006-11-30 19:25:51 -0800464}
465
466/*
467 * this one is very careful, as it is the first function
468 * to parse the userspace data
469 */
470static inline int
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200471ebt_check_entry_size_and_hooks(const struct ebt_entry *e,
472 const struct ebt_table_info *newinfo,
Al Viro0e795532006-11-30 19:27:13 -0800473 unsigned int *n, unsigned int *cnt,
474 unsigned int *totalcnt, unsigned int *udc_cnt)
Al Viro22b440b2006-11-30 19:25:51 -0800475{
Al Viro22b440b2006-11-30 19:25:51 -0800476 int i;
477
478 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Viro0e795532006-11-30 19:27:13 -0800479 if ((void *)e == (void *)newinfo->hook_entry[i])
Al Viro22b440b2006-11-30 19:25:51 -0800480 break;
481 }
482 /* beginning of a new chain
483 if i == NF_BR_NUMHOOKS it must be a user defined chain */
484 if (i != NF_BR_NUMHOOKS || !e->bitmask) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 /* this checks if the previous chain has as many entries
486 as it said it has */
487 if (*n != *cnt) {
488 BUGPRINT("nentries does not equal the nr of entries "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900489 "in the chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 return -EINVAL;
491 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 if (((struct ebt_entries *)e)->policy != EBT_DROP &&
493 ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
494 /* only RETURN from udc */
495 if (i != NF_BR_NUMHOOKS ||
496 ((struct ebt_entries *)e)->policy != EBT_RETURN) {
497 BUGPRINT("bad policy\n");
498 return -EINVAL;
499 }
500 }
501 if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
502 (*udc_cnt)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
504 BUGPRINT("counter_offset != totalcnt");
505 return -EINVAL;
506 }
507 *n = ((struct ebt_entries *)e)->nentries;
508 *cnt = 0;
509 return 0;
510 }
511 /* a plain old entry, heh */
512 if (sizeof(struct ebt_entry) > e->watchers_offset ||
513 e->watchers_offset > e->target_offset ||
514 e->target_offset >= e->next_offset) {
515 BUGPRINT("entry offsets not in right order\n");
516 return -EINVAL;
517 }
518 /* this is not checked anywhere else */
519 if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
520 BUGPRINT("target size too small\n");
521 return -EINVAL;
522 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 (*cnt)++;
524 (*totalcnt)++;
525 return 0;
526}
527
528struct ebt_cl_stack
529{
530 struct ebt_chainstack cs;
531 int from;
532 unsigned int hookmask;
533};
534
535/*
536 * we need these positions to check that the jumps to a different part of the
537 * entries is a jump to the beginning of a new chain.
538 */
539static inline int
540ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Viro177abc32006-11-30 19:27:32 -0800541 unsigned int *n, struct ebt_cl_stack *udc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542{
543 int i;
544
545 /* we're only interested in chain starts */
Al Viro40642f92006-11-30 19:24:12 -0800546 if (e->bitmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 return 0;
548 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
550 break;
551 }
552 /* only care about udc */
553 if (i != NF_BR_NUMHOOKS)
554 return 0;
555
556 udc[*n].cs.chaininfo = (struct ebt_entries *)e;
557 /* these initialisations are depended on later in check_chainloops() */
558 udc[*n].cs.n = 0;
559 udc[*n].hookmask = 0;
560
561 (*n)++;
562 return 0;
563}
564
565static inline int
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100566ebt_cleanup_match(struct ebt_entry_match *m, struct net *net, unsigned int *i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567{
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200568 struct xt_mtdtor_param par;
569
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 if (i && (*i)-- == 0)
571 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100573 par.net = net;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200574 par.match = m->u.match;
575 par.matchinfo = m->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200576 par.family = NFPROTO_BRIDGE;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200577 if (par.match->destroy != NULL)
578 par.match->destroy(&par);
579 module_put(par.match->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 return 0;
581}
582
583static inline int
Patrick McHardyadd67462010-02-03 13:45:12 +0100584ebt_cleanup_watcher(struct ebt_entry_watcher *w, struct net *net, unsigned int *i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200586 struct xt_tgdtor_param par;
587
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 if (i && (*i)-- == 0)
589 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
Patrick McHardyadd67462010-02-03 13:45:12 +0100591 par.net = net;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200592 par.target = w->u.watcher;
593 par.targinfo = w->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200594 par.family = NFPROTO_BRIDGE;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200595 if (par.target->destroy != NULL)
596 par.target->destroy(&par);
597 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 return 0;
599}
600
601static inline int
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100602ebt_cleanup_entry(struct ebt_entry *e, struct net *net, unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200604 struct xt_tgdtor_param par;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 struct ebt_entry_target *t;
606
Al Viro40642f92006-11-30 19:24:12 -0800607 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 return 0;
609 /* we're done */
610 if (cnt && (*cnt)-- == 0)
611 return 1;
Patrick McHardyadd67462010-02-03 13:45:12 +0100612 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, net, NULL);
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100613 EBT_MATCH_ITERATE(e, ebt_cleanup_match, net, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
Patrick McHardyadd67462010-02-03 13:45:12 +0100616 par.net = net;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200617 par.target = t->u.target;
618 par.targinfo = t->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200619 par.family = NFPROTO_BRIDGE;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200620 if (par.target->destroy != NULL)
621 par.target->destroy(&par);
622 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 return 0;
624}
625
626static inline int
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200627ebt_check_entry(struct ebt_entry *e, struct net *net,
628 const struct ebt_table_info *newinfo,
Al Virof7da79d2006-11-30 19:27:48 -0800629 const char *name, unsigned int *cnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
631{
632 struct ebt_entry_target *t;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200633 struct xt_target *target;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 unsigned int i, j, hook = 0, hookmask = 0;
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800635 size_t gap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 int ret;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200637 struct xt_mtchk_param mtpar;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200638 struct xt_tgchk_param tgpar;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
640 /* don't mess with the struct ebt_entries */
Al Viro40642f92006-11-30 19:24:12 -0800641 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 return 0;
643
644 if (e->bitmask & ~EBT_F_MASK) {
645 BUGPRINT("Unknown flag for bitmask\n");
646 return -EINVAL;
647 }
648 if (e->invflags & ~EBT_INV_MASK) {
649 BUGPRINT("Unknown flag for inv bitmask\n");
650 return -EINVAL;
651 }
652 if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
653 BUGPRINT("NOPROTO & 802_3 not allowed\n");
654 return -EINVAL;
655 }
656 /* what hook do we belong to? */
657 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Virof7da79d2006-11-30 19:27:48 -0800658 if (!newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 continue;
660 if ((char *)newinfo->hook_entry[i] < (char *)e)
661 hook = i;
662 else
663 break;
664 }
665 /* (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
666 a base chain */
667 if (i < NF_BR_NUMHOOKS)
668 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
669 else {
670 for (i = 0; i < udc_cnt; i++)
671 if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
672 break;
673 if (i == 0)
674 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
675 else
676 hookmask = cl_s[i - 1].hookmask;
677 }
678 i = 0;
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200679
Patrick McHardyadd67462010-02-03 13:45:12 +0100680 mtpar.net = tgpar.net = net;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200681 mtpar.table = tgpar.table = name;
682 mtpar.entryinfo = tgpar.entryinfo = e;
683 mtpar.hook_mask = tgpar.hook_mask = hookmask;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200684 mtpar.family = tgpar.family = NFPROTO_BRIDGE;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200685 ret = EBT_MATCH_ITERATE(e, ebt_check_match, &mtpar, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 if (ret != 0)
687 goto cleanup_matches;
688 j = 0;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200689 ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, &tgpar, &j);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 if (ret != 0)
691 goto cleanup_watchers;
692 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800693 gap = e->next_offset - e->target_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
Jan Engelhardt043ef462008-10-08 11:35:15 +0200695 target = try_then_request_module(
696 xt_find_target(NFPROTO_BRIDGE, t->u.name, 0),
697 "ebt_%s", t->u.name);
698 if (IS_ERR(target)) {
699 ret = PTR_ERR(target);
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200700 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200701 } else if (target == NULL) {
702 ret = -ENOENT;
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200703 goto cleanup_watchers;
704 }
705
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 t->u.target = target;
707 if (t->u.target == &ebt_standard_target) {
Al Viro14197d52006-11-30 19:25:21 -0800708 if (gap < sizeof(struct ebt_standard_target)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 BUGPRINT("Standard target size too big\n");
710 ret = -EFAULT;
711 goto cleanup_watchers;
712 }
713 if (((struct ebt_standard_target *)t)->verdict <
714 -NUM_STANDARD_TARGETS) {
715 BUGPRINT("Invalid standard target\n");
716 ret = -EFAULT;
717 goto cleanup_watchers;
718 }
Jan Engelhardt18219d32008-10-08 11:35:13 +0200719 } else if (t->target_size > gap - sizeof(struct ebt_entry_target)) {
720 module_put(t->u.target->me);
721 ret = -EFAULT;
722 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200723 }
724
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200725 tgpar.target = target;
726 tgpar.targinfo = t->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200727 ret = xt_check_target(&tgpar, t->target_size,
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200728 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200729 if (ret < 0) {
730 module_put(target->me);
Jan Engelhardt18219d32008-10-08 11:35:13 +0200731 goto cleanup_watchers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 }
733 (*cnt)++;
734 return 0;
735cleanup_watchers:
Patrick McHardyadd67462010-02-03 13:45:12 +0100736 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, net, &j);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737cleanup_matches:
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100738 EBT_MATCH_ITERATE(e, ebt_cleanup_match, net, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 return ret;
740}
741
742/*
743 * checks for loops and sets the hook mask for udc
744 * the hook mask for udc tells us from which base chains the udc can be
745 * accessed. This mask is a parameter to the check() functions of the extensions
746 */
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200747static int check_chainloops(const struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 unsigned int udc_cnt, unsigned int hooknr, char *base)
749{
750 int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200751 const struct ebt_entry *e = (struct ebt_entry *)chain->data;
752 const struct ebt_entry_target *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
754 while (pos < nentries || chain_nr != -1) {
755 /* end of udc, go back one 'recursion' step */
756 if (pos == nentries) {
757 /* put back values of the time when this chain was called */
758 e = cl_s[chain_nr].cs.e;
759 if (cl_s[chain_nr].from != -1)
760 nentries =
761 cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
762 else
763 nentries = chain->nentries;
764 pos = cl_s[chain_nr].cs.n;
765 /* make sure we won't see a loop that isn't one */
766 cl_s[chain_nr].cs.n = 0;
767 chain_nr = cl_s[chain_nr].from;
768 if (pos == nentries)
769 continue;
770 }
771 t = (struct ebt_entry_target *)
772 (((char *)e) + e->target_offset);
773 if (strcmp(t->u.name, EBT_STANDARD_TARGET))
774 goto letscontinue;
775 if (e->target_offset + sizeof(struct ebt_standard_target) >
776 e->next_offset) {
777 BUGPRINT("Standard target size too big\n");
778 return -1;
779 }
780 verdict = ((struct ebt_standard_target *)t)->verdict;
781 if (verdict >= 0) { /* jump to another chain */
782 struct ebt_entries *hlp2 =
783 (struct ebt_entries *)(base + verdict);
784 for (i = 0; i < udc_cnt; i++)
785 if (hlp2 == cl_s[i].cs.chaininfo)
786 break;
787 /* bad destination or loop */
788 if (i == udc_cnt) {
789 BUGPRINT("bad destination\n");
790 return -1;
791 }
792 if (cl_s[i].cs.n) {
793 BUGPRINT("loop\n");
794 return -1;
795 }
Al Viro98a08242006-11-30 19:24:49 -0800796 if (cl_s[i].hookmask & (1 << hooknr))
797 goto letscontinue;
798 /* this can't be 0, so the loop test is correct */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 cl_s[i].cs.n = pos + 1;
800 pos = 0;
Jan Engelhardt98e86402009-04-15 21:06:05 +0200801 cl_s[i].cs.e = ebt_next_entry(e);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 e = (struct ebt_entry *)(hlp2->data);
803 nentries = hlp2->nentries;
804 cl_s[i].from = chain_nr;
805 chain_nr = i;
806 /* this udc is accessible from the base chain for hooknr */
807 cl_s[i].hookmask |= (1 << hooknr);
808 continue;
809 }
810letscontinue:
Jan Engelhardt98e86402009-04-15 21:06:05 +0200811 e = ebt_next_entry(e);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 pos++;
813 }
814 return 0;
815}
816
817/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200818static int translate_table(struct net *net, const char *name,
Alexey Dobriyana83d8e82010-01-18 08:21:13 +0100819 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820{
821 unsigned int i, j, k, udc_cnt;
822 int ret;
823 struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
824
825 i = 0;
Al Viro1f072c92006-11-30 19:26:53 -0800826 while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 i++;
828 if (i == NF_BR_NUMHOOKS) {
829 BUGPRINT("No valid hooks specified\n");
830 return -EINVAL;
831 }
Al Viro1f072c92006-11-30 19:26:53 -0800832 if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 BUGPRINT("Chains don't start at beginning\n");
834 return -EINVAL;
835 }
836 /* make sure chains are ordered after each other in same order
837 as their corresponding hooks */
838 for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
Al Viro1f072c92006-11-30 19:26:53 -0800839 if (!newinfo->hook_entry[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 continue;
Al Viro1f072c92006-11-30 19:26:53 -0800841 if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 BUGPRINT("Hook order must be followed\n");
843 return -EINVAL;
844 }
845 i = j;
846 }
847
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 /* do some early checkings and initialize some things */
849 i = 0; /* holds the expected nr. of entries for the chain */
850 j = 0; /* holds the up to now counted entries for the chain */
851 k = 0; /* holds the total nr. of entries, should equal
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900852 newinfo->nentries afterwards */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
854 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro0e795532006-11-30 19:27:13 -0800855 ebt_check_entry_size_and_hooks, newinfo,
856 &i, &j, &k, &udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857
858 if (ret != 0)
859 return ret;
860
861 if (i != j) {
862 BUGPRINT("nentries does not equal the nr of entries in the "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900863 "(last) chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 return -EINVAL;
865 }
866 if (k != newinfo->nentries) {
867 BUGPRINT("Total nentries is wrong\n");
868 return -EINVAL;
869 }
870
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 /* get the location of the udc, put them in an array
872 while we're at it, allocate the chainstack */
873 if (udc_cnt) {
874 /* this will get free'd in do_replace()/ebt_register_table()
875 if an error occurs */
Jayachandran C7ad4d2f2006-04-11 17:25:38 -0700876 newinfo->chainstack =
Christoph Lameter53b8a312007-02-20 13:57:51 -0800877 vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 if (!newinfo->chainstack)
879 return -ENOMEM;
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700880 for_each_possible_cpu(i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 newinfo->chainstack[i] =
Jayachandran C18bc89a2006-04-20 00:14:49 -0700882 vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 if (!newinfo->chainstack[i]) {
884 while (i)
885 vfree(newinfo->chainstack[--i]);
886 vfree(newinfo->chainstack);
887 newinfo->chainstack = NULL;
888 return -ENOMEM;
889 }
890 }
891
Jayachandran C18bc89a2006-04-20 00:14:49 -0700892 cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 if (!cl_s)
894 return -ENOMEM;
895 i = 0; /* the i'th udc */
896 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro177abc32006-11-30 19:27:32 -0800897 ebt_get_udc_positions, newinfo, &i, cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 /* sanity check */
899 if (i != udc_cnt) {
900 BUGPRINT("i != udc_cnt\n");
901 vfree(cl_s);
902 return -EFAULT;
903 }
904 }
905
906 /* Check for loops */
907 for (i = 0; i < NF_BR_NUMHOOKS; i++)
Al Viro1f072c92006-11-30 19:26:53 -0800908 if (newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 if (check_chainloops(newinfo->hook_entry[i],
910 cl_s, udc_cnt, i, newinfo->entries)) {
James Lamanna68d31872005-06-22 22:12:57 -0700911 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 return -EINVAL;
913 }
914
Jan Engelhardt96de0e22007-10-19 23:21:04 +0200915 /* we now know the following (along with E=mc²):
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 - the nr of entries in each chain is right
917 - the size of the allocated space is right
918 - all valid hooks have a corresponding chain
919 - there are no loops
920 - wrong data can still be on the level of a single entry
921 - could be there are jumps to places that are not the
922 beginning of a chain. This can only occur in chains that
923 are not accessible from any base chains, so we don't care. */
924
925 /* used to know what we need to clean up if something goes wrong */
926 i = 0;
927 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Alexey Dobriyana83d8e82010-01-18 08:21:13 +0100928 ebt_check_entry, net, newinfo, name, &i, cl_s, udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 if (ret != 0) {
930 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100931 ebt_cleanup_entry, net, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 }
James Lamanna68d31872005-06-22 22:12:57 -0700933 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 return ret;
935}
936
937/* called under write_lock */
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200938static void get_counters(const struct ebt_counter *oldcounters,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 struct ebt_counter *counters, unsigned int nentries)
940{
941 int i, cpu;
942 struct ebt_counter *counter_base;
943
944 /* counters of cpu 0 */
945 memcpy(counters, oldcounters,
David S. Millerc8923c62005-10-13 14:41:23 -0700946 sizeof(struct ebt_counter) * nentries);
947
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 /* add other counters to those of cpu 0 */
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700949 for_each_possible_cpu(cpu) {
David S. Millerc8923c62005-10-13 14:41:23 -0700950 if (cpu == 0)
951 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
953 for (i = 0; i < nentries; i++) {
954 counters[i].pcnt += counter_base[i].pcnt;
955 counters[i].bcnt += counter_base[i].bcnt;
956 }
957 }
958}
959
960/* replace the table */
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200961static int do_replace(struct net *net, const void __user *user,
962 unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963{
964 int ret, i, countersize;
965 struct ebt_table_info *newinfo;
966 struct ebt_replace tmp;
967 struct ebt_table *t;
968 struct ebt_counter *counterstmp = NULL;
969 /* used to be able to unlock earlier */
970 struct ebt_table_info *table;
971
972 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
973 return -EFAULT;
974
975 if (len != sizeof(tmp) + tmp.entries_size) {
976 BUGPRINT("Wrong len argument\n");
977 return -EINVAL;
978 }
979
980 if (tmp.entries_size == 0) {
981 BUGPRINT("Entries_size never zero\n");
982 return -EINVAL;
983 }
Kirill Korotaevee4bb812006-02-04 02:16:56 -0800984 /* overflow check */
985 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
986 SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
987 return -ENOMEM;
988 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
989 return -ENOMEM;
990
Christoph Lameter53b8a312007-02-20 13:57:51 -0800991 countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -0700992 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 if (!newinfo)
994 return -ENOMEM;
995
996 if (countersize)
997 memset(newinfo->counters, 0, countersize);
998
Kris Katterjohn8b3a7002006-01-11 15:56:43 -0800999 newinfo->entries = vmalloc(tmp.entries_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 if (!newinfo->entries) {
1001 ret = -ENOMEM;
1002 goto free_newinfo;
1003 }
1004 if (copy_from_user(
1005 newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
1006 BUGPRINT("Couldn't copy entries from userspace\n");
1007 ret = -EFAULT;
1008 goto free_entries;
1009 }
1010
1011 /* the user wants counters back
1012 the check on the size is done later, when we have the lock */
1013 if (tmp.num_counters) {
Jayachandran C18bc89a2006-04-20 00:14:49 -07001014 counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 if (!counterstmp) {
1016 ret = -ENOMEM;
1017 goto free_entries;
1018 }
1019 }
1020 else
1021 counterstmp = NULL;
1022
1023 /* this can get initialized by translate_table() */
1024 newinfo->chainstack = NULL;
Al Viro1bc23262006-11-30 19:28:08 -08001025 ret = ebt_verify_pointers(&tmp, newinfo);
1026 if (ret != 0)
1027 goto free_counterstmp;
1028
Alexey Dobriyana83d8e82010-01-18 08:21:13 +01001029 ret = translate_table(net, tmp.name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030
1031 if (ret != 0)
1032 goto free_counterstmp;
1033
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001034 t = find_table_lock(net, tmp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 if (!t) {
1036 ret = -ENOENT;
1037 goto free_iterate;
1038 }
1039
1040 /* the table doesn't like it */
1041 if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
1042 goto free_unlock;
1043
1044 if (tmp.num_counters && tmp.num_counters != t->private->nentries) {
1045 BUGPRINT("Wrong nr. of counters requested\n");
1046 ret = -EINVAL;
1047 goto free_unlock;
1048 }
1049
1050 /* we have the mutex lock, so no danger in reading this pointer */
1051 table = t->private;
1052 /* make sure the table can only be rmmod'ed if it contains no rules */
1053 if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) {
1054 ret = -ENOENT;
1055 goto free_unlock;
1056 } else if (table->nentries && !newinfo->nentries)
1057 module_put(t->me);
1058 /* we need an atomic snapshot of the counters */
1059 write_lock_bh(&t->lock);
1060 if (tmp.num_counters)
1061 get_counters(t->private->counters, counterstmp,
1062 t->private->nentries);
1063
1064 t->private = newinfo;
1065 write_unlock_bh(&t->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001066 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 /* so, a user can change the chains while having messed up her counter
1068 allocation. Only reason why this is done is because this way the lock
1069 is held only once, while this doesn't bring the kernel into a
1070 dangerous state. */
1071 if (tmp.num_counters &&
1072 copy_to_user(tmp.counters, counterstmp,
1073 tmp.num_counters * sizeof(struct ebt_counter))) {
1074 BUGPRINT("Couldn't copy counters to userspace\n");
1075 ret = -EFAULT;
1076 }
1077 else
1078 ret = 0;
1079
1080 /* decrease module count and free resources */
1081 EBT_ENTRY_ITERATE(table->entries, table->entries_size,
Alexey Dobriyanf54e9362010-01-18 08:25:47 +01001082 ebt_cleanup_entry, net, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083
1084 vfree(table->entries);
1085 if (table->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001086 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 vfree(table->chainstack[i]);
1088 vfree(table->chainstack);
1089 }
1090 vfree(table);
1091
James Lamanna68d31872005-06-22 22:12:57 -07001092 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 return ret;
1094
1095free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001096 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097free_iterate:
1098 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Alexey Dobriyanf54e9362010-01-18 08:25:47 +01001099 ebt_cleanup_entry, net, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100free_counterstmp:
James Lamanna68d31872005-06-22 22:12:57 -07001101 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 /* can be initialized in translate_table() */
1103 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001104 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 vfree(newinfo->chainstack[i]);
1106 vfree(newinfo->chainstack);
1107 }
1108free_entries:
James Lamanna68d31872005-06-22 22:12:57 -07001109 vfree(newinfo->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110free_newinfo:
James Lamanna68d31872005-06-22 22:12:57 -07001111 vfree(newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 return ret;
1113}
1114
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001115struct ebt_table *
1116ebt_register_table(struct net *net, const struct ebt_table *input_table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117{
1118 struct ebt_table_info *newinfo;
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001119 struct ebt_table *t, *table;
Al Viro1e419cd2006-11-30 19:28:48 -08001120 struct ebt_replace_kernel *repl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 int ret, i, countersize;
Al Virodf07a812006-11-30 19:28:25 -08001122 void *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001124 if (input_table == NULL || (repl = input_table->table) == NULL ||
1125 repl->entries == 0 || repl->entries_size == 0 ||
1126 repl->counters != NULL || input_table->private != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 BUGPRINT("Bad table data for ebt_register_table!!!\n");
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001128 return ERR_PTR(-EINVAL);
1129 }
1130
1131 /* Don't add one table to multiple lists. */
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001132 table = kmemdup(input_table, sizeof(struct ebt_table), GFP_KERNEL);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001133 if (!table) {
1134 ret = -ENOMEM;
1135 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 }
1137
Christoph Lameter53b8a312007-02-20 13:57:51 -08001138 countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -07001139 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 ret = -ENOMEM;
1141 if (!newinfo)
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001142 goto free_table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
Al Virodf07a812006-11-30 19:28:25 -08001144 p = vmalloc(repl->entries_size);
1145 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 goto free_newinfo;
1147
Al Virodf07a812006-11-30 19:28:25 -08001148 memcpy(p, repl->entries, repl->entries_size);
1149 newinfo->entries = p;
1150
1151 newinfo->entries_size = repl->entries_size;
1152 newinfo->nentries = repl->nentries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153
1154 if (countersize)
1155 memset(newinfo->counters, 0, countersize);
1156
1157 /* fill in newinfo and parse the entries */
1158 newinfo->chainstack = NULL;
Al Virodf07a812006-11-30 19:28:25 -08001159 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1160 if ((repl->valid_hooks & (1 << i)) == 0)
1161 newinfo->hook_entry[i] = NULL;
1162 else
1163 newinfo->hook_entry[i] = p +
1164 ((char *)repl->hook_entry[i] - repl->entries);
1165 }
Alexey Dobriyana83d8e82010-01-18 08:21:13 +01001166 ret = translate_table(net, repl->name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 if (ret != 0) {
1168 BUGPRINT("Translate_table failed\n");
1169 goto free_chainstack;
1170 }
1171
1172 if (table->check && table->check(newinfo, table->valid_hooks)) {
1173 BUGPRINT("The table doesn't like its own initial data, lol\n");
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001174 return ERR_PTR(-EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 }
1176
1177 table->private = newinfo;
1178 rwlock_init(&table->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001179 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 if (ret != 0)
1181 goto free_chainstack;
1182
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001183 list_for_each_entry(t, &net->xt.tables[NFPROTO_BRIDGE], list) {
Patrick McHardydf0933d2006-09-20 11:57:53 -07001184 if (strcmp(t->name, table->name) == 0) {
1185 ret = -EEXIST;
1186 BUGPRINT("Table name already exists\n");
1187 goto free_unlock;
1188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 }
1190
1191 /* Hold a reference count if the chains aren't empty */
1192 if (newinfo->nentries && !try_module_get(table->me)) {
1193 ret = -ENOENT;
1194 goto free_unlock;
1195 }
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001196 list_add(&table->list, &net->xt.tables[NFPROTO_BRIDGE]);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001197 mutex_unlock(&ebt_mutex);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001198 return table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001200 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201free_chainstack:
1202 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001203 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 vfree(newinfo->chainstack[i]);
1205 vfree(newinfo->chainstack);
1206 }
1207 vfree(newinfo->entries);
1208free_newinfo:
1209 vfree(newinfo);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001210free_table:
1211 kfree(table);
1212out:
1213 return ERR_PTR(ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214}
1215
Alexey Dobriyanf54e9362010-01-18 08:25:47 +01001216void ebt_unregister_table(struct net *net, struct ebt_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217{
1218 int i;
1219
1220 if (!table) {
1221 BUGPRINT("Request to unregister NULL table!!!\n");
1222 return;
1223 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001224 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001225 list_del(&table->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001226 mutex_unlock(&ebt_mutex);
Alexey Dobriyandbcdf852008-11-04 14:28:04 +01001227 EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size,
Alexey Dobriyanf54e9362010-01-18 08:25:47 +01001228 ebt_cleanup_entry, net, NULL);
Alexey Dobriyandbcdf852008-11-04 14:28:04 +01001229 if (table->private->nentries)
1230 module_put(table->me);
James Lamanna68d31872005-06-22 22:12:57 -07001231 vfree(table->private->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 if (table->private->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001233 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 vfree(table->private->chainstack[i]);
1235 vfree(table->private->chainstack);
1236 }
1237 vfree(table->private);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001238 kfree(table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239}
1240
1241/* userspace just supplied us with counters */
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +02001242static int update_counters(struct net *net, const void __user *user,
1243 unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244{
1245 int i, ret;
1246 struct ebt_counter *tmp;
1247 struct ebt_replace hlp;
1248 struct ebt_table *t;
1249
1250 if (copy_from_user(&hlp, user, sizeof(hlp)))
1251 return -EFAULT;
1252
1253 if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
1254 return -EINVAL;
1255 if (hlp.num_counters == 0)
1256 return -EINVAL;
1257
Jayachandran C18bc89a2006-04-20 00:14:49 -07001258 if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 MEMPRINT("Update_counters && nomemory\n");
1260 return -ENOMEM;
1261 }
1262
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001263 t = find_table_lock(net, hlp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 if (!t)
1265 goto free_tmp;
1266
1267 if (hlp.num_counters != t->private->nentries) {
1268 BUGPRINT("Wrong nr of counters\n");
1269 ret = -EINVAL;
1270 goto unlock_mutex;
1271 }
1272
1273 if ( copy_from_user(tmp, hlp.counters,
1274 hlp.num_counters * sizeof(struct ebt_counter)) ) {
1275 BUGPRINT("Updata_counters && !cfu\n");
1276 ret = -EFAULT;
1277 goto unlock_mutex;
1278 }
1279
1280 /* we want an atomic add of the counters */
1281 write_lock_bh(&t->lock);
1282
1283 /* we add to the counters of the first cpu */
1284 for (i = 0; i < hlp.num_counters; i++) {
1285 t->private->counters[i].pcnt += tmp[i].pcnt;
1286 t->private->counters[i].bcnt += tmp[i].bcnt;
1287 }
1288
1289 write_unlock_bh(&t->lock);
1290 ret = 0;
1291unlock_mutex:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001292 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293free_tmp:
1294 vfree(tmp);
1295 return ret;
1296}
1297
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +02001298static inline int ebt_make_matchname(const struct ebt_entry_match *m,
1299 const char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300{
Al Viro1e419cd2006-11-30 19:28:48 -08001301 char __user *hlp = ubase + ((char *)m - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
1303 return -EFAULT;
1304 return 0;
1305}
1306
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +02001307static inline int ebt_make_watchername(const struct ebt_entry_watcher *w,
1308 const char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309{
Al Viro1e419cd2006-11-30 19:28:48 -08001310 char __user *hlp = ubase + ((char *)w - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
1312 return -EFAULT;
1313 return 0;
1314}
1315
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +02001316static inline int
1317ebt_make_names(struct ebt_entry *e, const char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318{
1319 int ret;
Al Viro1e419cd2006-11-30 19:28:48 -08001320 char __user *hlp;
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +02001321 const struct ebt_entry_target *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322
Al Viro40642f92006-11-30 19:24:12 -08001323 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 return 0;
1325
Al Viro1e419cd2006-11-30 19:28:48 -08001326 hlp = ubase + (((char *)e + e->target_offset) - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +09001328
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
1330 if (ret != 0)
1331 return ret;
1332 ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
1333 if (ret != 0)
1334 return ret;
1335 if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
1336 return -EFAULT;
1337 return 0;
1338}
1339
Ingo Molnar57b47a52006-03-20 22:35:41 -08001340/* called with ebt_mutex locked */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341static int copy_everything_to_user(struct ebt_table *t, void __user *user,
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +02001342 const int *len, int cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343{
1344 struct ebt_replace tmp;
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +02001345 struct ebt_counter *counterstmp;
1346 const struct ebt_counter *oldcounters;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 unsigned int entries_size, nentries;
1348 char *entries;
1349
1350 if (cmd == EBT_SO_GET_ENTRIES) {
1351 entries_size = t->private->entries_size;
1352 nentries = t->private->nentries;
1353 entries = t->private->entries;
1354 oldcounters = t->private->counters;
1355 } else {
1356 entries_size = t->table->entries_size;
1357 nentries = t->table->nentries;
1358 entries = t->table->entries;
1359 oldcounters = t->table->counters;
1360 }
1361
1362 if (copy_from_user(&tmp, user, sizeof(tmp))) {
1363 BUGPRINT("Cfu didn't work\n");
1364 return -EFAULT;
1365 }
1366
1367 if (*len != sizeof(struct ebt_replace) + entries_size +
1368 (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
1369 BUGPRINT("Wrong size\n");
1370 return -EINVAL;
1371 }
1372
1373 if (tmp.nentries != nentries) {
1374 BUGPRINT("Nentries wrong\n");
1375 return -EINVAL;
1376 }
1377
1378 if (tmp.entries_size != entries_size) {
1379 BUGPRINT("Wrong size\n");
1380 return -EINVAL;
1381 }
1382
1383 /* userspace might not need the counters */
1384 if (tmp.num_counters) {
1385 if (tmp.num_counters != nentries) {
1386 BUGPRINT("Num_counters wrong\n");
1387 return -EINVAL;
1388 }
Jayachandran C18bc89a2006-04-20 00:14:49 -07001389 counterstmp = vmalloc(nentries * sizeof(*counterstmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 if (!counterstmp) {
1391 MEMPRINT("Couldn't copy counters, out of memory\n");
1392 return -ENOMEM;
1393 }
1394 write_lock_bh(&t->lock);
1395 get_counters(oldcounters, counterstmp, nentries);
1396 write_unlock_bh(&t->lock);
1397
1398 if (copy_to_user(tmp.counters, counterstmp,
1399 nentries * sizeof(struct ebt_counter))) {
1400 BUGPRINT("Couldn't copy counters to userspace\n");
1401 vfree(counterstmp);
1402 return -EFAULT;
1403 }
1404 vfree(counterstmp);
1405 }
1406
1407 if (copy_to_user(tmp.entries, entries, entries_size)) {
1408 BUGPRINT("Couldn't copy entries to userspace\n");
1409 return -EFAULT;
1410 }
1411 /* set the match/watcher/target names right */
1412 return EBT_ENTRY_ITERATE(entries, entries_size,
1413 ebt_make_names, entries, tmp.entries);
1414}
1415
1416static int do_ebt_set_ctl(struct sock *sk,
1417 int cmd, void __user *user, unsigned int len)
1418{
1419 int ret;
1420
Florian Westphaldce766a2010-01-08 17:31:24 +01001421 if (!capable(CAP_NET_ADMIN))
1422 return -EPERM;
1423
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 switch(cmd) {
1425 case EBT_SO_SET_ENTRIES:
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001426 ret = do_replace(sock_net(sk), user, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 break;
1428 case EBT_SO_SET_COUNTERS:
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001429 ret = update_counters(sock_net(sk), user, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 break;
1431 default:
1432 ret = -EINVAL;
1433 }
1434 return ret;
1435}
1436
1437static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1438{
1439 int ret;
1440 struct ebt_replace tmp;
1441 struct ebt_table *t;
1442
Florian Westphaldce766a2010-01-08 17:31:24 +01001443 if (!capable(CAP_NET_ADMIN))
1444 return -EPERM;
1445
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 if (copy_from_user(&tmp, user, sizeof(tmp)))
1447 return -EFAULT;
1448
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001449 t = find_table_lock(sock_net(sk), tmp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 if (!t)
1451 return ret;
1452
1453 switch(cmd) {
1454 case EBT_SO_GET_INFO:
1455 case EBT_SO_GET_INIT_INFO:
1456 if (*len != sizeof(struct ebt_replace)){
1457 ret = -EINVAL;
Ingo Molnar57b47a52006-03-20 22:35:41 -08001458 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 break;
1460 }
1461 if (cmd == EBT_SO_GET_INFO) {
1462 tmp.nentries = t->private->nentries;
1463 tmp.entries_size = t->private->entries_size;
1464 tmp.valid_hooks = t->valid_hooks;
1465 } else {
1466 tmp.nentries = t->table->nentries;
1467 tmp.entries_size = t->table->entries_size;
1468 tmp.valid_hooks = t->table->valid_hooks;
1469 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001470 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 if (copy_to_user(user, &tmp, *len) != 0){
1472 BUGPRINT("c2u Didn't work\n");
1473 ret = -EFAULT;
1474 break;
1475 }
1476 ret = 0;
1477 break;
1478
1479 case EBT_SO_GET_ENTRIES:
1480 case EBT_SO_GET_INIT_ENTRIES:
1481 ret = copy_everything_to_user(t, user, len, cmd);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001482 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 break;
1484
1485 default:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001486 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 ret = -EINVAL;
1488 }
1489
1490 return ret;
1491}
1492
1493static struct nf_sockopt_ops ebt_sockopts =
Andrew Morton74ca4e5a2006-03-20 22:55:02 -08001494{
1495 .pf = PF_INET,
1496 .set_optmin = EBT_BASE_CTL,
1497 .set_optmax = EBT_SO_SET_MAX + 1,
1498 .set = do_ebt_set_ctl,
1499 .get_optmin = EBT_BASE_CTL,
1500 .get_optmax = EBT_SO_GET_MAX + 1,
1501 .get = do_ebt_get_ctl,
Neil Horman16fcec32007-09-11 11:28:26 +02001502 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503};
1504
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001505static int __init ebtables_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506{
1507 int ret;
1508
Jan Engelhardt043ef462008-10-08 11:35:15 +02001509 ret = xt_register_target(&ebt_standard_target);
1510 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 return ret;
Jan Engelhardt043ef462008-10-08 11:35:15 +02001512 ret = nf_register_sockopt(&ebt_sockopts);
1513 if (ret < 0) {
1514 xt_unregister_target(&ebt_standard_target);
1515 return ret;
1516 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517
Patrick McHardya887c1c2007-07-14 20:46:15 -07001518 printk(KERN_INFO "Ebtables v2.0 registered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 return 0;
1520}
1521
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001522static void __exit ebtables_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523{
1524 nf_unregister_sockopt(&ebt_sockopts);
Jan Engelhardt043ef462008-10-08 11:35:15 +02001525 xt_unregister_target(&ebt_standard_target);
Patrick McHardya887c1c2007-07-14 20:46:15 -07001526 printk(KERN_INFO "Ebtables v2.0 unregistered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527}
1528
1529EXPORT_SYMBOL(ebt_register_table);
1530EXPORT_SYMBOL(ebt_unregister_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531EXPORT_SYMBOL(ebt_do_table);
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001532module_init(ebtables_init);
1533module_exit(ebtables_fini);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534MODULE_LICENSE("GPL");