blob: 76b99d3c1eea0760c53d1c2fbd0b08cb957b7fae [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
37/*
38 * Each cpu has its own set of counters, so there is no need for write_lock in
39 * the softirq
40 * For reading or updating the counters, the user context needs to
41 * get a write_lock
42 */
43
44/* The size of each set of counters is altered to get cache alignment */
45#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
46#define COUNTER_OFFSET(n) (SMP_ALIGN(n * sizeof(struct ebt_counter)))
47#define COUNTER_BASE(c, n, cpu) ((struct ebt_counter *)(((char *)c) + \
48 COUNTER_OFFSET(n) * cpu))
49
50
51
Ingo Molnar57b47a52006-03-20 22:35:41 -080052static DEFINE_MUTEX(ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
Jan Engelhardt043ef462008-10-08 11:35:15 +020054static struct xt_target ebt_standard_target = {
Jan Engelhardt001a18d2008-10-08 11:35:14 +020055 .name = "standard",
56 .revision = 0,
57 .family = NFPROTO_BRIDGE,
Jan Engelhardt043ef462008-10-08 11:35:15 +020058 .targetsize = sizeof(int),
Jan Engelhardt18219d32008-10-08 11:35:13 +020059};
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Jan Engelhardt7eb35582008-10-08 11:35:19 +020061static inline int
62ebt_do_watcher(const struct ebt_entry_watcher *w, struct sk_buff *skb,
63 struct xt_target_param *par)
Linus Torvalds1da177e2005-04-16 15:20:36 -070064{
Jan Engelhardt7eb35582008-10-08 11:35:19 +020065 par->target = w->u.watcher;
66 par->targinfo = w->data;
67 w->u.watcher->target(skb, par);
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 /* watchers don't give a verdict */
69 return 0;
70}
71
72static inline int ebt_do_match (struct ebt_entry_match *m,
Jan Engelhardtf7108a22008-10-08 11:35:18 +020073 const struct sk_buff *skb, struct xt_match_param *par)
Linus Torvalds1da177e2005-04-16 15:20:36 -070074{
Jan Engelhardtf7108a22008-10-08 11:35:18 +020075 par->match = m->u.match;
76 par->matchinfo = m->data;
Jan Engelhardtd61ba9f2009-01-12 00:06:06 +000077 return m->u.match->match(skb, par) ? EBT_MATCH : EBT_NOMATCH;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078}
79
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +020080static inline int
81ebt_dev_check(const char *entry, const struct net_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -070082{
83 int i = 0;
Julia Lawallf3d8b2e2009-01-09 10:22:22 +000084 const char *devname;
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
86 if (*entry == '\0')
87 return 0;
88 if (!device)
89 return 1;
Julia Lawallf3d8b2e2009-01-09 10:22:22 +000090 devname = device->name;
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 /* 1 is the wildcard token */
92 while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i])
93 i++;
94 return (devname[i] != entry[i] && entry[i] != 1);
95}
96
97#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
98/* process standard matches */
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +020099static inline int
100ebt_basic_match(const struct ebt_entry *e, const struct ethhdr *h,
101 const struct net_device *in, const struct net_device *out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102{
103 int verdict, i;
104
105 if (e->bitmask & EBT_802_3) {
106 if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO))
107 return 1;
108 } else if (!(e->bitmask & EBT_NOPROTO) &&
109 FWINV2(e->ethproto != h->h_proto, EBT_IPROTO))
110 return 1;
111
112 if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
113 return 1;
114 if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
115 return 1;
116 if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check(
117 e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN))
118 return 1;
119 if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check(
120 e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT))
121 return 1;
122
123 if (e->bitmask & EBT_SOURCEMAC) {
124 verdict = 0;
125 for (i = 0; i < 6; i++)
126 verdict |= (h->h_source[i] ^ e->sourcemac[i]) &
127 e->sourcemsk[i];
128 if (FWINV2(verdict != 0, EBT_ISOURCE) )
129 return 1;
130 }
131 if (e->bitmask & EBT_DESTMAC) {
132 verdict = 0;
133 for (i = 0; i < 6; i++)
134 verdict |= (h->h_dest[i] ^ e->destmac[i]) &
135 e->destmsk[i];
136 if (FWINV2(verdict != 0, EBT_IDEST) )
137 return 1;
138 }
139 return 0;
140}
141
Jan Engelhardt98e86402009-04-15 21:06:05 +0200142static inline __pure
143struct ebt_entry *ebt_next_entry(const struct ebt_entry *entry)
144{
145 return (void *)entry + entry->next_offset;
146}
147
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148/* Do some firewalling */
Herbert Xu3db05fe2007-10-15 00:53:15 -0700149unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 const struct net_device *in, const struct net_device *out,
151 struct ebt_table *table)
152{
153 int i, nentries;
154 struct ebt_entry *point;
155 struct ebt_counter *counter_base, *cb_base;
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200156 const struct ebt_entry_target *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 int verdict, sp = 0;
158 struct ebt_chainstack *cs;
159 struct ebt_entries *chaininfo;
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200160 const char *base;
161 const struct ebt_table_info *private;
Jan Engelhardt5365f802008-10-08 11:35:16 +0200162 bool hotdrop = false;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200163 struct xt_match_param mtpar;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200164 struct xt_target_param tgpar;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200165
Jan Engelhardt916a9172008-10-08 11:35:20 +0200166 mtpar.family = tgpar.family = NFPROTO_BRIDGE;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200167 mtpar.in = tgpar.in = in;
168 mtpar.out = tgpar.out = out;
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200169 mtpar.hotdrop = &hotdrop;
Evgeniy Polyakova5e78822009-06-04 16:54:42 +0200170 mtpar.hooknum = tgpar.hooknum = hook;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
172 read_lock_bh(&table->lock);
173 private = table->private;
174 cb_base = COUNTER_BASE(private->counters, private->nentries,
175 smp_processor_id());
176 if (private->chainstack)
177 cs = private->chainstack[smp_processor_id()];
178 else
179 cs = NULL;
180 chaininfo = private->hook_entry[hook];
181 nentries = private->hook_entry[hook]->nentries;
182 point = (struct ebt_entry *)(private->hook_entry[hook]->data);
183 counter_base = cb_base + private->hook_entry[hook]->counter_offset;
184 /* base for chain jumps */
185 base = private->entries;
186 i = 0;
187 while (i < nentries) {
Herbert Xu3db05fe2007-10-15 00:53:15 -0700188 if (ebt_basic_match(point, eth_hdr(skb), in, out))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 goto letscontinue;
190
Jan Engelhardtf7108a22008-10-08 11:35:18 +0200191 if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, &mtpar) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 goto letscontinue;
Jan Engelhardt5365f802008-10-08 11:35:16 +0200193 if (hotdrop) {
194 read_unlock_bh(&table->lock);
195 return NF_DROP;
196 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
198 /* increase counter */
199 (*(counter_base + i)).pcnt++;
Herbert Xu3db05fe2007-10-15 00:53:15 -0700200 (*(counter_base + i)).bcnt += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
202 /* these should only watch: not modify, nor tell us
203 what to do with the packet */
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200204 EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, &tgpar);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
206 t = (struct ebt_entry_target *)
207 (((char *)point) + point->target_offset);
208 /* standard target */
209 if (!t->u.target->target)
210 verdict = ((struct ebt_standard_target *)t)->verdict;
Jan Engelhardt7eb35582008-10-08 11:35:19 +0200211 else {
212 tgpar.target = t->u.target;
213 tgpar.targinfo = t->data;
214 verdict = t->u.target->target(skb, &tgpar);
215 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 if (verdict == EBT_ACCEPT) {
217 read_unlock_bh(&table->lock);
218 return NF_ACCEPT;
219 }
220 if (verdict == EBT_DROP) {
221 read_unlock_bh(&table->lock);
222 return NF_DROP;
223 }
224 if (verdict == EBT_RETURN) {
225letsreturn:
226#ifdef CONFIG_NETFILTER_DEBUG
227 if (sp == 0) {
228 BUGPRINT("RETURN on base chain");
229 /* act like this is EBT_CONTINUE */
230 goto letscontinue;
231 }
232#endif
233 sp--;
234 /* put all the local variables right */
235 i = cs[sp].n;
236 chaininfo = cs[sp].chaininfo;
237 nentries = chaininfo->nentries;
238 point = cs[sp].e;
239 counter_base = cb_base +
240 chaininfo->counter_offset;
241 continue;
242 }
243 if (verdict == EBT_CONTINUE)
244 goto letscontinue;
245#ifdef CONFIG_NETFILTER_DEBUG
246 if (verdict < 0) {
247 BUGPRINT("bogus standard verdict\n");
248 read_unlock_bh(&table->lock);
249 return NF_DROP;
250 }
251#endif
252 /* jump to a udc */
253 cs[sp].n = i + 1;
254 cs[sp].chaininfo = chaininfo;
Jan Engelhardt98e86402009-04-15 21:06:05 +0200255 cs[sp].e = ebt_next_entry(point);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 i = 0;
257 chaininfo = (struct ebt_entries *) (base + verdict);
258#ifdef CONFIG_NETFILTER_DEBUG
259 if (chaininfo->distinguisher) {
260 BUGPRINT("jump to non-chain\n");
261 read_unlock_bh(&table->lock);
262 return NF_DROP;
263 }
264#endif
265 nentries = chaininfo->nentries;
266 point = (struct ebt_entry *)chaininfo->data;
267 counter_base = cb_base + chaininfo->counter_offset;
268 sp++;
269 continue;
270letscontinue:
Jan Engelhardt98e86402009-04-15 21:06:05 +0200271 point = ebt_next_entry(point);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 i++;
273 }
274
275 /* I actually like this :) */
276 if (chaininfo->policy == EBT_RETURN)
277 goto letsreturn;
278 if (chaininfo->policy == EBT_ACCEPT) {
279 read_unlock_bh(&table->lock);
280 return NF_ACCEPT;
281 }
282 read_unlock_bh(&table->lock);
283 return NF_DROP;
284}
285
286/* If it succeeds, returns element and locks mutex */
287static inline void *
288find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800289 struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290{
Patrick McHardydf0933d2006-09-20 11:57:53 -0700291 struct {
292 struct list_head list;
293 char name[EBT_FUNCTION_MAXNAMELEN];
294 } *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
Ingo Molnar57b47a52006-03-20 22:35:41 -0800296 *error = mutex_lock_interruptible(mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 if (*error != 0)
298 return NULL;
299
Patrick McHardydf0933d2006-09-20 11:57:53 -0700300 list_for_each_entry(e, head, list) {
301 if (strcmp(e->name, name) == 0)
302 return e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 }
Patrick McHardydf0933d2006-09-20 11:57:53 -0700304 *error = -ENOENT;
305 mutex_unlock(mutex);
306 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307}
308
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309static void *
310find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
Ingo Molnar57b47a52006-03-20 22:35:41 -0800311 int *error, struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312{
Johannes Berg95a5afc2008-10-16 15:24:51 -0700313 return try_then_request_module(
314 find_inlist_lock_noload(head, name, error, mutex),
315 "%s%s", prefix, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
318static inline struct ebt_table *
Alexey Dobriyan511061e2008-11-04 14:22:55 +0100319find_table_lock(struct net *net, const char *name, int *error,
320 struct mutex *mutex)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321{
Alexey Dobriyan511061e2008-11-04 14:22:55 +0100322 return find_inlist_lock(&net->xt.tables[NFPROTO_BRIDGE], name,
323 "ebtable_", error, mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324}
325
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326static inline int
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200327ebt_check_match(struct ebt_entry_match *m, struct xt_mtchk_param *par,
328 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329{
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200330 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200331 struct xt_match *match;
Al Viro14197d52006-11-30 19:25:21 -0800332 size_t left = ((char *)e + e->watchers_offset) - (char *)m;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 int ret;
334
Al Viro14197d52006-11-30 19:25:21 -0800335 if (left < sizeof(struct ebt_entry_match) ||
336 left - sizeof(struct ebt_entry_match) < m->match_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200338
339 match = try_then_request_module(xt_find_match(NFPROTO_BRIDGE,
340 m->u.name, 0), "ebt_%s", m->u.name);
341 if (IS_ERR(match))
342 return PTR_ERR(match);
343 if (match == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200345 m->u.match = match;
346
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200347 par->match = match;
348 par->matchinfo = m->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200349 ret = xt_check_match(par, m->match_size,
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200350 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200351 if (ret < 0) {
352 module_put(match->me);
353 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200355
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 (*cnt)++;
357 return 0;
358}
359
360static inline int
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200361ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
362 unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200364 const struct ebt_entry *e = par->entryinfo;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200365 struct xt_target *watcher;
Al Viro14197d52006-11-30 19:25:21 -0800366 size_t left = ((char *)e + e->target_offset) - (char *)w;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 int ret;
368
Al Viro14197d52006-11-30 19:25:21 -0800369 if (left < sizeof(struct ebt_entry_watcher) ||
370 left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 return -EINVAL;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200372
373 watcher = try_then_request_module(
374 xt_find_target(NFPROTO_BRIDGE, w->u.name, 0),
375 "ebt_%s", w->u.name);
376 if (IS_ERR(watcher))
377 return PTR_ERR(watcher);
378 if (watcher == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 return -ENOENT;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200380 w->u.watcher = watcher;
381
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200382 par->target = watcher;
383 par->targinfo = w->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200384 ret = xt_check_target(par, w->watcher_size,
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200385 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200386 if (ret < 0) {
387 module_put(watcher->me);
388 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 }
Jan Engelhardt043ef462008-10-08 11:35:15 +0200390
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 (*cnt)++;
392 return 0;
393}
394
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200395static int ebt_verify_pointers(const struct ebt_replace *repl,
Al Viro70fe9af2006-11-30 19:26:14 -0800396 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397{
Al Viro70fe9af2006-11-30 19:26:14 -0800398 unsigned int limit = repl->entries_size;
399 unsigned int valid_hooks = repl->valid_hooks;
400 unsigned int offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 int i;
402
Al Viroe4fd77d2006-11-30 19:26:35 -0800403 for (i = 0; i < NF_BR_NUMHOOKS; i++)
404 newinfo->hook_entry[i] = NULL;
405
406 newinfo->entries_size = repl->entries_size;
407 newinfo->nentries = repl->nentries;
408
Al Viro70fe9af2006-11-30 19:26:14 -0800409 while (offset < limit) {
410 size_t left = limit - offset;
411 struct ebt_entry *e = (void *)newinfo->entries + offset;
Al Virobb2ef252006-11-30 19:22:42 -0800412
Al Viro70fe9af2006-11-30 19:26:14 -0800413 if (left < sizeof(unsigned int))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 break;
Al Viro22b440b2006-11-30 19:25:51 -0800415
Al Viro70fe9af2006-11-30 19:26:14 -0800416 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
417 if ((valid_hooks & (1 << i)) == 0)
418 continue;
Al Viro1e419cd2006-11-30 19:28:48 -0800419 if ((char __user *)repl->hook_entry[i] ==
420 repl->entries + offset)
Al Viro70fe9af2006-11-30 19:26:14 -0800421 break;
422 }
423
424 if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
425 if (e->bitmask != 0) {
426 /* we make userspace set this right,
427 so there is no misunderstanding */
428 BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
429 "in distinguisher\n");
430 return -EINVAL;
431 }
432 if (i != NF_BR_NUMHOOKS)
433 newinfo->hook_entry[i] = (struct ebt_entries *)e;
434 if (left < sizeof(struct ebt_entries))
435 break;
436 offset += sizeof(struct ebt_entries);
437 } else {
438 if (left < sizeof(struct ebt_entry))
439 break;
440 if (left < e->next_offset)
441 break;
Florian Westphal1756de22010-02-15 18:15:55 +0100442 if (e->next_offset < sizeof(struct ebt_entry))
443 return -EINVAL;
Al Viro70fe9af2006-11-30 19:26:14 -0800444 offset += e->next_offset;
445 }
446 }
447 if (offset != limit) {
448 BUGPRINT("entries_size too small\n");
449 return -EINVAL;
450 }
Al Viroe4fd77d2006-11-30 19:26:35 -0800451
452 /* check if all valid hooks have a chain */
453 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
454 if (!newinfo->hook_entry[i] &&
455 (valid_hooks & (1 << i))) {
456 BUGPRINT("Valid hook without chain\n");
457 return -EINVAL;
458 }
459 }
Al Viro70fe9af2006-11-30 19:26:14 -0800460 return 0;
Al Viro22b440b2006-11-30 19:25:51 -0800461}
462
463/*
464 * this one is very careful, as it is the first function
465 * to parse the userspace data
466 */
467static inline int
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200468ebt_check_entry_size_and_hooks(const struct ebt_entry *e,
469 const struct ebt_table_info *newinfo,
Al Viro0e795532006-11-30 19:27:13 -0800470 unsigned int *n, unsigned int *cnt,
471 unsigned int *totalcnt, unsigned int *udc_cnt)
Al Viro22b440b2006-11-30 19:25:51 -0800472{
Al Viro22b440b2006-11-30 19:25:51 -0800473 int i;
474
475 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Viro0e795532006-11-30 19:27:13 -0800476 if ((void *)e == (void *)newinfo->hook_entry[i])
Al Viro22b440b2006-11-30 19:25:51 -0800477 break;
478 }
479 /* beginning of a new chain
480 if i == NF_BR_NUMHOOKS it must be a user defined chain */
481 if (i != NF_BR_NUMHOOKS || !e->bitmask) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 /* this checks if the previous chain has as many entries
483 as it said it has */
484 if (*n != *cnt) {
485 BUGPRINT("nentries does not equal the nr of entries "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900486 "in the chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 return -EINVAL;
488 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 if (((struct ebt_entries *)e)->policy != EBT_DROP &&
490 ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
491 /* only RETURN from udc */
492 if (i != NF_BR_NUMHOOKS ||
493 ((struct ebt_entries *)e)->policy != EBT_RETURN) {
494 BUGPRINT("bad policy\n");
495 return -EINVAL;
496 }
497 }
498 if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
499 (*udc_cnt)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
501 BUGPRINT("counter_offset != totalcnt");
502 return -EINVAL;
503 }
504 *n = ((struct ebt_entries *)e)->nentries;
505 *cnt = 0;
506 return 0;
507 }
508 /* a plain old entry, heh */
509 if (sizeof(struct ebt_entry) > e->watchers_offset ||
510 e->watchers_offset > e->target_offset ||
511 e->target_offset >= e->next_offset) {
512 BUGPRINT("entry offsets not in right order\n");
513 return -EINVAL;
514 }
515 /* this is not checked anywhere else */
516 if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
517 BUGPRINT("target size too small\n");
518 return -EINVAL;
519 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 (*cnt)++;
521 (*totalcnt)++;
522 return 0;
523}
524
525struct ebt_cl_stack
526{
527 struct ebt_chainstack cs;
528 int from;
529 unsigned int hookmask;
530};
531
532/*
533 * we need these positions to check that the jumps to a different part of the
534 * entries is a jump to the beginning of a new chain.
535 */
536static inline int
537ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
Al Viro177abc32006-11-30 19:27:32 -0800538 unsigned int *n, struct ebt_cl_stack *udc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539{
540 int i;
541
542 /* we're only interested in chain starts */
Al Viro40642f92006-11-30 19:24:12 -0800543 if (e->bitmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 return 0;
545 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
547 break;
548 }
549 /* only care about udc */
550 if (i != NF_BR_NUMHOOKS)
551 return 0;
552
553 udc[*n].cs.chaininfo = (struct ebt_entries *)e;
554 /* these initialisations are depended on later in check_chainloops() */
555 udc[*n].cs.n = 0;
556 udc[*n].hookmask = 0;
557
558 (*n)++;
559 return 0;
560}
561
562static inline int
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100563ebt_cleanup_match(struct ebt_entry_match *m, struct net *net, unsigned int *i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564{
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200565 struct xt_mtdtor_param par;
566
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 if (i && (*i)-- == 0)
568 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100570 par.net = net;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200571 par.match = m->u.match;
572 par.matchinfo = m->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200573 par.family = NFPROTO_BRIDGE;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200574 if (par.match->destroy != NULL)
575 par.match->destroy(&par);
576 module_put(par.match->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 return 0;
578}
579
580static inline int
Patrick McHardyadd67462010-02-03 13:45:12 +0100581ebt_cleanup_watcher(struct ebt_entry_watcher *w, struct net *net, unsigned int *i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200583 struct xt_tgdtor_param par;
584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 if (i && (*i)-- == 0)
586 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
Patrick McHardyadd67462010-02-03 13:45:12 +0100588 par.net = net;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200589 par.target = w->u.watcher;
590 par.targinfo = w->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200591 par.family = NFPROTO_BRIDGE;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200592 if (par.target->destroy != NULL)
593 par.target->destroy(&par);
594 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 return 0;
596}
597
598static inline int
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100599ebt_cleanup_entry(struct ebt_entry *e, struct net *net, unsigned int *cnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600{
Jan Engelhardta2df1642008-10-08 11:35:19 +0200601 struct xt_tgdtor_param par;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 struct ebt_entry_target *t;
603
Al Viro40642f92006-11-30 19:24:12 -0800604 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 return 0;
606 /* we're done */
607 if (cnt && (*cnt)-- == 0)
608 return 1;
Patrick McHardyadd67462010-02-03 13:45:12 +0100609 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, net, NULL);
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100610 EBT_MATCH_ITERATE(e, ebt_cleanup_match, net, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
Patrick McHardyadd67462010-02-03 13:45:12 +0100613 par.net = net;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200614 par.target = t->u.target;
615 par.targinfo = t->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200616 par.family = NFPROTO_BRIDGE;
Jan Engelhardta2df1642008-10-08 11:35:19 +0200617 if (par.target->destroy != NULL)
618 par.target->destroy(&par);
619 module_put(par.target->me);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 return 0;
621}
622
623static inline int
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200624ebt_check_entry(struct ebt_entry *e, struct net *net,
625 const struct ebt_table_info *newinfo,
Al Virof7da79d2006-11-30 19:27:48 -0800626 const char *name, unsigned int *cnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
628{
629 struct ebt_entry_target *t;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200630 struct xt_target *target;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 unsigned int i, j, hook = 0, hookmask = 0;
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800632 size_t gap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 int ret;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200634 struct xt_mtchk_param mtpar;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200635 struct xt_tgchk_param tgpar;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
637 /* don't mess with the struct ebt_entries */
Al Viro40642f92006-11-30 19:24:12 -0800638 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 return 0;
640
641 if (e->bitmask & ~EBT_F_MASK) {
642 BUGPRINT("Unknown flag for bitmask\n");
643 return -EINVAL;
644 }
645 if (e->invflags & ~EBT_INV_MASK) {
646 BUGPRINT("Unknown flag for inv bitmask\n");
647 return -EINVAL;
648 }
649 if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
650 BUGPRINT("NOPROTO & 802_3 not allowed\n");
651 return -EINVAL;
652 }
653 /* what hook do we belong to? */
654 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
Al Virof7da79d2006-11-30 19:27:48 -0800655 if (!newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 continue;
657 if ((char *)newinfo->hook_entry[i] < (char *)e)
658 hook = i;
659 else
660 break;
661 }
662 /* (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
663 a base chain */
664 if (i < NF_BR_NUMHOOKS)
665 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
666 else {
667 for (i = 0; i < udc_cnt; i++)
668 if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
669 break;
670 if (i == 0)
671 hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
672 else
673 hookmask = cl_s[i - 1].hookmask;
674 }
675 i = 0;
Jan Engelhardt9b4fce72008-10-08 11:35:18 +0200676
Patrick McHardyadd67462010-02-03 13:45:12 +0100677 mtpar.net = tgpar.net = net;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200678 mtpar.table = tgpar.table = name;
679 mtpar.entryinfo = tgpar.entryinfo = e;
680 mtpar.hook_mask = tgpar.hook_mask = hookmask;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200681 mtpar.family = tgpar.family = NFPROTO_BRIDGE;
Jan Engelhardt6be3d852008-10-08 11:35:19 +0200682 ret = EBT_MATCH_ITERATE(e, ebt_check_match, &mtpar, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 if (ret != 0)
684 goto cleanup_matches;
685 j = 0;
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200686 ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, &tgpar, &j);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 if (ret != 0)
688 goto cleanup_watchers;
689 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
Chuck Ebbert44f9a2f2007-01-04 12:17:44 -0800690 gap = e->next_offset - e->target_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
Jan Engelhardt043ef462008-10-08 11:35:15 +0200692 target = try_then_request_module(
693 xt_find_target(NFPROTO_BRIDGE, t->u.name, 0),
694 "ebt_%s", t->u.name);
695 if (IS_ERR(target)) {
696 ret = PTR_ERR(target);
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200697 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200698 } else if (target == NULL) {
699 ret = -ENOENT;
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200700 goto cleanup_watchers;
701 }
702
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 t->u.target = target;
704 if (t->u.target == &ebt_standard_target) {
Al Viro14197d52006-11-30 19:25:21 -0800705 if (gap < sizeof(struct ebt_standard_target)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 BUGPRINT("Standard target size too big\n");
707 ret = -EFAULT;
708 goto cleanup_watchers;
709 }
710 if (((struct ebt_standard_target *)t)->verdict <
711 -NUM_STANDARD_TARGETS) {
712 BUGPRINT("Invalid standard target\n");
713 ret = -EFAULT;
714 goto cleanup_watchers;
715 }
Jan Engelhardt18219d32008-10-08 11:35:13 +0200716 } else if (t->target_size > gap - sizeof(struct ebt_entry_target)) {
717 module_put(t->u.target->me);
718 ret = -EFAULT;
719 goto cleanup_watchers;
Jan Engelhardt043ef462008-10-08 11:35:15 +0200720 }
721
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200722 tgpar.target = target;
723 tgpar.targinfo = t->data;
Jan Engelhardt916a9172008-10-08 11:35:20 +0200724 ret = xt_check_target(&tgpar, t->target_size,
Jan Engelhardtaf5d6dc2008-10-08 11:35:19 +0200725 e->ethproto, e->invflags & EBT_IPROTO);
Jan Engelhardt043ef462008-10-08 11:35:15 +0200726 if (ret < 0) {
727 module_put(target->me);
Jan Engelhardt18219d32008-10-08 11:35:13 +0200728 goto cleanup_watchers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 }
730 (*cnt)++;
731 return 0;
732cleanup_watchers:
Patrick McHardyadd67462010-02-03 13:45:12 +0100733 EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, net, &j);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734cleanup_matches:
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100735 EBT_MATCH_ITERATE(e, ebt_cleanup_match, net, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 return ret;
737}
738
739/*
740 * checks for loops and sets the hook mask for udc
741 * the hook mask for udc tells us from which base chains the udc can be
742 * accessed. This mask is a parameter to the check() functions of the extensions
743 */
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200744static int check_chainloops(const struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 unsigned int udc_cnt, unsigned int hooknr, char *base)
746{
747 int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200748 const struct ebt_entry *e = (struct ebt_entry *)chain->data;
749 const struct ebt_entry_target *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
751 while (pos < nentries || chain_nr != -1) {
752 /* end of udc, go back one 'recursion' step */
753 if (pos == nentries) {
754 /* put back values of the time when this chain was called */
755 e = cl_s[chain_nr].cs.e;
756 if (cl_s[chain_nr].from != -1)
757 nentries =
758 cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
759 else
760 nentries = chain->nentries;
761 pos = cl_s[chain_nr].cs.n;
762 /* make sure we won't see a loop that isn't one */
763 cl_s[chain_nr].cs.n = 0;
764 chain_nr = cl_s[chain_nr].from;
765 if (pos == nentries)
766 continue;
767 }
768 t = (struct ebt_entry_target *)
769 (((char *)e) + e->target_offset);
770 if (strcmp(t->u.name, EBT_STANDARD_TARGET))
771 goto letscontinue;
772 if (e->target_offset + sizeof(struct ebt_standard_target) >
773 e->next_offset) {
774 BUGPRINT("Standard target size too big\n");
775 return -1;
776 }
777 verdict = ((struct ebt_standard_target *)t)->verdict;
778 if (verdict >= 0) { /* jump to another chain */
779 struct ebt_entries *hlp2 =
780 (struct ebt_entries *)(base + verdict);
781 for (i = 0; i < udc_cnt; i++)
782 if (hlp2 == cl_s[i].cs.chaininfo)
783 break;
784 /* bad destination or loop */
785 if (i == udc_cnt) {
786 BUGPRINT("bad destination\n");
787 return -1;
788 }
789 if (cl_s[i].cs.n) {
790 BUGPRINT("loop\n");
791 return -1;
792 }
Al Viro98a08242006-11-30 19:24:49 -0800793 if (cl_s[i].hookmask & (1 << hooknr))
794 goto letscontinue;
795 /* this can't be 0, so the loop test is correct */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 cl_s[i].cs.n = pos + 1;
797 pos = 0;
Jan Engelhardt98e86402009-04-15 21:06:05 +0200798 cl_s[i].cs.e = ebt_next_entry(e);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 e = (struct ebt_entry *)(hlp2->data);
800 nentries = hlp2->nentries;
801 cl_s[i].from = chain_nr;
802 chain_nr = i;
803 /* this udc is accessible from the base chain for hooknr */
804 cl_s[i].hookmask |= (1 << hooknr);
805 continue;
806 }
807letscontinue:
Jan Engelhardt98e86402009-04-15 21:06:05 +0200808 e = ebt_next_entry(e);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 pos++;
810 }
811 return 0;
812}
813
814/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200815static int translate_table(struct net *net, const char *name,
Alexey Dobriyana83d8e82010-01-18 08:21:13 +0100816 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817{
818 unsigned int i, j, k, udc_cnt;
819 int ret;
820 struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
821
822 i = 0;
Al Viro1f072c92006-11-30 19:26:53 -0800823 while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 i++;
825 if (i == NF_BR_NUMHOOKS) {
826 BUGPRINT("No valid hooks specified\n");
827 return -EINVAL;
828 }
Al Viro1f072c92006-11-30 19:26:53 -0800829 if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 BUGPRINT("Chains don't start at beginning\n");
831 return -EINVAL;
832 }
833 /* make sure chains are ordered after each other in same order
834 as their corresponding hooks */
835 for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
Al Viro1f072c92006-11-30 19:26:53 -0800836 if (!newinfo->hook_entry[j])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 continue;
Al Viro1f072c92006-11-30 19:26:53 -0800838 if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 BUGPRINT("Hook order must be followed\n");
840 return -EINVAL;
841 }
842 i = j;
843 }
844
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 /* do some early checkings and initialize some things */
846 i = 0; /* holds the expected nr. of entries for the chain */
847 j = 0; /* holds the up to now counted entries for the chain */
848 k = 0; /* holds the total nr. of entries, should equal
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900849 newinfo->nentries afterwards */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
851 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro0e795532006-11-30 19:27:13 -0800852 ebt_check_entry_size_and_hooks, newinfo,
853 &i, &j, &k, &udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854
855 if (ret != 0)
856 return ret;
857
858 if (i != j) {
859 BUGPRINT("nentries does not equal the nr of entries in the "
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +0900860 "(last) chain\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 return -EINVAL;
862 }
863 if (k != newinfo->nentries) {
864 BUGPRINT("Total nentries is wrong\n");
865 return -EINVAL;
866 }
867
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 /* get the location of the udc, put them in an array
869 while we're at it, allocate the chainstack */
870 if (udc_cnt) {
871 /* this will get free'd in do_replace()/ebt_register_table()
872 if an error occurs */
Jayachandran C7ad4d2f2006-04-11 17:25:38 -0700873 newinfo->chainstack =
Christoph Lameter53b8a312007-02-20 13:57:51 -0800874 vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 if (!newinfo->chainstack)
876 return -ENOMEM;
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700877 for_each_possible_cpu(i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 newinfo->chainstack[i] =
Jayachandran C18bc89a2006-04-20 00:14:49 -0700879 vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0])));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 if (!newinfo->chainstack[i]) {
881 while (i)
882 vfree(newinfo->chainstack[--i]);
883 vfree(newinfo->chainstack);
884 newinfo->chainstack = NULL;
885 return -ENOMEM;
886 }
887 }
888
Jayachandran C18bc89a2006-04-20 00:14:49 -0700889 cl_s = vmalloc(udc_cnt * sizeof(*cl_s));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 if (!cl_s)
891 return -ENOMEM;
892 i = 0; /* the i'th udc */
893 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Al Viro177abc32006-11-30 19:27:32 -0800894 ebt_get_udc_positions, newinfo, &i, cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 /* sanity check */
896 if (i != udc_cnt) {
897 BUGPRINT("i != udc_cnt\n");
898 vfree(cl_s);
899 return -EFAULT;
900 }
901 }
902
903 /* Check for loops */
904 for (i = 0; i < NF_BR_NUMHOOKS; i++)
Al Viro1f072c92006-11-30 19:26:53 -0800905 if (newinfo->hook_entry[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 if (check_chainloops(newinfo->hook_entry[i],
907 cl_s, udc_cnt, i, newinfo->entries)) {
James Lamanna68d31872005-06-22 22:12:57 -0700908 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 return -EINVAL;
910 }
911
Jan Engelhardt96de0e22007-10-19 23:21:04 +0200912 /* we now know the following (along with E=mc²):
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 - the nr of entries in each chain is right
914 - the size of the allocated space is right
915 - all valid hooks have a corresponding chain
916 - there are no loops
917 - wrong data can still be on the level of a single entry
918 - could be there are jumps to places that are not the
919 beginning of a chain. This can only occur in chains that
920 are not accessible from any base chains, so we don't care. */
921
922 /* used to know what we need to clean up if something goes wrong */
923 i = 0;
924 ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Alexey Dobriyana83d8e82010-01-18 08:21:13 +0100925 ebt_check_entry, net, newinfo, name, &i, cl_s, udc_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 if (ret != 0) {
927 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Alexey Dobriyanf54e9362010-01-18 08:25:47 +0100928 ebt_cleanup_entry, net, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 }
James Lamanna68d31872005-06-22 22:12:57 -0700930 vfree(cl_s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 return ret;
932}
933
934/* called under write_lock */
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +0200935static void get_counters(const struct ebt_counter *oldcounters,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 struct ebt_counter *counters, unsigned int nentries)
937{
938 int i, cpu;
939 struct ebt_counter *counter_base;
940
941 /* counters of cpu 0 */
942 memcpy(counters, oldcounters,
David S. Millerc8923c62005-10-13 14:41:23 -0700943 sizeof(struct ebt_counter) * nentries);
944
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 /* add other counters to those of cpu 0 */
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -0700946 for_each_possible_cpu(cpu) {
David S. Millerc8923c62005-10-13 14:41:23 -0700947 if (cpu == 0)
948 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
950 for (i = 0; i < nentries; i++) {
951 counters[i].pcnt += counter_base[i].pcnt;
952 counters[i].bcnt += counter_base[i].bcnt;
953 }
954 }
955}
956
Florian Westphale7887592010-02-04 18:38:53 +0100957static int do_replace_finish(struct net *net, struct ebt_replace *repl,
958 struct ebt_table_info *newinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959{
Florian Westphale7887592010-02-04 18:38:53 +0100960 int ret, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 struct ebt_counter *counterstmp = NULL;
962 /* used to be able to unlock earlier */
963 struct ebt_table_info *table;
Florian Westphale7887592010-02-04 18:38:53 +0100964 struct ebt_table *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
966 /* the user wants counters back
967 the check on the size is done later, when we have the lock */
Florian Westphale7887592010-02-04 18:38:53 +0100968 if (repl->num_counters) {
969 unsigned long size = repl->num_counters * sizeof(*counterstmp);
970 counterstmp = vmalloc(size);
971 if (!counterstmp)
972 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 newinfo->chainstack = NULL;
Florian Westphale7887592010-02-04 18:38:53 +0100976 ret = ebt_verify_pointers(repl, newinfo);
Al Viro1bc23262006-11-30 19:28:08 -0800977 if (ret != 0)
978 goto free_counterstmp;
979
Florian Westphale7887592010-02-04 18:38:53 +0100980 ret = translate_table(net, repl->name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
982 if (ret != 0)
983 goto free_counterstmp;
984
Florian Westphale7887592010-02-04 18:38:53 +0100985 t = find_table_lock(net, repl->name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 if (!t) {
987 ret = -ENOENT;
988 goto free_iterate;
989 }
990
991 /* the table doesn't like it */
Florian Westphale7887592010-02-04 18:38:53 +0100992 if (t->check && (ret = t->check(newinfo, repl->valid_hooks)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 goto free_unlock;
994
Florian Westphale7887592010-02-04 18:38:53 +0100995 if (repl->num_counters && repl->num_counters != t->private->nentries) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 BUGPRINT("Wrong nr. of counters requested\n");
997 ret = -EINVAL;
998 goto free_unlock;
999 }
1000
1001 /* we have the mutex lock, so no danger in reading this pointer */
1002 table = t->private;
1003 /* make sure the table can only be rmmod'ed if it contains no rules */
1004 if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) {
1005 ret = -ENOENT;
1006 goto free_unlock;
1007 } else if (table->nentries && !newinfo->nentries)
1008 module_put(t->me);
1009 /* we need an atomic snapshot of the counters */
1010 write_lock_bh(&t->lock);
Florian Westphale7887592010-02-04 18:38:53 +01001011 if (repl->num_counters)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 get_counters(t->private->counters, counterstmp,
1013 t->private->nentries);
1014
1015 t->private = newinfo;
1016 write_unlock_bh(&t->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001017 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 /* so, a user can change the chains while having messed up her counter
1019 allocation. Only reason why this is done is because this way the lock
1020 is held only once, while this doesn't bring the kernel into a
1021 dangerous state. */
Florian Westphale7887592010-02-04 18:38:53 +01001022 if (repl->num_counters &&
1023 copy_to_user(repl->counters, counterstmp,
1024 repl->num_counters * sizeof(struct ebt_counter))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 ret = -EFAULT;
1026 }
1027 else
1028 ret = 0;
1029
1030 /* decrease module count and free resources */
1031 EBT_ENTRY_ITERATE(table->entries, table->entries_size,
Alexey Dobriyanf54e9362010-01-18 08:25:47 +01001032 ebt_cleanup_entry, net, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
1034 vfree(table->entries);
1035 if (table->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001036 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 vfree(table->chainstack[i]);
1038 vfree(table->chainstack);
1039 }
1040 vfree(table);
1041
James Lamanna68d31872005-06-22 22:12:57 -07001042 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 return ret;
1044
1045free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001046 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047free_iterate:
1048 EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
Alexey Dobriyanf54e9362010-01-18 08:25:47 +01001049 ebt_cleanup_entry, net, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050free_counterstmp:
James Lamanna68d31872005-06-22 22:12:57 -07001051 vfree(counterstmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 /* can be initialized in translate_table() */
1053 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001054 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 vfree(newinfo->chainstack[i]);
1056 vfree(newinfo->chainstack);
1057 }
Florian Westphale7887592010-02-04 18:38:53 +01001058 return ret;
1059}
1060
1061/* replace the table */
1062static int do_replace(struct net *net, const void __user *user,
1063 unsigned int len)
1064{
1065 int ret, countersize;
1066 struct ebt_table_info *newinfo;
1067 struct ebt_replace tmp;
1068
1069 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1070 return -EFAULT;
1071
1072 if (len != sizeof(tmp) + tmp.entries_size) {
1073 BUGPRINT("Wrong len argument\n");
1074 return -EINVAL;
1075 }
1076
1077 if (tmp.entries_size == 0) {
1078 BUGPRINT("Entries_size never zero\n");
1079 return -EINVAL;
1080 }
1081 /* overflow check */
1082 if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) /
1083 NR_CPUS - SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
1084 return -ENOMEM;
1085 if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
1086 return -ENOMEM;
1087
1088 countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids;
1089 newinfo = vmalloc(sizeof(*newinfo) + countersize);
1090 if (!newinfo)
1091 return -ENOMEM;
1092
1093 if (countersize)
1094 memset(newinfo->counters, 0, countersize);
1095
1096 newinfo->entries = vmalloc(tmp.entries_size);
1097 if (!newinfo->entries) {
1098 ret = -ENOMEM;
1099 goto free_newinfo;
1100 }
1101 if (copy_from_user(
1102 newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
1103 BUGPRINT("Couldn't copy entries from userspace\n");
1104 ret = -EFAULT;
1105 goto free_entries;
1106 }
1107
1108 ret = do_replace_finish(net, &tmp, newinfo);
1109 if (ret == 0)
1110 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111free_entries:
James Lamanna68d31872005-06-22 22:12:57 -07001112 vfree(newinfo->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113free_newinfo:
James Lamanna68d31872005-06-22 22:12:57 -07001114 vfree(newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 return ret;
1116}
1117
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001118struct ebt_table *
1119ebt_register_table(struct net *net, const struct ebt_table *input_table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120{
1121 struct ebt_table_info *newinfo;
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001122 struct ebt_table *t, *table;
Al Viro1e419cd2006-11-30 19:28:48 -08001123 struct ebt_replace_kernel *repl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 int ret, i, countersize;
Al Virodf07a812006-11-30 19:28:25 -08001125 void *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001127 if (input_table == NULL || (repl = input_table->table) == NULL ||
1128 repl->entries == 0 || repl->entries_size == 0 ||
1129 repl->counters != NULL || input_table->private != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 BUGPRINT("Bad table data for ebt_register_table!!!\n");
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001131 return ERR_PTR(-EINVAL);
1132 }
1133
1134 /* Don't add one table to multiple lists. */
Jan Engelhardt35aad0f2009-08-24 14:56:30 +02001135 table = kmemdup(input_table, sizeof(struct ebt_table), GFP_KERNEL);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001136 if (!table) {
1137 ret = -ENOMEM;
1138 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 }
1140
Christoph Lameter53b8a312007-02-20 13:57:51 -08001141 countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
Jayachandran C18bc89a2006-04-20 00:14:49 -07001142 newinfo = vmalloc(sizeof(*newinfo) + countersize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 ret = -ENOMEM;
1144 if (!newinfo)
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001145 goto free_table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
Al Virodf07a812006-11-30 19:28:25 -08001147 p = vmalloc(repl->entries_size);
1148 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 goto free_newinfo;
1150
Al Virodf07a812006-11-30 19:28:25 -08001151 memcpy(p, repl->entries, repl->entries_size);
1152 newinfo->entries = p;
1153
1154 newinfo->entries_size = repl->entries_size;
1155 newinfo->nentries = repl->nentries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
1157 if (countersize)
1158 memset(newinfo->counters, 0, countersize);
1159
1160 /* fill in newinfo and parse the entries */
1161 newinfo->chainstack = NULL;
Al Virodf07a812006-11-30 19:28:25 -08001162 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
1163 if ((repl->valid_hooks & (1 << i)) == 0)
1164 newinfo->hook_entry[i] = NULL;
1165 else
1166 newinfo->hook_entry[i] = p +
1167 ((char *)repl->hook_entry[i] - repl->entries);
1168 }
Alexey Dobriyana83d8e82010-01-18 08:21:13 +01001169 ret = translate_table(net, repl->name, newinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 if (ret != 0) {
1171 BUGPRINT("Translate_table failed\n");
1172 goto free_chainstack;
1173 }
1174
1175 if (table->check && table->check(newinfo, table->valid_hooks)) {
1176 BUGPRINT("The table doesn't like its own initial data, lol\n");
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001177 return ERR_PTR(-EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 }
1179
1180 table->private = newinfo;
1181 rwlock_init(&table->lock);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001182 ret = mutex_lock_interruptible(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 if (ret != 0)
1184 goto free_chainstack;
1185
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001186 list_for_each_entry(t, &net->xt.tables[NFPROTO_BRIDGE], list) {
Patrick McHardydf0933d2006-09-20 11:57:53 -07001187 if (strcmp(t->name, table->name) == 0) {
1188 ret = -EEXIST;
1189 BUGPRINT("Table name already exists\n");
1190 goto free_unlock;
1191 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 }
1193
1194 /* Hold a reference count if the chains aren't empty */
1195 if (newinfo->nentries && !try_module_get(table->me)) {
1196 ret = -ENOENT;
1197 goto free_unlock;
1198 }
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001199 list_add(&table->list, &net->xt.tables[NFPROTO_BRIDGE]);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001200 mutex_unlock(&ebt_mutex);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001201 return table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202free_unlock:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001203 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204free_chainstack:
1205 if (newinfo->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001206 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 vfree(newinfo->chainstack[i]);
1208 vfree(newinfo->chainstack);
1209 }
1210 vfree(newinfo->entries);
1211free_newinfo:
1212 vfree(newinfo);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001213free_table:
1214 kfree(table);
1215out:
1216 return ERR_PTR(ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217}
1218
Alexey Dobriyanf54e9362010-01-18 08:25:47 +01001219void ebt_unregister_table(struct net *net, struct ebt_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220{
1221 int i;
1222
1223 if (!table) {
1224 BUGPRINT("Request to unregister NULL table!!!\n");
1225 return;
1226 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001227 mutex_lock(&ebt_mutex);
Patrick McHardydf0933d2006-09-20 11:57:53 -07001228 list_del(&table->list);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001229 mutex_unlock(&ebt_mutex);
Alexey Dobriyandbcdf852008-11-04 14:28:04 +01001230 EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size,
Alexey Dobriyanf54e9362010-01-18 08:25:47 +01001231 ebt_cleanup_entry, net, NULL);
Alexey Dobriyandbcdf852008-11-04 14:28:04 +01001232 if (table->private->nentries)
1233 module_put(table->me);
James Lamanna68d31872005-06-22 22:12:57 -07001234 vfree(table->private->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 if (table->private->chainstack) {
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001236 for_each_possible_cpu(i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 vfree(table->private->chainstack[i]);
1238 vfree(table->private->chainstack);
1239 }
1240 vfree(table->private);
Alexey Dobriyan6beceee2008-11-04 14:27:15 +01001241 kfree(table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242}
1243
1244/* userspace just supplied us with counters */
Florian Westphal49facff2010-02-07 02:48:47 +01001245static int do_update_counters(struct net *net, const char *name,
1246 struct ebt_counter __user *counters,
1247 unsigned int num_counters,
1248 const void __user *user, unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249{
1250 int i, ret;
1251 struct ebt_counter *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 struct ebt_table *t;
1253
Florian Westphal49facff2010-02-07 02:48:47 +01001254 if (num_counters == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 return -EINVAL;
1256
Florian Westphal49facff2010-02-07 02:48:47 +01001257 tmp = vmalloc(num_counters * sizeof(*tmp));
1258 if (!tmp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260
Florian Westphal49facff2010-02-07 02:48:47 +01001261 t = find_table_lock(net, name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 if (!t)
1263 goto free_tmp;
1264
Florian Westphal49facff2010-02-07 02:48:47 +01001265 if (num_counters != t->private->nentries) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 BUGPRINT("Wrong nr of counters\n");
1267 ret = -EINVAL;
1268 goto unlock_mutex;
1269 }
1270
Florian Westphal49facff2010-02-07 02:48:47 +01001271 if (copy_from_user(tmp, counters, num_counters * sizeof(*counters))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 ret = -EFAULT;
1273 goto unlock_mutex;
1274 }
1275
1276 /* we want an atomic add of the counters */
1277 write_lock_bh(&t->lock);
1278
1279 /* we add to the counters of the first cpu */
Florian Westphal49facff2010-02-07 02:48:47 +01001280 for (i = 0; i < num_counters; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 t->private->counters[i].pcnt += tmp[i].pcnt;
1282 t->private->counters[i].bcnt += tmp[i].bcnt;
1283 }
1284
1285 write_unlock_bh(&t->lock);
1286 ret = 0;
1287unlock_mutex:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001288 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289free_tmp:
1290 vfree(tmp);
1291 return ret;
1292}
1293
Florian Westphal49facff2010-02-07 02:48:47 +01001294static int update_counters(struct net *net, const void __user *user,
1295 unsigned int len)
1296{
1297 struct ebt_replace hlp;
1298
1299 if (copy_from_user(&hlp, user, sizeof(hlp)))
1300 return -EFAULT;
1301
1302 if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
1303 return -EINVAL;
1304
1305 return do_update_counters(net, hlp.name, hlp.counters,
1306 hlp.num_counters, user, len);
1307}
1308
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +02001309static inline int ebt_make_matchname(const struct ebt_entry_match *m,
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 *)m - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
1314 return -EFAULT;
1315 return 0;
1316}
1317
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +02001318static inline int ebt_make_watchername(const struct ebt_entry_watcher *w,
1319 const char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320{
Al Viro1e419cd2006-11-30 19:28:48 -08001321 char __user *hlp = ubase + ((char *)w - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
1323 return -EFAULT;
1324 return 0;
1325}
1326
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +02001327static inline int
1328ebt_make_names(struct ebt_entry *e, const char *base, char __user *ubase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329{
1330 int ret;
Al Viro1e419cd2006-11-30 19:28:48 -08001331 char __user *hlp;
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +02001332 const struct ebt_entry_target *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333
Al Viro40642f92006-11-30 19:24:12 -08001334 if (e->bitmask == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 return 0;
1336
Al Viro1e419cd2006-11-30 19:28:48 -08001337 hlp = ubase + (((char *)e + e->target_offset) - base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
YOSHIFUJI Hideaki9d6f2292007-02-09 23:24:35 +09001339
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
1341 if (ret != 0)
1342 return ret;
1343 ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
1344 if (ret != 0)
1345 return ret;
1346 if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
1347 return -EFAULT;
1348 return 0;
1349}
1350
Florian Westphal837395a2010-02-07 02:11:34 +01001351static int copy_counters_to_user(struct ebt_table *t,
1352 const struct ebt_counter *oldcounters,
1353 void __user *user, unsigned int num_counters,
1354 unsigned int nentries)
1355{
1356 struct ebt_counter *counterstmp;
1357 int ret = 0;
1358
1359 /* userspace might not need the counters */
1360 if (num_counters == 0)
1361 return 0;
1362
1363 if (num_counters != nentries) {
1364 BUGPRINT("Num_counters wrong\n");
1365 return -EINVAL;
1366 }
1367
1368 counterstmp = vmalloc(nentries * sizeof(*counterstmp));
1369 if (!counterstmp)
1370 return -ENOMEM;
1371
1372 write_lock_bh(&t->lock);
1373 get_counters(oldcounters, counterstmp, nentries);
1374 write_unlock_bh(&t->lock);
1375
1376 if (copy_to_user(user, counterstmp,
1377 nentries * sizeof(struct ebt_counter)))
1378 ret = -EFAULT;
1379 vfree(counterstmp);
1380 return ret;
1381}
1382
Ingo Molnar57b47a52006-03-20 22:35:41 -08001383/* called with ebt_mutex locked */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384static int copy_everything_to_user(struct ebt_table *t, void __user *user,
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +02001385 const int *len, int cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386{
1387 struct ebt_replace tmp;
Jan Engelhardtd5d1baa2009-06-26 07:51:59 +02001388 const struct ebt_counter *oldcounters;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 unsigned int entries_size, nentries;
Florian Westphal837395a2010-02-07 02:11:34 +01001390 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 char *entries;
1392
1393 if (cmd == EBT_SO_GET_ENTRIES) {
1394 entries_size = t->private->entries_size;
1395 nentries = t->private->nentries;
1396 entries = t->private->entries;
1397 oldcounters = t->private->counters;
1398 } else {
1399 entries_size = t->table->entries_size;
1400 nentries = t->table->nentries;
1401 entries = t->table->entries;
1402 oldcounters = t->table->counters;
1403 }
1404
1405 if (copy_from_user(&tmp, user, sizeof(tmp))) {
1406 BUGPRINT("Cfu didn't work\n");
1407 return -EFAULT;
1408 }
1409
1410 if (*len != sizeof(struct ebt_replace) + entries_size +
1411 (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
1412 BUGPRINT("Wrong size\n");
1413 return -EINVAL;
1414 }
1415
1416 if (tmp.nentries != nentries) {
1417 BUGPRINT("Nentries wrong\n");
1418 return -EINVAL;
1419 }
1420
1421 if (tmp.entries_size != entries_size) {
1422 BUGPRINT("Wrong size\n");
1423 return -EINVAL;
1424 }
1425
Florian Westphal837395a2010-02-07 02:11:34 +01001426 ret = copy_counters_to_user(t, oldcounters, tmp.counters,
1427 tmp.num_counters, nentries);
1428 if (ret)
1429 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430
1431 if (copy_to_user(tmp.entries, entries, entries_size)) {
1432 BUGPRINT("Couldn't copy entries to userspace\n");
1433 return -EFAULT;
1434 }
1435 /* set the match/watcher/target names right */
1436 return EBT_ENTRY_ITERATE(entries, entries_size,
1437 ebt_make_names, entries, tmp.entries);
1438}
1439
1440static int do_ebt_set_ctl(struct sock *sk,
1441 int cmd, void __user *user, unsigned int len)
1442{
1443 int ret;
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 switch(cmd) {
1449 case EBT_SO_SET_ENTRIES:
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001450 ret = do_replace(sock_net(sk), user, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 break;
1452 case EBT_SO_SET_COUNTERS:
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001453 ret = update_counters(sock_net(sk), user, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 break;
1455 default:
1456 ret = -EINVAL;
1457 }
1458 return ret;
1459}
1460
1461static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1462{
1463 int ret;
1464 struct ebt_replace tmp;
1465 struct ebt_table *t;
1466
Florian Westphaldce766a2010-01-08 17:31:24 +01001467 if (!capable(CAP_NET_ADMIN))
1468 return -EPERM;
1469
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 if (copy_from_user(&tmp, user, sizeof(tmp)))
1471 return -EFAULT;
1472
Alexey Dobriyan511061e2008-11-04 14:22:55 +01001473 t = find_table_lock(sock_net(sk), tmp.name, &ret, &ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 if (!t)
1475 return ret;
1476
1477 switch(cmd) {
1478 case EBT_SO_GET_INFO:
1479 case EBT_SO_GET_INIT_INFO:
1480 if (*len != sizeof(struct ebt_replace)){
1481 ret = -EINVAL;
Ingo Molnar57b47a52006-03-20 22:35:41 -08001482 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 break;
1484 }
1485 if (cmd == EBT_SO_GET_INFO) {
1486 tmp.nentries = t->private->nentries;
1487 tmp.entries_size = t->private->entries_size;
1488 tmp.valid_hooks = t->valid_hooks;
1489 } else {
1490 tmp.nentries = t->table->nentries;
1491 tmp.entries_size = t->table->entries_size;
1492 tmp.valid_hooks = t->table->valid_hooks;
1493 }
Ingo Molnar57b47a52006-03-20 22:35:41 -08001494 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 if (copy_to_user(user, &tmp, *len) != 0){
1496 BUGPRINT("c2u Didn't work\n");
1497 ret = -EFAULT;
1498 break;
1499 }
1500 ret = 0;
1501 break;
1502
1503 case EBT_SO_GET_ENTRIES:
1504 case EBT_SO_GET_INIT_ENTRIES:
1505 ret = copy_everything_to_user(t, user, len, cmd);
Ingo Molnar57b47a52006-03-20 22:35:41 -08001506 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 break;
1508
1509 default:
Ingo Molnar57b47a52006-03-20 22:35:41 -08001510 mutex_unlock(&ebt_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 ret = -EINVAL;
1512 }
1513
1514 return ret;
1515}
1516
1517static struct nf_sockopt_ops ebt_sockopts =
Andrew Morton74ca4e5a2006-03-20 22:55:02 -08001518{
1519 .pf = PF_INET,
1520 .set_optmin = EBT_BASE_CTL,
1521 .set_optmax = EBT_SO_SET_MAX + 1,
1522 .set = do_ebt_set_ctl,
1523 .get_optmin = EBT_BASE_CTL,
1524 .get_optmax = EBT_SO_GET_MAX + 1,
1525 .get = do_ebt_get_ctl,
Neil Horman16fcec32007-09-11 11:28:26 +02001526 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527};
1528
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001529static int __init ebtables_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530{
1531 int ret;
1532
Jan Engelhardt043ef462008-10-08 11:35:15 +02001533 ret = xt_register_target(&ebt_standard_target);
1534 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 return ret;
Jan Engelhardt043ef462008-10-08 11:35:15 +02001536 ret = nf_register_sockopt(&ebt_sockopts);
1537 if (ret < 0) {
1538 xt_unregister_target(&ebt_standard_target);
1539 return ret;
1540 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541
Patrick McHardya887c1c2007-07-14 20:46:15 -07001542 printk(KERN_INFO "Ebtables v2.0 registered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 return 0;
1544}
1545
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001546static void __exit ebtables_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547{
1548 nf_unregister_sockopt(&ebt_sockopts);
Jan Engelhardt043ef462008-10-08 11:35:15 +02001549 xt_unregister_target(&ebt_standard_target);
Patrick McHardya887c1c2007-07-14 20:46:15 -07001550 printk(KERN_INFO "Ebtables v2.0 unregistered\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551}
1552
1553EXPORT_SYMBOL(ebt_register_table);
1554EXPORT_SYMBOL(ebt_unregister_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555EXPORT_SYMBOL(ebt_do_table);
Andrew Morton65b4b4e2006-03-28 16:37:06 -08001556module_init(ebtables_init);
1557module_exit(ebtables_fini);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558MODULE_LICENSE("GPL");