2019-05-19 06:08:20 -06:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2005-04-16 16:20:36 -06:00
|
|
|
/*
|
|
|
|
* Packet matching code for ARP packets.
|
|
|
|
*
|
|
|
|
* Based heavily, if not almost entirely, upon ip_tables.c framework.
|
|
|
|
*
|
|
|
|
* Some ARP specific bits are:
|
|
|
|
*
|
|
|
|
* Copyright (C) 2002 David S. Miller (davem@redhat.com)
|
2013-04-06 07:24:29 -06:00
|
|
|
* Copyright (C) 2006-2009 Patrick McHardy <kaber@trash.net>
|
2005-04-16 16:20:36 -06:00
|
|
|
*
|
|
|
|
*/
|
2009-07-09 14:54:53 -06:00
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
2005-04-16 16:20:36 -06:00
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/skbuff.h>
|
|
|
|
#include <linux/netdevice.h>
|
2006-01-11 13:17:47 -07:00
|
|
|
#include <linux/capability.h>
|
2005-04-16 16:20:36 -06:00
|
|
|
#include <linux/if_arp.h>
|
|
|
|
#include <linux/kmod.h>
|
|
|
|
#include <linux/vmalloc.h>
|
|
|
|
#include <linux/proc_fs.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/init.h>
|
2006-03-20 23:35:41 -07:00
|
|
|
#include <linux/mutex.h>
|
2007-12-17 23:26:54 -07:00
|
|
|
#include <linux/err.h>
|
|
|
|
#include <net/compat.h>
|
2008-01-31 05:04:32 -07:00
|
|
|
#include <net/sock.h>
|
2016-12-24 12:46:01 -07:00
|
|
|
#include <linux/uaccess.h>
|
2005-04-16 16:20:36 -06:00
|
|
|
|
[NETFILTER] x_tables: Abstraction layer for {ip,ip6,arp}_tables
This monster-patch tries to do the best job for unifying the data
structures and backend interfaces for the three evil clones ip_tables,
ip6_tables and arp_tables. In an ideal world we would never have
allowed this kind of copy+paste programming... but well, our world
isn't (yet?) ideal.
o introduce a new x_tables module
o {ip,arp,ip6}_tables depend on this x_tables module
o registration functions for tables, matches and targets are only
wrappers around x_tables provided functions
o all matches/targets that are used from ip_tables and ip6_tables
are now implemented as xt_FOOBAR.c files and provide module aliases
to ipt_FOOBAR and ip6t_FOOBAR
o header files for xt_matches are in include/linux/netfilter/,
include/linux/netfilter_{ipv4,ipv6} contains compatibility wrappers
around the xt_FOOBAR.h headers
Based on this patchset we're going to further unify the code,
gradually getting rid of all the layer 3 specific assumptions.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-01-12 14:30:04 -07:00
|
|
|
#include <linux/netfilter/x_tables.h>
|
2005-04-16 16:20:36 -06:00
|
|
|
#include <linux/netfilter_arp/arp_tables.h>
|
2009-06-17 14:14:54 -06:00
|
|
|
#include "../../netfilter/xt_repldata.h"
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
|
|
|
|
MODULE_DESCRIPTION("arptables core");
|
|
|
|
|
2009-06-17 14:14:54 -06:00
|
|
|
void *arpt_alloc_initial_table(const struct xt_table *info)
|
|
|
|
{
|
|
|
|
return xt_alloc_initial_table(arpt, ARPT);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(arpt_alloc_initial_table);
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap,
|
2008-04-14 03:15:35 -06:00
|
|
|
const char *hdr_addr, int len)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
int i, ret;
|
|
|
|
|
|
|
|
if (len > ARPT_DEV_ADDR_LEN_MAX)
|
|
|
|
len = ARPT_DEV_ADDR_LEN_MAX;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
ret |= (hdr_addr[i] ^ ap->addr[i]) & ap->mask[i];
|
|
|
|
|
2010-09-22 14:43:57 -06:00
|
|
|
return ret != 0;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
2009-02-18 09:47:50 -07:00
|
|
|
/*
|
2011-03-30 19:57:33 -06:00
|
|
|
* Unfortunately, _b and _mask are not aligned to an int (or long int)
|
2009-02-18 09:47:50 -07:00
|
|
|
* Some arches dont care, unrolling the loop is a win on them.
|
2009-03-24 15:15:22 -06:00
|
|
|
* For other arches, we only have a 16bit alignement.
|
2009-02-18 09:47:50 -07:00
|
|
|
*/
|
|
|
|
static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
|
2009-03-25 10:31:52 -06:00
|
|
|
unsigned long ret = ifname_compare_aligned(_a, _b, _mask);
|
2009-02-18 09:47:50 -07:00
|
|
|
#else
|
|
|
|
unsigned long ret = 0;
|
2009-03-24 15:15:22 -06:00
|
|
|
const u16 *a = (const u16 *)_a;
|
|
|
|
const u16 *b = (const u16 *)_b;
|
|
|
|
const u16 *mask = (const u16 *)_mask;
|
2009-02-18 09:47:50 -07:00
|
|
|
int i;
|
|
|
|
|
2009-03-24 15:15:22 -06:00
|
|
|
for (i = 0; i < IFNAMSIZ/sizeof(u16); i++)
|
|
|
|
ret |= (a[i] ^ b[i]) & mask[i];
|
2009-02-18 09:47:50 -07:00
|
|
|
#endif
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/* Returns whether packet matches rule or not. */
|
|
|
|
static inline int arp_packet_match(const struct arphdr *arphdr,
|
|
|
|
struct net_device *dev,
|
|
|
|
const char *indev,
|
|
|
|
const char *outdev,
|
|
|
|
const struct arpt_arp *arpinfo)
|
|
|
|
{
|
2008-04-14 03:15:35 -06:00
|
|
|
const char *arpptr = (char *)(arphdr + 1);
|
|
|
|
const char *src_devaddr, *tgt_devaddr;
|
2006-09-28 15:21:07 -06:00
|
|
|
__be32 src_ipaddr, tgt_ipaddr;
|
2009-02-18 09:47:50 -07:00
|
|
|
long ret;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2016-06-24 14:25:22 -06:00
|
|
|
if (NF_INVF(arpinfo, ARPT_INV_ARPOP,
|
|
|
|
(arphdr->ar_op & arpinfo->arpop_mask) != arpinfo->arpop))
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
|
2016-06-24 14:25:22 -06:00
|
|
|
if (NF_INVF(arpinfo, ARPT_INV_ARPHRD,
|
|
|
|
(arphdr->ar_hrd & arpinfo->arhrd_mask) != arpinfo->arhrd))
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
|
2016-06-24 14:25:22 -06:00
|
|
|
if (NF_INVF(arpinfo, ARPT_INV_ARPPRO,
|
|
|
|
(arphdr->ar_pro & arpinfo->arpro_mask) != arpinfo->arpro))
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
|
2016-06-24 14:25:22 -06:00
|
|
|
if (NF_INVF(arpinfo, ARPT_INV_ARPHLN,
|
|
|
|
(arphdr->ar_hln & arpinfo->arhln_mask) != arpinfo->arhln))
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
src_devaddr = arpptr;
|
|
|
|
arpptr += dev->addr_len;
|
|
|
|
memcpy(&src_ipaddr, arpptr, sizeof(u32));
|
|
|
|
arpptr += sizeof(u32);
|
|
|
|
tgt_devaddr = arpptr;
|
|
|
|
arpptr += dev->addr_len;
|
|
|
|
memcpy(&tgt_ipaddr, arpptr, sizeof(u32));
|
|
|
|
|
2016-06-24 14:25:22 -06:00
|
|
|
if (NF_INVF(arpinfo, ARPT_INV_SRCDEVADDR,
|
|
|
|
arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr,
|
|
|
|
dev->addr_len)) ||
|
|
|
|
NF_INVF(arpinfo, ARPT_INV_TGTDEVADDR,
|
|
|
|
arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr,
|
|
|
|
dev->addr_len)))
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
|
2016-06-24 14:25:22 -06:00
|
|
|
if (NF_INVF(arpinfo, ARPT_INV_SRCIP,
|
|
|
|
(src_ipaddr & arpinfo->smsk.s_addr) != arpinfo->src.s_addr) ||
|
|
|
|
NF_INVF(arpinfo, ARPT_INV_TGTIP,
|
|
|
|
(tgt_ipaddr & arpinfo->tmsk.s_addr) != arpinfo->tgt.s_addr))
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Look for ifname matches. */
|
2009-02-18 09:47:50 -07:00
|
|
|
ret = ifname_compare(indev, arpinfo->iniface, arpinfo->iniface_mask);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2016-06-24 14:25:22 -06:00
|
|
|
if (NF_INVF(arpinfo, ARPT_INV_VIA_IN, ret != 0))
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
|
2009-02-18 09:47:50 -07:00
|
|
|
ret = ifname_compare(outdev, arpinfo->outiface, arpinfo->outiface_mask);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2016-06-24 14:25:22 -06:00
|
|
|
if (NF_INVF(arpinfo, ARPT_INV_VIA_OUT, ret != 0))
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int arp_checkentry(const struct arpt_arp *arp)
|
|
|
|
{
|
2016-05-03 05:54:23 -06:00
|
|
|
if (arp->flags & ~ARPT_F_MASK)
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
2016-05-03 05:54:23 -06:00
|
|
|
if (arp->invflags & ~ARPT_INV_MASK)
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-10-08 03:35:19 -06:00
|
|
|
static unsigned int
|
2009-07-05 11:43:26 -06:00
|
|
|
arpt_error(struct sk_buff *skb, const struct xt_action_param *par)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2012-05-13 15:56:26 -06:00
|
|
|
net_err_ratelimited("arp_tables: error: '%s'\n",
|
|
|
|
(const char *)par->targinfo);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
return NF_DROP;
|
|
|
|
}
|
|
|
|
|
2010-10-13 08:11:22 -06:00
|
|
|
static inline const struct xt_entry_target *
|
2009-06-25 23:51:59 -06:00
|
|
|
arpt_get_target_c(const struct arpt_entry *e)
|
|
|
|
{
|
|
|
|
return arpt_get_target((struct arpt_entry *)e);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline struct arpt_entry *
|
|
|
|
get_entry(const void *base, unsigned int offset)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
return (struct arpt_entry *)(base + offset);
|
|
|
|
}
|
|
|
|
|
2015-07-14 09:51:10 -06:00
|
|
|
static inline
|
2009-04-15 13:06:05 -06:00
|
|
|
struct arpt_entry *arpt_next_entry(const struct arpt_entry *entry)
|
|
|
|
{
|
|
|
|
return (void *)entry + entry->next_offset;
|
|
|
|
}
|
|
|
|
|
2007-10-15 01:53:15 -06:00
|
|
|
unsigned int arpt_do_table(struct sk_buff *skb,
|
2015-04-03 19:18:46 -06:00
|
|
|
const struct nf_hook_state *state,
|
2008-04-14 03:15:43 -06:00
|
|
|
struct xt_table *table)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2015-09-18 13:32:55 -06:00
|
|
|
unsigned int hook = state->hook;
|
2009-02-18 09:47:50 -07:00
|
|
|
static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
|
2005-04-16 16:20:36 -06:00
|
|
|
unsigned int verdict = NF_DROP;
|
2008-04-14 03:15:35 -06:00
|
|
|
const struct arphdr *arp;
|
2015-06-30 14:21:00 -06:00
|
|
|
struct arpt_entry *e, **jumpstack;
|
2005-04-16 16:20:36 -06:00
|
|
|
const char *indev, *outdev;
|
2015-06-15 10:57:30 -06:00
|
|
|
const void *table_base;
|
2015-06-30 14:21:00 -06:00
|
|
|
unsigned int cpu, stackidx = 0;
|
2008-04-14 03:15:35 -06:00
|
|
|
const struct xt_table_info *private;
|
2009-07-05 10:26:37 -06:00
|
|
|
struct xt_action_param acpar;
|
2011-04-04 09:04:03 -06:00
|
|
|
unsigned int addend;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2008-03-03 13:20:57 -07:00
|
|
|
if (!pskb_may_pull(skb, arp_hdr_len(skb->dev)))
|
2005-04-16 16:20:36 -06:00
|
|
|
return NF_DROP;
|
|
|
|
|
2015-04-03 19:18:46 -06:00
|
|
|
indev = state->in ? state->in->name : nulldevname;
|
|
|
|
outdev = state->out ? state->out->name : nulldevname;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2011-04-04 09:04:03 -06:00
|
|
|
local_bh_disable();
|
|
|
|
addend = xt_write_recseq_begin();
|
2017-10-09 13:09:04 -06:00
|
|
|
private = READ_ONCE(table->private); /* Address dependency. */
|
2015-06-30 14:21:00 -06:00
|
|
|
cpu = smp_processor_id();
|
2015-06-10 17:34:55 -06:00
|
|
|
table_base = private->entries;
|
2015-06-30 14:21:00 -06:00
|
|
|
jumpstack = (struct arpt_entry **)private->jumpstack[cpu];
|
2009-02-20 02:35:32 -07:00
|
|
|
|
netfilter: xtables: don't save/restore jumpstack offset
In most cases there is no reentrancy into ip/ip6tables.
For skbs sent by REJECT or SYNPROXY targets, there is one level
of reentrancy, but its not relevant as those targets issue an absolute
verdict, i.e. the jumpstack can be clobbered since its not used
after the target issues absolute verdict (ACCEPT, DROP, STOLEN, etc).
So the only special case where it is relevant is the TEE target, which
returns XT_CONTINUE.
This patch changes ip(6)_do_table to always use the jump stack starting
from 0.
When we detect we're operating on an skb sent via TEE (percpu
nf_skb_duplicated is 1) we switch to an alternate stack to leave
the original one alone.
Since there is no TEE support for arptables, it doesn't need to
test if tee is active.
The jump stack overflow tests are no longer needed as well --
since ->stacksize is the largest call depth we cannot exceed it.
A much better alternative to the external jumpstack would be to just
declare a jumps[32] stack on the local stack frame, but that would mean
we'd have to reject iptables rulesets that used to work before.
Another alternative would be to start rejecting rulesets with a larger
call depth, e.g. 1000 -- in this case it would be feasible to allocate the
entire stack in the percpu area which would avoid one dereference.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2015-07-14 09:51:08 -06:00
|
|
|
/* No TEE support for arptables, so no need to switch to alternate
|
|
|
|
* stack. All targets that reenter must return absolute verdicts.
|
|
|
|
*/
|
[NETFILTER] x_tables: Abstraction layer for {ip,ip6,arp}_tables
This monster-patch tries to do the best job for unifying the data
structures and backend interfaces for the three evil clones ip_tables,
ip6_tables and arp_tables. In an ideal world we would never have
allowed this kind of copy+paste programming... but well, our world
isn't (yet?) ideal.
o introduce a new x_tables module
o {ip,arp,ip6}_tables depend on this x_tables module
o registration functions for tables, matches and targets are only
wrappers around x_tables provided functions
o all matches/targets that are used from ip_tables and ip6_tables
are now implemented as xt_FOOBAR.c files and provide module aliases
to ipt_FOOBAR and ip6t_FOOBAR
o header files for xt_matches are in include/linux/netfilter/,
include/linux/netfilter_{ipv4,ipv6} contains compatibility wrappers
around the xt_FOOBAR.h headers
Based on this patchset we're going to further unify the code,
gradually getting rid of all the layer 3 specific assumptions.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-01-12 14:30:04 -07:00
|
|
|
e = get_entry(table_base, private->hook_entry[hook]);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2016-11-03 03:56:21 -06:00
|
|
|
acpar.state = state;
|
2009-07-07 12:54:30 -06:00
|
|
|
acpar.hotdrop = false;
|
2008-10-08 03:35:19 -06:00
|
|
|
|
2007-10-15 01:53:15 -06:00
|
|
|
arp = arp_hdr(skb);
|
2005-04-16 16:20:36 -06:00
|
|
|
do {
|
2010-10-13 08:11:22 -06:00
|
|
|
const struct xt_entry_target *t;
|
2015-06-10 17:34:54 -06:00
|
|
|
struct xt_counters *counter;
|
2009-04-15 13:28:39 -06:00
|
|
|
|
|
|
|
if (!arp_packet_match(arp, skb->dev, indev, outdev, &e->arp)) {
|
|
|
|
e = arpt_next_entry(e);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-06-10 17:34:54 -06:00
|
|
|
counter = xt_get_this_cpu_counter(&e->counters);
|
|
|
|
ADD_COUNTER(*counter, arp_hdr_len(skb->dev), 1);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2009-06-25 23:51:59 -06:00
|
|
|
t = arpt_get_target_c(e);
|
2009-04-15 13:28:39 -06:00
|
|
|
|
|
|
|
/* Standard target? */
|
|
|
|
if (!t->u.kernel.target->target) {
|
|
|
|
int v;
|
|
|
|
|
2010-10-13 08:11:22 -06:00
|
|
|
v = ((struct xt_standard_target *)t)->verdict;
|
2009-04-15 13:28:39 -06:00
|
|
|
if (v < 0) {
|
|
|
|
/* Pop from stack? */
|
2010-10-13 08:28:00 -06:00
|
|
|
if (v != XT_RETURN) {
|
2012-04-14 23:58:06 -06:00
|
|
|
verdict = (unsigned int)(-v) - 1;
|
2005-04-16 16:20:36 -06:00
|
|
|
break;
|
2009-04-15 13:28:39 -06:00
|
|
|
}
|
2015-06-30 14:21:00 -06:00
|
|
|
if (stackidx == 0) {
|
|
|
|
e = get_entry(table_base,
|
|
|
|
private->underflow[hook]);
|
|
|
|
} else {
|
|
|
|
e = jumpstack[--stackidx];
|
|
|
|
e = arpt_next_entry(e);
|
|
|
|
}
|
2009-04-15 13:28:39 -06:00
|
|
|
continue;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
2009-04-15 13:28:39 -06:00
|
|
|
if (table_base + v
|
|
|
|
!= arpt_next_entry(e)) {
|
2018-02-07 05:46:25 -07:00
|
|
|
if (unlikely(stackidx >= private->stacksize)) {
|
|
|
|
verdict = NF_DROP;
|
|
|
|
break;
|
|
|
|
}
|
2015-06-30 14:21:00 -06:00
|
|
|
jumpstack[stackidx++] = e;
|
2009-04-15 13:28:39 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
e = get_entry(table_base, v);
|
2009-04-15 13:35:33 -06:00
|
|
|
continue;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
2009-04-15 13:35:33 -06:00
|
|
|
|
2009-07-05 10:26:37 -06:00
|
|
|
acpar.target = t->u.kernel.target;
|
|
|
|
acpar.targinfo = t->data;
|
|
|
|
verdict = t->u.kernel.target->target(skb, &acpar);
|
2009-04-15 13:35:33 -06:00
|
|
|
|
2017-07-26 20:22:04 -06:00
|
|
|
if (verdict == XT_CONTINUE) {
|
|
|
|
/* Target might have changed stuff. */
|
|
|
|
arp = arp_hdr(skb);
|
2009-04-15 13:35:33 -06:00
|
|
|
e = arpt_next_entry(e);
|
2017-07-26 20:22:04 -06:00
|
|
|
} else {
|
2009-04-15 13:35:33 -06:00
|
|
|
/* Verdict */
|
|
|
|
break;
|
2017-07-26 20:22:04 -06:00
|
|
|
}
|
2009-07-07 12:54:30 -06:00
|
|
|
} while (!acpar.hotdrop);
|
2011-04-04 09:04:03 -06:00
|
|
|
xt_write_recseq_end(addend);
|
|
|
|
local_bh_enable();
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2009-07-07 12:54:30 -06:00
|
|
|
if (acpar.hotdrop)
|
2005-04-16 16:20:36 -06:00
|
|
|
return NF_DROP;
|
|
|
|
else
|
|
|
|
return verdict;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* All zeroes == unconditional rule. */
|
2016-03-22 11:02:52 -06:00
|
|
|
static inline bool unconditional(const struct arpt_entry *e)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2009-07-09 15:00:19 -06:00
|
|
|
static const struct arpt_arp uncond;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2016-03-22 11:02:52 -06:00
|
|
|
return e->target_offset == sizeof(struct arpt_entry) &&
|
|
|
|
memcmp(&e->arp, &uncond, sizeof(uncond)) == 0;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Figures out from what hook each rule can be called: returns 0 if
|
|
|
|
* there are loops. Puts hook bitmask in comefrom.
|
|
|
|
*/
|
2015-08-26 15:20:51 -06:00
|
|
|
static int mark_source_chains(const struct xt_table_info *newinfo,
|
2016-07-14 09:51:26 -06:00
|
|
|
unsigned int valid_hooks, void *entry0,
|
|
|
|
unsigned int *offsets)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
unsigned int hook;
|
|
|
|
|
|
|
|
/* No recursion; use packet counter to save back ptrs (reset
|
|
|
|
* to 0 as we leave), and comefrom to save source hook bitmask.
|
|
|
|
*/
|
|
|
|
for (hook = 0; hook < NF_ARP_NUMHOOKS; hook++) {
|
|
|
|
unsigned int pos = newinfo->hook_entry[hook];
|
2017-03-28 13:05:16 -06:00
|
|
|
struct arpt_entry *e = entry0 + pos;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
if (!(valid_hooks & (1 << hook)))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Set initial back pointer. */
|
|
|
|
e->counters.pcnt = pos;
|
|
|
|
|
|
|
|
for (;;) {
|
2010-10-13 08:11:22 -06:00
|
|
|
const struct xt_standard_target *t
|
2009-06-25 23:51:59 -06:00
|
|
|
= (void *)arpt_get_target_c(e);
|
2006-12-12 01:29:52 -07:00
|
|
|
int visited = e->comefrom & (1 << hook);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2016-05-03 05:54:23 -06:00
|
|
|
if (e->comefrom & (1 << NF_ARP_NUMHOOKS))
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
2016-05-03 05:54:23 -06:00
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
e->comefrom
|
|
|
|
|= ((1 << hook) | (1 << NF_ARP_NUMHOOKS));
|
|
|
|
|
|
|
|
/* Unconditional return/END. */
|
2016-03-22 11:02:52 -06:00
|
|
|
if ((unconditional(e) &&
|
2009-11-23 15:17:06 -07:00
|
|
|
(strcmp(t->target.u.user.name,
|
2010-10-13 08:28:00 -06:00
|
|
|
XT_STANDARD_TARGET) == 0) &&
|
2016-03-22 11:02:52 -06:00
|
|
|
t->verdict < 0) || visited) {
|
2005-04-16 16:20:36 -06:00
|
|
|
unsigned int oldpos, size;
|
|
|
|
|
|
|
|
/* Return: backtrack through the last
|
|
|
|
* big jump.
|
|
|
|
*/
|
|
|
|
do {
|
|
|
|
e->comefrom ^= (1<<NF_ARP_NUMHOOKS);
|
|
|
|
oldpos = pos;
|
|
|
|
pos = e->counters.pcnt;
|
|
|
|
e->counters.pcnt = 0;
|
|
|
|
|
|
|
|
/* We're at the start. */
|
|
|
|
if (pos == oldpos)
|
|
|
|
goto next;
|
|
|
|
|
2017-03-28 13:05:16 -06:00
|
|
|
e = entry0 + pos;
|
2005-04-16 16:20:36 -06:00
|
|
|
} while (oldpos == pos + e->next_offset);
|
|
|
|
|
|
|
|
/* Move along one */
|
|
|
|
size = e->next_offset;
|
2017-03-28 13:05:16 -06:00
|
|
|
e = entry0 + pos + size;
|
2016-04-01 06:17:21 -06:00
|
|
|
if (pos + size >= newinfo->size)
|
|
|
|
return 0;
|
2005-04-16 16:20:36 -06:00
|
|
|
e->counters.pcnt = pos;
|
|
|
|
pos += size;
|
|
|
|
} else {
|
|
|
|
int newpos = t->verdict;
|
|
|
|
|
|
|
|
if (strcmp(t->target.u.user.name,
|
2010-10-13 08:28:00 -06:00
|
|
|
XT_STANDARD_TARGET) == 0 &&
|
2009-11-23 15:17:06 -07:00
|
|
|
newpos >= 0) {
|
2005-04-16 16:20:36 -06:00
|
|
|
/* This a jump; chase it. */
|
2016-07-14 09:51:26 -06:00
|
|
|
if (!xt_find_jump_offset(offsets, newpos,
|
|
|
|
newinfo->number))
|
|
|
|
return 0;
|
2005-04-16 16:20:36 -06:00
|
|
|
} else {
|
|
|
|
/* ... this is a fallthru */
|
|
|
|
newpos = pos + e->next_offset;
|
2016-04-01 06:17:21 -06:00
|
|
|
if (newpos >= newinfo->size)
|
|
|
|
return 0;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
2017-03-28 13:05:16 -06:00
|
|
|
e = entry0 + newpos;
|
2005-04-16 16:20:36 -06:00
|
|
|
e->counters.pcnt = pos;
|
|
|
|
pos = newpos;
|
|
|
|
}
|
|
|
|
}
|
2016-05-03 05:54:23 -06:00
|
|
|
next: ;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-12-26 17:33:10 -07:00
|
|
|
static int check_target(struct arpt_entry *e, struct net *net, const char *name)
|
2007-12-17 22:56:33 -07:00
|
|
|
{
|
2010-10-13 08:11:22 -06:00
|
|
|
struct xt_entry_target *t = arpt_get_target(e);
|
2008-10-08 03:35:19 -06:00
|
|
|
struct xt_tgchk_param par = {
|
2019-12-26 17:33:10 -07:00
|
|
|
.net = net,
|
2008-10-08 03:35:19 -06:00
|
|
|
.table = name,
|
|
|
|
.entryinfo = e,
|
|
|
|
.target = t->u.kernel.target,
|
|
|
|
.targinfo = t->data,
|
|
|
|
.hook_mask = e->comefrom,
|
2008-10-08 03:35:20 -06:00
|
|
|
.family = NFPROTO_ARP,
|
2008-10-08 03:35:19 -06:00
|
|
|
};
|
|
|
|
|
2016-05-03 05:54:23 -06:00
|
|
|
return xt_check_target(&par, t->u.target_size - sizeof(*t), 0, false);
|
2007-12-17 22:56:33 -07:00
|
|
|
}
|
|
|
|
|
2019-12-26 17:33:10 -07:00
|
|
|
static int
|
|
|
|
find_check_entry(struct arpt_entry *e, struct net *net, const char *name,
|
|
|
|
unsigned int size,
|
2016-11-22 06:44:19 -07:00
|
|
|
struct xt_percpu_counter_alloc_state *alloc_state)
|
2007-12-17 22:56:33 -07:00
|
|
|
{
|
2010-10-13 08:11:22 -06:00
|
|
|
struct xt_entry_target *t;
|
2008-04-14 03:15:43 -06:00
|
|
|
struct xt_target *target;
|
2007-12-17 22:56:33 -07:00
|
|
|
int ret;
|
|
|
|
|
2016-11-22 06:44:19 -07:00
|
|
|
if (!xt_percpu_counter_alloc(alloc_state, &e->counters))
|
2015-06-10 17:34:54 -06:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2007-12-17 22:56:33 -07:00
|
|
|
t = arpt_get_target(e);
|
2009-07-10 10:55:11 -06:00
|
|
|
target = xt_request_find_target(NFPROTO_ARP, t->u.user.name,
|
|
|
|
t->u.user.revision);
|
|
|
|
if (IS_ERR(target)) {
|
|
|
|
ret = PTR_ERR(target);
|
2005-04-16 16:20:36 -06:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
t->u.kernel.target = target;
|
|
|
|
|
2019-12-26 17:33:10 -07:00
|
|
|
ret = check_target(e, net, name);
|
2006-03-20 19:00:36 -07:00
|
|
|
if (ret)
|
|
|
|
goto err;
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
2006-03-20 19:00:36 -07:00
|
|
|
err:
|
|
|
|
module_put(t->u.kernel.target->me);
|
2005-04-16 16:20:36 -06:00
|
|
|
out:
|
2016-11-22 06:44:17 -07:00
|
|
|
xt_percpu_counter_free(&e->counters);
|
2015-06-10 17:34:54 -06:00
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-06-25 23:51:59 -06:00
|
|
|
static bool check_underflow(const struct arpt_entry *e)
|
2009-07-18 07:22:30 -06:00
|
|
|
{
|
2010-10-13 08:11:22 -06:00
|
|
|
const struct xt_entry_target *t;
|
2009-07-18 07:22:30 -06:00
|
|
|
unsigned int verdict;
|
|
|
|
|
2016-03-22 11:02:52 -06:00
|
|
|
if (!unconditional(e))
|
2009-07-18 07:22:30 -06:00
|
|
|
return false;
|
2009-06-25 23:51:59 -06:00
|
|
|
t = arpt_get_target_c(e);
|
2009-07-18 07:22:30 -06:00
|
|
|
if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
|
|
|
|
return false;
|
2010-10-13 08:11:22 -06:00
|
|
|
verdict = ((struct xt_standard_target *)t)->verdict;
|
2009-07-18 07:22:30 -06:00
|
|
|
verdict = -verdict - 1;
|
|
|
|
return verdict == NF_DROP || verdict == NF_ACCEPT;
|
|
|
|
}
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
static inline int check_entry_size_and_hooks(struct arpt_entry *e,
|
[NETFILTER] x_tables: Abstraction layer for {ip,ip6,arp}_tables
This monster-patch tries to do the best job for unifying the data
structures and backend interfaces for the three evil clones ip_tables,
ip6_tables and arp_tables. In an ideal world we would never have
allowed this kind of copy+paste programming... but well, our world
isn't (yet?) ideal.
o introduce a new x_tables module
o {ip,arp,ip6}_tables depend on this x_tables module
o registration functions for tables, matches and targets are only
wrappers around x_tables provided functions
o all matches/targets that are used from ip_tables and ip6_tables
are now implemented as xt_FOOBAR.c files and provide module aliases
to ipt_FOOBAR and ip6t_FOOBAR
o header files for xt_matches are in include/linux/netfilter/,
include/linux/netfilter_{ipv4,ipv6} contains compatibility wrappers
around the xt_FOOBAR.h headers
Based on this patchset we're going to further unify the code,
gradually getting rid of all the layer 3 specific assumptions.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-01-12 14:30:04 -07:00
|
|
|
struct xt_table_info *newinfo,
|
2009-06-25 23:51:59 -06:00
|
|
|
const unsigned char *base,
|
|
|
|
const unsigned char *limit,
|
2005-04-16 16:20:36 -06:00
|
|
|
const unsigned int *hook_entries,
|
|
|
|
const unsigned int *underflows,
|
2010-02-24 10:33:43 -07:00
|
|
|
unsigned int valid_hooks)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
unsigned int h;
|
2016-03-22 11:02:49 -06:00
|
|
|
int err;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2009-11-23 15:17:06 -07:00
|
|
|
if ((unsigned long)e % __alignof__(struct arpt_entry) != 0 ||
|
2016-03-22 11:02:50 -06:00
|
|
|
(unsigned char *)e + sizeof(struct arpt_entry) >= limit ||
|
2016-05-03 05:54:23 -06:00
|
|
|
(unsigned char *)e + e->next_offset > limit)
|
2005-04-16 16:20:36 -06:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (e->next_offset
|
2016-05-03 05:54:23 -06:00
|
|
|
< sizeof(struct arpt_entry) + sizeof(struct xt_entry_target))
|
2005-04-16 16:20:36 -06:00
|
|
|
return -EINVAL;
|
|
|
|
|
2016-04-01 06:17:24 -06:00
|
|
|
if (!arp_checkentry(&e->arp))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2016-04-01 06:17:28 -06:00
|
|
|
err = xt_check_entry_offsets(e, e->elems, e->target_offset,
|
|
|
|
e->next_offset);
|
2016-03-22 11:02:49 -06:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/* Check hooks & underflows */
|
|
|
|
for (h = 0; h < NF_ARP_NUMHOOKS; h++) {
|
2009-07-18 06:52:58 -06:00
|
|
|
if (!(valid_hooks & (1 << h)))
|
|
|
|
continue;
|
2005-04-16 16:20:36 -06:00
|
|
|
if ((unsigned char *)e - base == hook_entries[h])
|
|
|
|
newinfo->hook_entry[h] = hook_entries[h];
|
2009-07-09 14:54:53 -06:00
|
|
|
if ((unsigned char *)e - base == underflows[h]) {
|
2016-05-03 05:54:23 -06:00
|
|
|
if (!check_underflow(e))
|
2009-07-09 14:54:53 -06:00
|
|
|
return -EINVAL;
|
2016-05-03 05:54:23 -06:00
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
newinfo->underflow[h] = underflows[h];
|
2009-07-09 14:54:53 -06:00
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Clear counters and comefrom */
|
[NETFILTER] x_tables: Abstraction layer for {ip,ip6,arp}_tables
This monster-patch tries to do the best job for unifying the data
structures and backend interfaces for the three evil clones ip_tables,
ip6_tables and arp_tables. In an ideal world we would never have
allowed this kind of copy+paste programming... but well, our world
isn't (yet?) ideal.
o introduce a new x_tables module
o {ip,arp,ip6}_tables depend on this x_tables module
o registration functions for tables, matches and targets are only
wrappers around x_tables provided functions
o all matches/targets that are used from ip_tables and ip6_tables
are now implemented as xt_FOOBAR.c files and provide module aliases
to ipt_FOOBAR and ip6t_FOOBAR
o header files for xt_matches are in include/linux/netfilter/,
include/linux/netfilter_{ipv4,ipv6} contains compatibility wrappers
around the xt_FOOBAR.h headers
Based on this patchset we're going to further unify the code,
gradually getting rid of all the layer 3 specific assumptions.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-01-12 14:30:04 -07:00
|
|
|
e->counters = ((struct xt_counters) { 0, 0 });
|
2005-04-16 16:20:36 -06:00
|
|
|
e->comefrom = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-11 15:19:53 -07:00
|
|
|
static void cleanup_entry(struct arpt_entry *e, struct net *net)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2008-10-08 03:35:19 -06:00
|
|
|
struct xt_tgdtor_param par;
|
2010-10-13 08:11:22 -06:00
|
|
|
struct xt_entry_target *t;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
t = arpt_get_target(e);
|
2020-01-11 15:19:53 -07:00
|
|
|
par.net = net;
|
2008-10-08 03:35:19 -06:00
|
|
|
par.target = t->u.kernel.target;
|
|
|
|
par.targinfo = t->data;
|
2008-10-08 03:35:20 -06:00
|
|
|
par.family = NFPROTO_ARP;
|
2008-10-08 03:35:19 -06:00
|
|
|
if (par.target->destroy != NULL)
|
|
|
|
par.target->destroy(&par);
|
|
|
|
module_put(par.target->me);
|
2016-11-22 06:44:17 -07:00
|
|
|
xt_percpu_counter_free(&e->counters);
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Checks and translates the user-supplied table segment (held in
|
|
|
|
* newinfo).
|
|
|
|
*/
|
2019-12-26 17:33:10 -07:00
|
|
|
static int translate_table(struct net *net,
|
|
|
|
struct xt_table_info *newinfo,
|
|
|
|
void *entry0,
|
2015-10-14 16:17:06 -06:00
|
|
|
const struct arpt_replace *repl)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2016-11-22 06:44:19 -07:00
|
|
|
struct xt_percpu_counter_alloc_state alloc_state = { 0 };
|
2010-02-24 10:32:59 -07:00
|
|
|
struct arpt_entry *iter;
|
2016-07-14 09:51:26 -06:00
|
|
|
unsigned int *offsets;
|
2005-04-16 16:20:36 -06:00
|
|
|
unsigned int i;
|
2010-02-24 10:32:59 -07:00
|
|
|
int ret = 0;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2010-02-24 10:36:04 -07:00
|
|
|
newinfo->size = repl->size;
|
|
|
|
newinfo->number = repl->num_entries;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* Init all hooks to impossible value. */
|
|
|
|
for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
|
|
|
|
newinfo->hook_entry[i] = 0xFFFFFFFF;
|
|
|
|
newinfo->underflow[i] = 0xFFFFFFFF;
|
|
|
|
}
|
|
|
|
|
2016-07-14 09:51:26 -06:00
|
|
|
offsets = xt_alloc_entry_offsets(newinfo->number);
|
|
|
|
if (!offsets)
|
|
|
|
return -ENOMEM;
|
2005-04-16 16:20:36 -06:00
|
|
|
i = 0;
|
|
|
|
|
|
|
|
/* Walk through entries, checking offsets. */
|
2010-02-24 10:32:59 -07:00
|
|
|
xt_entry_foreach(iter, entry0, newinfo->size) {
|
|
|
|
ret = check_entry_size_and_hooks(iter, newinfo, entry0,
|
2010-02-26 09:53:31 -07:00
|
|
|
entry0 + repl->size,
|
|
|
|
repl->hook_entry,
|
|
|
|
repl->underflow,
|
|
|
|
repl->valid_hooks);
|
2010-02-24 10:32:59 -07:00
|
|
|
if (ret != 0)
|
2016-07-14 09:51:26 -06:00
|
|
|
goto out_free;
|
|
|
|
if (i < repl->num_entries)
|
|
|
|
offsets[i] = (void *)iter - entry0;
|
2010-02-24 10:33:43 -07:00
|
|
|
++i;
|
2015-08-26 15:20:51 -06:00
|
|
|
if (strcmp(arpt_get_target(iter)->u.user.name,
|
|
|
|
XT_ERROR_TARGET) == 0)
|
|
|
|
++newinfo->stacksize;
|
2010-02-24 10:32:59 -07:00
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2016-07-14 09:51:26 -06:00
|
|
|
ret = -EINVAL;
|
2016-05-03 05:54:23 -06:00
|
|
|
if (i != repl->num_entries)
|
2016-07-14 09:51:26 -06:00
|
|
|
goto out_free;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2018-02-27 11:42:29 -07:00
|
|
|
ret = xt_check_table_hooks(newinfo, repl->valid_hooks);
|
|
|
|
if (ret)
|
|
|
|
goto out_free;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2016-07-14 09:51:26 -06:00
|
|
|
if (!mark_source_chains(newinfo, repl->valid_hooks, entry0, offsets)) {
|
|
|
|
ret = -ELOOP;
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
kvfree(offsets);
|
2006-12-05 14:43:50 -07:00
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/* Finally, each sanity check must pass */
|
|
|
|
i = 0;
|
2010-02-24 10:32:59 -07:00
|
|
|
xt_entry_foreach(iter, entry0, newinfo->size) {
|
2019-12-26 17:33:10 -07:00
|
|
|
ret = find_check_entry(iter, net, repl->name, repl->size,
|
2016-11-22 06:44:19 -07:00
|
|
|
&alloc_state);
|
2010-02-24 10:32:59 -07:00
|
|
|
if (ret != 0)
|
|
|
|
break;
|
2010-02-24 10:33:43 -07:00
|
|
|
++i;
|
2010-02-24 10:32:59 -07:00
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2006-12-05 14:43:50 -07:00
|
|
|
if (ret != 0) {
|
2010-02-24 10:33:43 -07:00
|
|
|
xt_entry_foreach(iter, entry0, newinfo->size) {
|
|
|
|
if (i-- == 0)
|
2010-02-24 10:32:59 -07:00
|
|
|
break;
|
2020-01-11 15:19:53 -07:00
|
|
|
cleanup_entry(iter, net);
|
2010-02-24 10:33:43 -07:00
|
|
|
}
|
2006-12-05 14:43:50 -07:00
|
|
|
return ret;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
2016-07-14 09:51:26 -06:00
|
|
|
return ret;
|
|
|
|
out_free:
|
|
|
|
kvfree(offsets);
|
2005-04-16 16:20:36 -06:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
[NETFILTER] x_tables: Abstraction layer for {ip,ip6,arp}_tables
This monster-patch tries to do the best job for unifying the data
structures and backend interfaces for the three evil clones ip_tables,
ip6_tables and arp_tables. In an ideal world we would never have
allowed this kind of copy+paste programming... but well, our world
isn't (yet?) ideal.
o introduce a new x_tables module
o {ip,arp,ip6}_tables depend on this x_tables module
o registration functions for tables, matches and targets are only
wrappers around x_tables provided functions
o all matches/targets that are used from ip_tables and ip6_tables
are now implemented as xt_FOOBAR.c files and provide module aliases
to ipt_FOOBAR and ip6t_FOOBAR
o header files for xt_matches are in include/linux/netfilter/,
include/linux/netfilter_{ipv4,ipv6} contains compatibility wrappers
around the xt_FOOBAR.h headers
Based on this patchset we're going to further unify the code,
gradually getting rid of all the layer 3 specific assumptions.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-01-12 14:30:04 -07:00
|
|
|
static void get_counters(const struct xt_table_info *t,
|
|
|
|
struct xt_counters counters[])
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2010-02-24 10:32:59 -07:00
|
|
|
struct arpt_entry *iter;
|
2005-04-16 16:20:36 -06:00
|
|
|
unsigned int cpu;
|
|
|
|
unsigned int i;
|
|
|
|
|
2006-04-10 23:52:50 -06:00
|
|
|
for_each_possible_cpu(cpu) {
|
2011-04-04 09:04:03 -06:00
|
|
|
seqcount_t *s = &per_cpu(xt_recseq, cpu);
|
2011-01-10 12:11:38 -07:00
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
i = 0;
|
2015-06-10 17:34:55 -06:00
|
|
|
xt_entry_foreach(iter, t->entries, t->size) {
|
2015-06-10 17:34:54 -06:00
|
|
|
struct xt_counters *tmp;
|
2011-01-10 12:11:38 -07:00
|
|
|
u64 bcnt, pcnt;
|
|
|
|
unsigned int start;
|
|
|
|
|
2015-06-10 17:34:54 -06:00
|
|
|
tmp = xt_get_per_cpu_counter(&iter->counters, cpu);
|
2011-01-10 12:11:38 -07:00
|
|
|
do {
|
2011-04-04 09:04:03 -06:00
|
|
|
start = read_seqcount_begin(s);
|
2015-06-10 17:34:54 -06:00
|
|
|
bcnt = tmp->bcnt;
|
|
|
|
pcnt = tmp->pcnt;
|
2011-04-04 09:04:03 -06:00
|
|
|
} while (read_seqcount_retry(s, start));
|
2011-01-10 12:11:38 -07:00
|
|
|
|
|
|
|
ADD_COUNTER(counters[i], bcnt, pcnt);
|
2010-02-24 10:33:43 -07:00
|
|
|
++i;
|
2017-09-01 14:41:03 -06:00
|
|
|
cond_resched();
|
2010-02-24 10:33:43 -07:00
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
2009-02-20 02:35:32 -07:00
|
|
|
}
|
|
|
|
|
2017-10-11 17:13:51 -06:00
|
|
|
static void get_old_counters(const struct xt_table_info *t,
|
|
|
|
struct xt_counters counters[])
|
|
|
|
{
|
|
|
|
struct arpt_entry *iter;
|
|
|
|
unsigned int cpu, i;
|
|
|
|
|
|
|
|
for_each_possible_cpu(cpu) {
|
|
|
|
i = 0;
|
|
|
|
xt_entry_foreach(iter, t->entries, t->size) {
|
|
|
|
struct xt_counters *tmp;
|
|
|
|
|
|
|
|
tmp = xt_get_per_cpu_counter(&iter->counters, cpu);
|
|
|
|
ADD_COUNTER(counters[i], tmp->bcnt, tmp->pcnt);
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
cond_resched();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-25 23:51:59 -06:00
|
|
|
static struct xt_counters *alloc_counters(const struct xt_table *table)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2007-12-17 22:56:48 -07:00
|
|
|
unsigned int countersize;
|
[NETFILTER] x_tables: Abstraction layer for {ip,ip6,arp}_tables
This monster-patch tries to do the best job for unifying the data
structures and backend interfaces for the three evil clones ip_tables,
ip6_tables and arp_tables. In an ideal world we would never have
allowed this kind of copy+paste programming... but well, our world
isn't (yet?) ideal.
o introduce a new x_tables module
o {ip,arp,ip6}_tables depend on this x_tables module
o registration functions for tables, matches and targets are only
wrappers around x_tables provided functions
o all matches/targets that are used from ip_tables and ip6_tables
are now implemented as xt_FOOBAR.c files and provide module aliases
to ipt_FOOBAR and ip6t_FOOBAR
o header files for xt_matches are in include/linux/netfilter/,
include/linux/netfilter_{ipv4,ipv6} contains compatibility wrappers
around the xt_FOOBAR.h headers
Based on this patchset we're going to further unify the code,
gradually getting rid of all the layer 3 specific assumptions.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-01-12 14:30:04 -07:00
|
|
|
struct xt_counters *counters;
|
2009-06-25 23:51:59 -06:00
|
|
|
const struct xt_table_info *private = table->private;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* We need atomic snapshot of counters: rest doesn't change
|
|
|
|
* (other than comefrom, which userspace doesn't care
|
|
|
|
* about).
|
|
|
|
*/
|
[NETFILTER] x_tables: Abstraction layer for {ip,ip6,arp}_tables
This monster-patch tries to do the best job for unifying the data
structures and backend interfaces for the three evil clones ip_tables,
ip6_tables and arp_tables. In an ideal world we would never have
allowed this kind of copy+paste programming... but well, our world
isn't (yet?) ideal.
o introduce a new x_tables module
o {ip,arp,ip6}_tables depend on this x_tables module
o registration functions for tables, matches and targets are only
wrappers around x_tables provided functions
o all matches/targets that are used from ip_tables and ip6_tables
are now implemented as xt_FOOBAR.c files and provide module aliases
to ipt_FOOBAR and ip6t_FOOBAR
o header files for xt_matches are in include/linux/netfilter/,
include/linux/netfilter_{ipv4,ipv6} contains compatibility wrappers
around the xt_FOOBAR.h headers
Based on this patchset we're going to further unify the code,
gradually getting rid of all the layer 3 specific assumptions.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-01-12 14:30:04 -07:00
|
|
|
countersize = sizeof(struct xt_counters) * private->number;
|
2011-01-10 12:11:38 -07:00
|
|
|
counters = vzalloc(countersize);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
if (counters == NULL)
|
2009-04-28 23:36:33 -06:00
|
|
|
return ERR_PTR(-ENOMEM);
|
2009-02-20 02:35:32 -07:00
|
|
|
|
2009-04-28 23:36:33 -06:00
|
|
|
get_counters(private, counters);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-12-17 22:56:48 -07:00
|
|
|
return counters;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int copy_entries_to_user(unsigned int total_size,
|
2009-06-25 23:51:59 -06:00
|
|
|
const struct xt_table *table,
|
2007-12-17 22:56:48 -07:00
|
|
|
void __user *userptr)
|
|
|
|
{
|
|
|
|
unsigned int off, num;
|
2009-06-25 23:51:59 -06:00
|
|
|
const struct arpt_entry *e;
|
2007-12-17 22:56:48 -07:00
|
|
|
struct xt_counters *counters;
|
2008-04-14 03:15:43 -06:00
|
|
|
struct xt_table_info *private = table->private;
|
2007-12-17 22:56:48 -07:00
|
|
|
int ret = 0;
|
|
|
|
void *loc_cpu_entry;
|
|
|
|
|
|
|
|
counters = alloc_counters(table);
|
|
|
|
if (IS_ERR(counters))
|
|
|
|
return PTR_ERR(counters);
|
|
|
|
|
2015-06-10 17:34:55 -06:00
|
|
|
loc_cpu_entry = private->entries;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* FIXME: use iterator macros --RR */
|
|
|
|
/* ... then go back and fix counters and names */
|
|
|
|
for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
|
2010-10-13 08:11:22 -06:00
|
|
|
const struct xt_entry_target *t;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2017-03-28 13:05:16 -06:00
|
|
|
e = loc_cpu_entry + off;
|
2017-01-02 15:19:43 -07:00
|
|
|
if (copy_to_user(userptr + off, e, sizeof(*e))) {
|
|
|
|
ret = -EFAULT;
|
|
|
|
goto free_counters;
|
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
if (copy_to_user(userptr + off
|
|
|
|
+ offsetof(struct arpt_entry, counters),
|
|
|
|
&counters[num],
|
|
|
|
sizeof(counters[num])) != 0) {
|
|
|
|
ret = -EFAULT;
|
|
|
|
goto free_counters;
|
|
|
|
}
|
|
|
|
|
2009-06-25 23:51:59 -06:00
|
|
|
t = arpt_get_target_c(e);
|
2017-01-02 15:19:43 -07:00
|
|
|
if (xt_target_to_user(t, userptr + off + e->target_offset)) {
|
2005-04-16 16:20:36 -06:00
|
|
|
ret = -EFAULT;
|
|
|
|
goto free_counters;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free_counters:
|
|
|
|
vfree(counters);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2007-12-17 23:26:54 -07:00
|
|
|
#ifdef CONFIG_COMPAT
|
2009-06-26 00:23:19 -06:00
|
|
|
static void compat_standard_from_user(void *dst, const void *src)
|
2007-12-17 23:26:54 -07:00
|
|
|
{
|
|
|
|
int v = *(compat_int_t *)src;
|
|
|
|
|
|
|
|
if (v > 0)
|
2008-10-08 03:35:01 -06:00
|
|
|
v += xt_compat_calc_jump(NFPROTO_ARP, v);
|
2007-12-17 23:26:54 -07:00
|
|
|
memcpy(dst, &v, sizeof(v));
|
|
|
|
}
|
|
|
|
|
2009-06-26 00:23:19 -06:00
|
|
|
static int compat_standard_to_user(void __user *dst, const void *src)
|
2007-12-17 23:26:54 -07:00
|
|
|
{
|
|
|
|
compat_int_t cv = *(int *)src;
|
|
|
|
|
|
|
|
if (cv > 0)
|
2008-10-08 03:35:01 -06:00
|
|
|
cv -= xt_compat_calc_jump(NFPROTO_ARP, cv);
|
2007-12-17 23:26:54 -07:00
|
|
|
return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
|
|
|
|
}
|
|
|
|
|
2009-06-25 23:51:59 -06:00
|
|
|
static int compat_calc_entry(const struct arpt_entry *e,
|
2007-12-17 23:26:54 -07:00
|
|
|
const struct xt_table_info *info,
|
2009-06-25 23:51:59 -06:00
|
|
|
const void *base, struct xt_table_info *newinfo)
|
2007-12-17 23:26:54 -07:00
|
|
|
{
|
2010-10-13 08:11:22 -06:00
|
|
|
const struct xt_entry_target *t;
|
2007-12-17 23:26:54 -07:00
|
|
|
unsigned int entry_offset;
|
|
|
|
int off, i, ret;
|
|
|
|
|
|
|
|
off = sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry);
|
|
|
|
entry_offset = (void *)e - base;
|
|
|
|
|
2009-06-25 23:51:59 -06:00
|
|
|
t = arpt_get_target_c(e);
|
2007-12-17 23:26:54 -07:00
|
|
|
off += xt_compat_target_offset(t->u.kernel.target);
|
|
|
|
newinfo->size -= off;
|
2008-10-08 03:35:01 -06:00
|
|
|
ret = xt_compat_add_offset(NFPROTO_ARP, entry_offset, off);
|
2007-12-17 23:26:54 -07:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
|
|
|
|
if (info->hook_entry[i] &&
|
|
|
|
(e < (struct arpt_entry *)(base + info->hook_entry[i])))
|
|
|
|
newinfo->hook_entry[i] -= off;
|
|
|
|
if (info->underflow[i] &&
|
|
|
|
(e < (struct arpt_entry *)(base + info->underflow[i])))
|
|
|
|
newinfo->underflow[i] -= off;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int compat_table_info(const struct xt_table_info *info,
|
|
|
|
struct xt_table_info *newinfo)
|
|
|
|
{
|
2010-02-24 10:32:59 -07:00
|
|
|
struct arpt_entry *iter;
|
2015-06-15 10:57:30 -06:00
|
|
|
const void *loc_cpu_entry;
|
2010-02-24 10:33:43 -07:00
|
|
|
int ret;
|
2007-12-17 23:26:54 -07:00
|
|
|
|
|
|
|
if (!newinfo || !info)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2015-06-10 17:34:55 -06:00
|
|
|
/* we dont care about newinfo->entries */
|
2007-12-17 23:26:54 -07:00
|
|
|
memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
|
|
|
|
newinfo->initial_entries = 0;
|
2015-06-10 17:34:55 -06:00
|
|
|
loc_cpu_entry = info->entries;
|
2018-02-27 11:42:34 -07:00
|
|
|
ret = xt_compat_init_offsets(NFPROTO_ARP, info->number);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2010-02-24 10:32:59 -07:00
|
|
|
xt_entry_foreach(iter, loc_cpu_entry, info->size) {
|
|
|
|
ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo);
|
|
|
|
if (ret != 0)
|
2010-02-24 10:33:43 -07:00
|
|
|
return ret;
|
2010-02-24 10:32:59 -07:00
|
|
|
}
|
2010-02-24 10:33:43 -07:00
|
|
|
return 0;
|
2007-12-17 23:26:54 -07:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-06-25 23:51:59 -06:00
|
|
|
static int get_info(struct net *net, void __user *user,
|
2015-10-14 16:17:06 -06:00
|
|
|
const int *len, int compat)
|
2007-12-17 23:26:24 -07:00
|
|
|
{
|
2010-10-13 07:56:56 -06:00
|
|
|
char name[XT_TABLE_MAXNAMELEN];
|
2008-04-14 03:15:43 -06:00
|
|
|
struct xt_table *t;
|
2007-12-17 23:26:24 -07:00
|
|
|
int ret;
|
|
|
|
|
2016-05-03 05:54:23 -06:00
|
|
|
if (*len != sizeof(struct arpt_getinfo))
|
2007-12-17 23:26:24 -07:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (copy_from_user(name, user, sizeof(name)) != 0)
|
|
|
|
return -EFAULT;
|
|
|
|
|
2010-10-13 07:56:56 -06:00
|
|
|
name[XT_TABLE_MAXNAMELEN-1] = '\0';
|
2007-12-17 23:26:54 -07:00
|
|
|
#ifdef CONFIG_COMPAT
|
|
|
|
if (compat)
|
2008-10-08 03:35:01 -06:00
|
|
|
xt_compat_lock(NFPROTO_ARP);
|
2007-12-17 23:26:54 -07:00
|
|
|
#endif
|
2017-12-08 09:01:53 -07:00
|
|
|
t = xt_request_find_table_lock(net, NFPROTO_ARP, name);
|
|
|
|
if (!IS_ERR(t)) {
|
2007-12-17 23:26:24 -07:00
|
|
|
struct arpt_getinfo info;
|
2008-04-14 03:15:35 -06:00
|
|
|
const struct xt_table_info *private = t->private;
|
2007-12-17 23:26:54 -07:00
|
|
|
#ifdef CONFIG_COMPAT
|
2010-02-08 12:17:43 -07:00
|
|
|
struct xt_table_info tmp;
|
|
|
|
|
2007-12-17 23:26:54 -07:00
|
|
|
if (compat) {
|
|
|
|
ret = compat_table_info(private, &tmp);
|
2008-10-08 03:35:01 -06:00
|
|
|
xt_compat_flush_offsets(NFPROTO_ARP);
|
2007-12-17 23:26:54 -07:00
|
|
|
private = &tmp;
|
|
|
|
}
|
|
|
|
#endif
|
2010-11-03 01:44:12 -06:00
|
|
|
memset(&info, 0, sizeof(info));
|
2007-12-17 23:26:24 -07:00
|
|
|
info.valid_hooks = t->valid_hooks;
|
|
|
|
memcpy(info.hook_entry, private->hook_entry,
|
|
|
|
sizeof(info.hook_entry));
|
|
|
|
memcpy(info.underflow, private->underflow,
|
|
|
|
sizeof(info.underflow));
|
|
|
|
info.num_entries = private->number;
|
|
|
|
info.size = private->size;
|
|
|
|
strcpy(info.name, name);
|
|
|
|
|
|
|
|
if (copy_to_user(user, &info, *len) != 0)
|
|
|
|
ret = -EFAULT;
|
|
|
|
else
|
|
|
|
ret = 0;
|
|
|
|
xt_table_unlock(t);
|
|
|
|
module_put(t->me);
|
|
|
|
} else
|
2017-12-08 09:01:53 -07:00
|
|
|
ret = PTR_ERR(t);
|
2007-12-17 23:26:54 -07:00
|
|
|
#ifdef CONFIG_COMPAT
|
|
|
|
if (compat)
|
2008-10-08 03:35:01 -06:00
|
|
|
xt_compat_unlock(NFPROTO_ARP);
|
2007-12-17 23:26:54 -07:00
|
|
|
#endif
|
2007-12-17 23:26:24 -07:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2008-01-31 05:04:32 -07:00
|
|
|
static int get_entries(struct net *net, struct arpt_get_entries __user *uptr,
|
2009-06-25 23:51:59 -06:00
|
|
|
const int *len)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
int ret;
|
2007-12-17 23:26:38 -07:00
|
|
|
struct arpt_get_entries get;
|
2008-04-14 03:15:43 -06:00
|
|
|
struct xt_table *t;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2016-05-03 05:54:23 -06:00
|
|
|
if (*len < sizeof(get))
|
2007-12-17 23:26:38 -07:00
|
|
|
return -EINVAL;
|
|
|
|
if (copy_from_user(&get, uptr, sizeof(get)) != 0)
|
|
|
|
return -EFAULT;
|
2016-05-03 05:54:23 -06:00
|
|
|
if (*len != sizeof(struct arpt_get_entries) + get.size)
|
2007-12-17 23:26:38 -07:00
|
|
|
return -EINVAL;
|
2016-05-03 05:54:23 -06:00
|
|
|
|
2016-03-24 14:29:53 -06:00
|
|
|
get.name[sizeof(get.name) - 1] = '\0';
|
2007-12-17 23:26:38 -07:00
|
|
|
|
2008-10-08 03:35:01 -06:00
|
|
|
t = xt_find_table_lock(net, NFPROTO_ARP, get.name);
|
2017-12-08 09:01:53 -07:00
|
|
|
if (!IS_ERR(t)) {
|
2008-04-14 03:15:35 -06:00
|
|
|
const struct xt_table_info *private = t->private;
|
|
|
|
|
2007-12-17 23:26:38 -07:00
|
|
|
if (get.size == private->size)
|
[NETFILTER] x_tables: Abstraction layer for {ip,ip6,arp}_tables
This monster-patch tries to do the best job for unifying the data
structures and backend interfaces for the three evil clones ip_tables,
ip6_tables and arp_tables. In an ideal world we would never have
allowed this kind of copy+paste programming... but well, our world
isn't (yet?) ideal.
o introduce a new x_tables module
o {ip,arp,ip6}_tables depend on this x_tables module
o registration functions for tables, matches and targets are only
wrappers around x_tables provided functions
o all matches/targets that are used from ip_tables and ip6_tables
are now implemented as xt_FOOBAR.c files and provide module aliases
to ipt_FOOBAR and ip6t_FOOBAR
o header files for xt_matches are in include/linux/netfilter/,
include/linux/netfilter_{ipv4,ipv6} contains compatibility wrappers
around the xt_FOOBAR.h headers
Based on this patchset we're going to further unify the code,
gradually getting rid of all the layer 3 specific assumptions.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-01-12 14:30:04 -07:00
|
|
|
ret = copy_entries_to_user(private->size,
|
2005-04-16 16:20:36 -06:00
|
|
|
t, uptr->entrytable);
|
2016-05-03 05:54:23 -06:00
|
|
|
else
|
2008-04-14 03:15:45 -06:00
|
|
|
ret = -EAGAIN;
|
2016-05-03 05:54:23 -06:00
|
|
|
|
2005-10-26 01:34:24 -06:00
|
|
|
module_put(t->me);
|
[NETFILTER] x_tables: Abstraction layer for {ip,ip6,arp}_tables
This monster-patch tries to do the best job for unifying the data
structures and backend interfaces for the three evil clones ip_tables,
ip6_tables and arp_tables. In an ideal world we would never have
allowed this kind of copy+paste programming... but well, our world
isn't (yet?) ideal.
o introduce a new x_tables module
o {ip,arp,ip6}_tables depend on this x_tables module
o registration functions for tables, matches and targets are only
wrappers around x_tables provided functions
o all matches/targets that are used from ip_tables and ip6_tables
are now implemented as xt_FOOBAR.c files and provide module aliases
to ipt_FOOBAR and ip6t_FOOBAR
o header files for xt_matches are in include/linux/netfilter/,
include/linux/netfilter_{ipv4,ipv6} contains compatibility wrappers
around the xt_FOOBAR.h headers
Based on this patchset we're going to further unify the code,
gradually getting rid of all the layer 3 specific assumptions.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-01-12 14:30:04 -07:00
|
|
|
xt_table_unlock(t);
|
2005-04-16 16:20:36 -06:00
|
|
|
} else
|
2017-12-08 09:01:53 -07:00
|
|
|
ret = PTR_ERR(t);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2008-01-31 05:04:32 -07:00
|
|
|
static int __do_replace(struct net *net, const char *name,
|
|
|
|
unsigned int valid_hooks,
|
2007-12-17 23:26:54 -07:00
|
|
|
struct xt_table_info *newinfo,
|
|
|
|
unsigned int num_counters,
|
|
|
|
void __user *counters_ptr)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
int ret;
|
2008-04-14 03:15:43 -06:00
|
|
|
struct xt_table *t;
|
2007-12-17 23:26:54 -07:00
|
|
|
struct xt_table_info *oldinfo;
|
[NETFILTER] x_tables: Abstraction layer for {ip,ip6,arp}_tables
This monster-patch tries to do the best job for unifying the data
structures and backend interfaces for the three evil clones ip_tables,
ip6_tables and arp_tables. In an ideal world we would never have
allowed this kind of copy+paste programming... but well, our world
isn't (yet?) ideal.
o introduce a new x_tables module
o {ip,arp,ip6}_tables depend on this x_tables module
o registration functions for tables, matches and targets are only
wrappers around x_tables provided functions
o all matches/targets that are used from ip_tables and ip6_tables
are now implemented as xt_FOOBAR.c files and provide module aliases
to ipt_FOOBAR and ip6t_FOOBAR
o header files for xt_matches are in include/linux/netfilter/,
include/linux/netfilter_{ipv4,ipv6} contains compatibility wrappers
around the xt_FOOBAR.h headers
Based on this patchset we're going to further unify the code,
gradually getting rid of all the layer 3 specific assumptions.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-01-12 14:30:04 -07:00
|
|
|
struct xt_counters *counters;
|
2007-12-17 23:26:54 -07:00
|
|
|
void *loc_cpu_old_entry;
|
2010-02-24 10:32:59 -07:00
|
|
|
struct arpt_entry *iter;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-12-17 23:26:54 -07:00
|
|
|
ret = 0;
|
2018-02-27 11:42:33 -07:00
|
|
|
counters = xt_counters_alloc(num_counters);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (!counters) {
|
|
|
|
ret = -ENOMEM;
|
2007-12-17 23:26:54 -07:00
|
|
|
goto out;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
2017-12-08 09:01:53 -07:00
|
|
|
t = xt_request_find_table_lock(net, NFPROTO_ARP, name);
|
|
|
|
if (IS_ERR(t)) {
|
|
|
|
ret = PTR_ERR(t);
|
2005-04-16 16:20:36 -06:00
|
|
|
goto free_newinfo_counters_untrans;
|
2005-10-26 01:34:24 -06:00
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* You lied! */
|
2007-12-17 23:26:54 -07:00
|
|
|
if (valid_hooks != t->valid_hooks) {
|
2005-04-16 16:20:36 -06:00
|
|
|
ret = -EINVAL;
|
2005-10-26 01:34:24 -06:00
|
|
|
goto put_module;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
2007-12-17 23:26:54 -07:00
|
|
|
oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (!oldinfo)
|
|
|
|
goto put_module;
|
|
|
|
|
|
|
|
/* Update module usage count based on number of rules */
|
2007-02-09 07:24:47 -07:00
|
|
|
if ((oldinfo->number > oldinfo->initial_entries) ||
|
|
|
|
(newinfo->number <= oldinfo->initial_entries))
|
2005-04-16 16:20:36 -06:00
|
|
|
module_put(t->me);
|
|
|
|
if ((oldinfo->number > oldinfo->initial_entries) &&
|
|
|
|
(newinfo->number <= oldinfo->initial_entries))
|
|
|
|
module_put(t->me);
|
|
|
|
|
2018-02-16 03:04:56 -07:00
|
|
|
xt_table_unlock(t);
|
|
|
|
|
2017-10-11 17:13:51 -06:00
|
|
|
get_old_counters(oldinfo, counters);
|
2009-04-28 23:36:33 -06:00
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/* Decrease module usage counts and free resource */
|
2015-06-10 17:34:55 -06:00
|
|
|
loc_cpu_old_entry = oldinfo->entries;
|
2010-02-24 10:32:59 -07:00
|
|
|
xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size)
|
2020-01-11 15:19:53 -07:00
|
|
|
cleanup_entry(iter, net);
|
2005-12-14 00:13:48 -07:00
|
|
|
|
[NETFILTER] x_tables: Abstraction layer for {ip,ip6,arp}_tables
This monster-patch tries to do the best job for unifying the data
structures and backend interfaces for the three evil clones ip_tables,
ip6_tables and arp_tables. In an ideal world we would never have
allowed this kind of copy+paste programming... but well, our world
isn't (yet?) ideal.
o introduce a new x_tables module
o {ip,arp,ip6}_tables depend on this x_tables module
o registration functions for tables, matches and targets are only
wrappers around x_tables provided functions
o all matches/targets that are used from ip_tables and ip6_tables
are now implemented as xt_FOOBAR.c files and provide module aliases
to ipt_FOOBAR and ip6t_FOOBAR
o header files for xt_matches are in include/linux/netfilter/,
include/linux/netfilter_{ipv4,ipv6} contains compatibility wrappers
around the xt_FOOBAR.h headers
Based on this patchset we're going to further unify the code,
gradually getting rid of all the layer 3 specific assumptions.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-01-12 14:30:04 -07:00
|
|
|
xt_free_table_info(oldinfo);
|
2007-12-17 23:26:54 -07:00
|
|
|
if (copy_to_user(counters_ptr, counters,
|
2014-04-04 09:57:45 -06:00
|
|
|
sizeof(struct xt_counters) * num_counters) != 0) {
|
|
|
|
/* Silent error, can't fail, new table is already in place */
|
|
|
|
net_warn_ratelimited("arptables: counters copy to user failed while replacing table\n");
|
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
vfree(counters);
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
put_module:
|
|
|
|
module_put(t->me);
|
[NETFILTER] x_tables: Abstraction layer for {ip,ip6,arp}_tables
This monster-patch tries to do the best job for unifying the data
structures and backend interfaces for the three evil clones ip_tables,
ip6_tables and arp_tables. In an ideal world we would never have
allowed this kind of copy+paste programming... but well, our world
isn't (yet?) ideal.
o introduce a new x_tables module
o {ip,arp,ip6}_tables depend on this x_tables module
o registration functions for tables, matches and targets are only
wrappers around x_tables provided functions
o all matches/targets that are used from ip_tables and ip6_tables
are now implemented as xt_FOOBAR.c files and provide module aliases
to ipt_FOOBAR and ip6t_FOOBAR
o header files for xt_matches are in include/linux/netfilter/,
include/linux/netfilter_{ipv4,ipv6} contains compatibility wrappers
around the xt_FOOBAR.h headers
Based on this patchset we're going to further unify the code,
gradually getting rid of all the layer 3 specific assumptions.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-01-12 14:30:04 -07:00
|
|
|
xt_table_unlock(t);
|
2005-04-16 16:20:36 -06:00
|
|
|
free_newinfo_counters_untrans:
|
|
|
|
vfree(counters);
|
2007-12-17 23:26:54 -07:00
|
|
|
out:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-06-25 23:51:59 -06:00
|
|
|
static int do_replace(struct net *net, const void __user *user,
|
2015-10-14 16:17:06 -06:00
|
|
|
unsigned int len)
|
2007-12-17 23:26:54 -07:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct arpt_replace tmp;
|
|
|
|
struct xt_table_info *newinfo;
|
|
|
|
void *loc_cpu_entry;
|
2010-02-24 10:32:59 -07:00
|
|
|
struct arpt_entry *iter;
|
2007-12-17 23:26:54 -07:00
|
|
|
|
|
|
|
if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
/* overflow check */
|
|
|
|
if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
|
|
|
|
return -ENOMEM;
|
2015-05-19 18:55:17 -06:00
|
|
|
if (tmp.num_counters == 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2011-03-15 06:35:21 -06:00
|
|
|
tmp.name[sizeof(tmp.name)-1] = 0;
|
2007-12-17 23:26:54 -07:00
|
|
|
|
|
|
|
newinfo = xt_alloc_table_info(tmp.size);
|
|
|
|
if (!newinfo)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2015-06-10 17:34:55 -06:00
|
|
|
loc_cpu_entry = newinfo->entries;
|
2007-12-17 23:26:54 -07:00
|
|
|
if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
|
|
|
|
tmp.size) != 0) {
|
|
|
|
ret = -EFAULT;
|
|
|
|
goto free_newinfo;
|
|
|
|
}
|
|
|
|
|
2019-12-26 17:33:10 -07:00
|
|
|
ret = translate_table(net, newinfo, loc_cpu_entry, &tmp);
|
2007-12-17 23:26:54 -07:00
|
|
|
if (ret != 0)
|
|
|
|
goto free_newinfo;
|
|
|
|
|
2008-01-31 05:04:32 -07:00
|
|
|
ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
|
2007-12-17 23:26:54 -07:00
|
|
|
tmp.num_counters, tmp.counters);
|
|
|
|
if (ret)
|
|
|
|
goto free_newinfo_untrans;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
free_newinfo_untrans:
|
2010-02-24 10:32:59 -07:00
|
|
|
xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
|
2020-01-11 15:19:53 -07:00
|
|
|
cleanup_entry(iter, net);
|
2005-04-16 16:20:36 -06:00
|
|
|
free_newinfo:
|
[NETFILTER] x_tables: Abstraction layer for {ip,ip6,arp}_tables
This monster-patch tries to do the best job for unifying the data
structures and backend interfaces for the three evil clones ip_tables,
ip6_tables and arp_tables. In an ideal world we would never have
allowed this kind of copy+paste programming... but well, our world
isn't (yet?) ideal.
o introduce a new x_tables module
o {ip,arp,ip6}_tables depend on this x_tables module
o registration functions for tables, matches and targets are only
wrappers around x_tables provided functions
o all matches/targets that are used from ip_tables and ip6_tables
are now implemented as xt_FOOBAR.c files and provide module aliases
to ipt_FOOBAR and ip6t_FOOBAR
o header files for xt_matches are in include/linux/netfilter/,
include/linux/netfilter_{ipv4,ipv6} contains compatibility wrappers
around the xt_FOOBAR.h headers
Based on this patchset we're going to further unify the code,
gradually getting rid of all the layer 3 specific assumptions.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-01-12 14:30:04 -07:00
|
|
|
xt_free_table_info(newinfo);
|
2005-04-16 16:20:36 -06:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-06-25 23:51:59 -06:00
|
|
|
static int do_add_counters(struct net *net, const void __user *user,
|
|
|
|
unsigned int len, int compat)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2015-06-10 17:34:55 -06:00
|
|
|
unsigned int i;
|
2007-12-17 23:26:54 -07:00
|
|
|
struct xt_counters_info tmp;
|
|
|
|
struct xt_counters *paddc;
|
2008-04-14 03:15:43 -06:00
|
|
|
struct xt_table *t;
|
2008-04-14 03:15:35 -06:00
|
|
|
const struct xt_table_info *private;
|
2005-10-26 01:34:24 -06:00
|
|
|
int ret = 0;
|
2010-02-24 10:32:59 -07:00
|
|
|
struct arpt_entry *iter;
|
2011-04-04 09:04:03 -06:00
|
|
|
unsigned int addend;
|
2007-12-17 23:26:54 -07:00
|
|
|
|
2016-04-01 07:37:59 -06:00
|
|
|
paddc = xt_copy_counters_from_user(user, len, &tmp, compat);
|
|
|
|
if (IS_ERR(paddc))
|
|
|
|
return PTR_ERR(paddc);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2016-04-01 07:37:59 -06:00
|
|
|
t = xt_find_table_lock(net, NFPROTO_ARP, tmp.name);
|
2017-12-08 09:01:53 -07:00
|
|
|
if (IS_ERR(t)) {
|
|
|
|
ret = PTR_ERR(t);
|
2005-04-16 16:20:36 -06:00
|
|
|
goto free;
|
2005-10-26 01:34:24 -06:00
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2009-04-28 23:36:33 -06:00
|
|
|
local_bh_disable();
|
[NETFILTER] x_tables: Abstraction layer for {ip,ip6,arp}_tables
This monster-patch tries to do the best job for unifying the data
structures and backend interfaces for the three evil clones ip_tables,
ip6_tables and arp_tables. In an ideal world we would never have
allowed this kind of copy+paste programming... but well, our world
isn't (yet?) ideal.
o introduce a new x_tables module
o {ip,arp,ip6}_tables depend on this x_tables module
o registration functions for tables, matches and targets are only
wrappers around x_tables provided functions
o all matches/targets that are used from ip_tables and ip6_tables
are now implemented as xt_FOOBAR.c files and provide module aliases
to ipt_FOOBAR and ip6t_FOOBAR
o header files for xt_matches are in include/linux/netfilter/,
include/linux/netfilter_{ipv4,ipv6} contains compatibility wrappers
around the xt_FOOBAR.h headers
Based on this patchset we're going to further unify the code,
gradually getting rid of all the layer 3 specific assumptions.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-01-12 14:30:04 -07:00
|
|
|
private = t->private;
|
2016-04-01 07:37:59 -06:00
|
|
|
if (private->number != tmp.num_counters) {
|
2005-04-16 16:20:36 -06:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto unlock_up_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = 0;
|
2015-06-10 17:34:55 -06:00
|
|
|
|
2011-04-04 09:04:03 -06:00
|
|
|
addend = xt_write_recseq_begin();
|
2015-06-10 17:34:55 -06:00
|
|
|
xt_entry_foreach(iter, private->entries, private->size) {
|
2015-06-10 17:34:54 -06:00
|
|
|
struct xt_counters *tmp;
|
|
|
|
|
|
|
|
tmp = xt_get_this_cpu_counter(&iter->counters);
|
|
|
|
ADD_COUNTER(*tmp, paddc[i].bcnt, paddc[i].pcnt);
|
2010-02-24 10:33:43 -07:00
|
|
|
++i;
|
|
|
|
}
|
2011-04-04 09:04:03 -06:00
|
|
|
xt_write_recseq_end(addend);
|
2005-04-16 16:20:36 -06:00
|
|
|
unlock_up_free:
|
2009-04-28 23:36:33 -06:00
|
|
|
local_bh_enable();
|
[NETFILTER] x_tables: Abstraction layer for {ip,ip6,arp}_tables
This monster-patch tries to do the best job for unifying the data
structures and backend interfaces for the three evil clones ip_tables,
ip6_tables and arp_tables. In an ideal world we would never have
allowed this kind of copy+paste programming... but well, our world
isn't (yet?) ideal.
o introduce a new x_tables module
o {ip,arp,ip6}_tables depend on this x_tables module
o registration functions for tables, matches and targets are only
wrappers around x_tables provided functions
o all matches/targets that are used from ip_tables and ip6_tables
are now implemented as xt_FOOBAR.c files and provide module aliases
to ipt_FOOBAR and ip6t_FOOBAR
o header files for xt_matches are in include/linux/netfilter/,
include/linux/netfilter_{ipv4,ipv6} contains compatibility wrappers
around the xt_FOOBAR.h headers
Based on this patchset we're going to further unify the code,
gradually getting rid of all the layer 3 specific assumptions.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-01-12 14:30:04 -07:00
|
|
|
xt_table_unlock(t);
|
2005-10-26 01:34:24 -06:00
|
|
|
module_put(t->me);
|
2005-04-16 16:20:36 -06:00
|
|
|
free:
|
|
|
|
vfree(paddc);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2007-12-17 23:26:54 -07:00
|
|
|
#ifdef CONFIG_COMPAT
|
2016-04-01 06:17:32 -06:00
|
|
|
struct compat_arpt_replace {
|
|
|
|
char name[XT_TABLE_MAXNAMELEN];
|
|
|
|
u32 valid_hooks;
|
|
|
|
u32 num_entries;
|
|
|
|
u32 size;
|
|
|
|
u32 hook_entry[NF_ARP_NUMHOOKS];
|
|
|
|
u32 underflow[NF_ARP_NUMHOOKS];
|
|
|
|
u32 num_counters;
|
|
|
|
compat_uptr_t counters;
|
|
|
|
struct compat_arpt_entry entries[0];
|
|
|
|
};
|
|
|
|
|
2010-02-24 10:33:43 -07:00
|
|
|
static inline void compat_release_entry(struct compat_arpt_entry *e)
|
2007-12-17 23:26:54 -07:00
|
|
|
{
|
2010-10-13 08:11:22 -06:00
|
|
|
struct xt_entry_target *t;
|
2007-12-17 23:26:54 -07:00
|
|
|
|
|
|
|
t = compat_arpt_get_target(e);
|
|
|
|
module_put(t->u.kernel.target->me);
|
|
|
|
}
|
|
|
|
|
netfilter: x_tables: do compat validation via translate_table
This looks like refactoring, but its also a bug fix.
Problem is that the compat path (32bit iptables, 64bit kernel) lacks a few
sanity tests that are done in the normal path.
For example, we do not check for underflows and the base chain policies.
While its possible to also add such checks to the compat path, its more
copy&pastry, for instance we cannot reuse check_underflow() helper as
e->target_offset differs in the compat case.
Other problem is that it makes auditing for validation errors harder; two
places need to be checked and kept in sync.
At a high level 32 bit compat works like this:
1- initial pass over blob:
validate match/entry offsets, bounds checking
lookup all matches and targets
do bookkeeping wrt. size delta of 32/64bit structures
assign match/target.u.kernel pointer (points at kernel
implementation, needed to access ->compatsize etc.)
2- allocate memory according to the total bookkeeping size to
contain the translated ruleset
3- second pass over original blob:
for each entry, copy the 32bit representation to the newly allocated
memory. This also does any special match translations (e.g.
adjust 32bit to 64bit longs, etc).
4- check if ruleset is free of loops (chase all jumps)
5-first pass over translated blob:
call the checkentry function of all matches and targets.
The alternative implemented by this patch is to drop steps 3&4 from the
compat process, the translation is changed into an intermediate step
rather than a full 1:1 translate_table replacement.
In the 2nd pass (step #3), change the 64bit ruleset back to a kernel
representation, i.e. put() the kernel pointer and restore ->u.user.name .
This gets us a 64bit ruleset that is in the format generated by a 64bit
iptables userspace -- we can then use translate_table() to get the
'native' sanity checks.
This has two drawbacks:
1. we re-validate all the match and target entry structure sizes even
though compat translation is supposed to never generate bogus offsets.
2. we put and then re-lookup each match and target.
THe upside is that we get all sanity tests and ruleset validations
provided by the normal path and can remove some duplicated compat code.
iptables-restore time of autogenerated ruleset with 300k chains of form
-A CHAIN0001 -m limit --limit 1/s -j CHAIN0002
-A CHAIN0002 -m limit --limit 1/s -j CHAIN0003
shows no noticeable differences in restore times:
old: 0m30.796s
new: 0m31.521s
64bit: 0m25.674s
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2016-04-01 06:17:34 -06:00
|
|
|
static int
|
2007-12-17 23:26:54 -07:00
|
|
|
check_compat_entry_size_and_hooks(struct compat_arpt_entry *e,
|
|
|
|
struct xt_table_info *newinfo,
|
|
|
|
unsigned int *size,
|
2009-06-25 23:51:59 -06:00
|
|
|
const unsigned char *base,
|
netfilter: x_tables: do compat validation via translate_table
This looks like refactoring, but its also a bug fix.
Problem is that the compat path (32bit iptables, 64bit kernel) lacks a few
sanity tests that are done in the normal path.
For example, we do not check for underflows and the base chain policies.
While its possible to also add such checks to the compat path, its more
copy&pastry, for instance we cannot reuse check_underflow() helper as
e->target_offset differs in the compat case.
Other problem is that it makes auditing for validation errors harder; two
places need to be checked and kept in sync.
At a high level 32 bit compat works like this:
1- initial pass over blob:
validate match/entry offsets, bounds checking
lookup all matches and targets
do bookkeeping wrt. size delta of 32/64bit structures
assign match/target.u.kernel pointer (points at kernel
implementation, needed to access ->compatsize etc.)
2- allocate memory according to the total bookkeeping size to
contain the translated ruleset
3- second pass over original blob:
for each entry, copy the 32bit representation to the newly allocated
memory. This also does any special match translations (e.g.
adjust 32bit to 64bit longs, etc).
4- check if ruleset is free of loops (chase all jumps)
5-first pass over translated blob:
call the checkentry function of all matches and targets.
The alternative implemented by this patch is to drop steps 3&4 from the
compat process, the translation is changed into an intermediate step
rather than a full 1:1 translate_table replacement.
In the 2nd pass (step #3), change the 64bit ruleset back to a kernel
representation, i.e. put() the kernel pointer and restore ->u.user.name .
This gets us a 64bit ruleset that is in the format generated by a 64bit
iptables userspace -- we can then use translate_table() to get the
'native' sanity checks.
This has two drawbacks:
1. we re-validate all the match and target entry structure sizes even
though compat translation is supposed to never generate bogus offsets.
2. we put and then re-lookup each match and target.
THe upside is that we get all sanity tests and ruleset validations
provided by the normal path and can remove some duplicated compat code.
iptables-restore time of autogenerated ruleset with 300k chains of form
-A CHAIN0001 -m limit --limit 1/s -j CHAIN0002
-A CHAIN0002 -m limit --limit 1/s -j CHAIN0003
shows no noticeable differences in restore times:
old: 0m30.796s
new: 0m31.521s
64bit: 0m25.674s
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2016-04-01 06:17:34 -06:00
|
|
|
const unsigned char *limit)
|
2007-12-17 23:26:54 -07:00
|
|
|
{
|
2010-10-13 08:11:22 -06:00
|
|
|
struct xt_entry_target *t;
|
2007-12-17 23:26:54 -07:00
|
|
|
struct xt_target *target;
|
|
|
|
unsigned int entry_offset;
|
netfilter: x_tables: do compat validation via translate_table
This looks like refactoring, but its also a bug fix.
Problem is that the compat path (32bit iptables, 64bit kernel) lacks a few
sanity tests that are done in the normal path.
For example, we do not check for underflows and the base chain policies.
While its possible to also add such checks to the compat path, its more
copy&pastry, for instance we cannot reuse check_underflow() helper as
e->target_offset differs in the compat case.
Other problem is that it makes auditing for validation errors harder; two
places need to be checked and kept in sync.
At a high level 32 bit compat works like this:
1- initial pass over blob:
validate match/entry offsets, bounds checking
lookup all matches and targets
do bookkeeping wrt. size delta of 32/64bit structures
assign match/target.u.kernel pointer (points at kernel
implementation, needed to access ->compatsize etc.)
2- allocate memory according to the total bookkeeping size to
contain the translated ruleset
3- second pass over original blob:
for each entry, copy the 32bit representation to the newly allocated
memory. This also does any special match translations (e.g.
adjust 32bit to 64bit longs, etc).
4- check if ruleset is free of loops (chase all jumps)
5-first pass over translated blob:
call the checkentry function of all matches and targets.
The alternative implemented by this patch is to drop steps 3&4 from the
compat process, the translation is changed into an intermediate step
rather than a full 1:1 translate_table replacement.
In the 2nd pass (step #3), change the 64bit ruleset back to a kernel
representation, i.e. put() the kernel pointer and restore ->u.user.name .
This gets us a 64bit ruleset that is in the format generated by a 64bit
iptables userspace -- we can then use translate_table() to get the
'native' sanity checks.
This has two drawbacks:
1. we re-validate all the match and target entry structure sizes even
though compat translation is supposed to never generate bogus offsets.
2. we put and then re-lookup each match and target.
THe upside is that we get all sanity tests and ruleset validations
provided by the normal path and can remove some duplicated compat code.
iptables-restore time of autogenerated ruleset with 300k chains of form
-A CHAIN0001 -m limit --limit 1/s -j CHAIN0002
-A CHAIN0002 -m limit --limit 1/s -j CHAIN0003
shows no noticeable differences in restore times:
old: 0m30.796s
new: 0m31.521s
64bit: 0m25.674s
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2016-04-01 06:17:34 -06:00
|
|
|
int ret, off;
|
2007-12-17 23:26:54 -07:00
|
|
|
|
2009-11-23 15:17:06 -07:00
|
|
|
if ((unsigned long)e % __alignof__(struct compat_arpt_entry) != 0 ||
|
2016-03-22 11:02:50 -06:00
|
|
|
(unsigned char *)e + sizeof(struct compat_arpt_entry) >= limit ||
|
2016-05-03 05:54:23 -06:00
|
|
|
(unsigned char *)e + e->next_offset > limit)
|
2007-12-17 23:26:54 -07:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (e->next_offset < sizeof(struct compat_arpt_entry) +
|
2016-05-03 05:54:23 -06:00
|
|
|
sizeof(struct compat_xt_entry_target))
|
2007-12-17 23:26:54 -07:00
|
|
|
return -EINVAL;
|
|
|
|
|
2016-04-01 06:17:24 -06:00
|
|
|
if (!arp_checkentry(&e->arp))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2016-04-01 06:17:28 -06:00
|
|
|
ret = xt_compat_check_entry_offsets(e, e->elems, e->target_offset,
|
2016-04-01 06:17:26 -06:00
|
|
|
e->next_offset);
|
2007-12-17 23:26:54 -07:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
off = sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry);
|
|
|
|
entry_offset = (void *)e - (void *)base;
|
|
|
|
|
|
|
|
t = compat_arpt_get_target(e);
|
2009-07-10 10:55:11 -06:00
|
|
|
target = xt_request_find_target(NFPROTO_ARP, t->u.user.name,
|
|
|
|
t->u.user.revision);
|
|
|
|
if (IS_ERR(target)) {
|
|
|
|
ret = PTR_ERR(target);
|
2007-12-17 23:26:54 -07:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
t->u.kernel.target = target;
|
|
|
|
|
|
|
|
off += xt_compat_target_offset(target);
|
|
|
|
*size += off;
|
2008-10-08 03:35:01 -06:00
|
|
|
ret = xt_compat_add_offset(NFPROTO_ARP, entry_offset, off);
|
2007-12-17 23:26:54 -07:00
|
|
|
if (ret)
|
|
|
|
goto release_target;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
release_target:
|
|
|
|
module_put(t->u.kernel.target->me);
|
|
|
|
out:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-04-01 06:17:33 -06:00
|
|
|
static void
|
2007-12-17 23:26:54 -07:00
|
|
|
compat_copy_entry_from_user(struct compat_arpt_entry *e, void **dstptr,
|
2016-04-01 06:17:32 -06:00
|
|
|
unsigned int *size,
|
2007-12-17 23:26:54 -07:00
|
|
|
struct xt_table_info *newinfo, unsigned char *base)
|
|
|
|
{
|
2010-10-13 08:11:22 -06:00
|
|
|
struct xt_entry_target *t;
|
2007-12-17 23:26:54 -07:00
|
|
|
struct arpt_entry *de;
|
|
|
|
unsigned int origsize;
|
2016-04-01 06:17:33 -06:00
|
|
|
int h;
|
2007-12-17 23:26:54 -07:00
|
|
|
|
|
|
|
origsize = *size;
|
2017-03-28 13:05:16 -06:00
|
|
|
de = *dstptr;
|
2007-12-17 23:26:54 -07:00
|
|
|
memcpy(de, e, sizeof(struct arpt_entry));
|
|
|
|
memcpy(&de->counters, &e->counters, sizeof(e->counters));
|
|
|
|
|
|
|
|
*dstptr += sizeof(struct arpt_entry);
|
|
|
|
*size += sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry);
|
|
|
|
|
|
|
|
de->target_offset = e->target_offset - (origsize - *size);
|
|
|
|
t = compat_arpt_get_target(e);
|
|
|
|
xt_compat_target_from_user(t, dstptr, size);
|
|
|
|
|
|
|
|
de->next_offset = e->next_offset - (origsize - *size);
|
|
|
|
for (h = 0; h < NF_ARP_NUMHOOKS; h++) {
|
|
|
|
if ((unsigned char *)de - base < newinfo->hook_entry[h])
|
|
|
|
newinfo->hook_entry[h] -= origsize - *size;
|
|
|
|
if ((unsigned char *)de - base < newinfo->underflow[h])
|
|
|
|
newinfo->underflow[h] -= origsize - *size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-26 17:33:10 -07:00
|
|
|
static int translate_compat_table(struct net *net,
|
|
|
|
struct xt_table_info **pinfo,
|
2007-12-17 23:26:54 -07:00
|
|
|
void **pentry0,
|
2016-04-01 06:17:32 -06:00
|
|
|
const struct compat_arpt_replace *compatr)
|
2007-12-17 23:26:54 -07:00
|
|
|
{
|
|
|
|
unsigned int i, j;
|
|
|
|
struct xt_table_info *newinfo, *info;
|
|
|
|
void *pos, *entry0, *entry1;
|
2010-02-24 10:32:59 -07:00
|
|
|
struct compat_arpt_entry *iter0;
|
netfilter: x_tables: do compat validation via translate_table
This looks like refactoring, but its also a bug fix.
Problem is that the compat path (32bit iptables, 64bit kernel) lacks a few
sanity tests that are done in the normal path.
For example, we do not check for underflows and the base chain policies.
While its possible to also add such checks to the compat path, its more
copy&pastry, for instance we cannot reuse check_underflow() helper as
e->target_offset differs in the compat case.
Other problem is that it makes auditing for validation errors harder; two
places need to be checked and kept in sync.
At a high level 32 bit compat works like this:
1- initial pass over blob:
validate match/entry offsets, bounds checking
lookup all matches and targets
do bookkeeping wrt. size delta of 32/64bit structures
assign match/target.u.kernel pointer (points at kernel
implementation, needed to access ->compatsize etc.)
2- allocate memory according to the total bookkeeping size to
contain the translated ruleset
3- second pass over original blob:
for each entry, copy the 32bit representation to the newly allocated
memory. This also does any special match translations (e.g.
adjust 32bit to 64bit longs, etc).
4- check if ruleset is free of loops (chase all jumps)
5-first pass over translated blob:
call the checkentry function of all matches and targets.
The alternative implemented by this patch is to drop steps 3&4 from the
compat process, the translation is changed into an intermediate step
rather than a full 1:1 translate_table replacement.
In the 2nd pass (step #3), change the 64bit ruleset back to a kernel
representation, i.e. put() the kernel pointer and restore ->u.user.name .
This gets us a 64bit ruleset that is in the format generated by a 64bit
iptables userspace -- we can then use translate_table() to get the
'native' sanity checks.
This has two drawbacks:
1. we re-validate all the match and target entry structure sizes even
though compat translation is supposed to never generate bogus offsets.
2. we put and then re-lookup each match and target.
THe upside is that we get all sanity tests and ruleset validations
provided by the normal path and can remove some duplicated compat code.
iptables-restore time of autogenerated ruleset with 300k chains of form
-A CHAIN0001 -m limit --limit 1/s -j CHAIN0002
-A CHAIN0002 -m limit --limit 1/s -j CHAIN0003
shows no noticeable differences in restore times:
old: 0m30.796s
new: 0m31.521s
64bit: 0m25.674s
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2016-04-01 06:17:34 -06:00
|
|
|
struct arpt_replace repl;
|
2007-12-17 23:26:54 -07:00
|
|
|
unsigned int size;
|
2018-02-27 11:42:34 -07:00
|
|
|
int ret;
|
2007-12-17 23:26:54 -07:00
|
|
|
|
|
|
|
info = *pinfo;
|
|
|
|
entry0 = *pentry0;
|
2016-04-01 06:17:32 -06:00
|
|
|
size = compatr->size;
|
|
|
|
info->number = compatr->num_entries;
|
2007-12-17 23:26:54 -07:00
|
|
|
|
|
|
|
j = 0;
|
2008-10-08 03:35:01 -06:00
|
|
|
xt_compat_lock(NFPROTO_ARP);
|
2018-02-27 11:42:34 -07:00
|
|
|
ret = xt_compat_init_offsets(NFPROTO_ARP, compatr->num_entries);
|
|
|
|
if (ret)
|
|
|
|
goto out_unlock;
|
2007-12-17 23:26:54 -07:00
|
|
|
/* Walk through entries, checking offsets. */
|
2016-04-01 06:17:32 -06:00
|
|
|
xt_entry_foreach(iter0, entry0, compatr->size) {
|
2010-02-24 10:32:59 -07:00
|
|
|
ret = check_compat_entry_size_and_hooks(iter0, info, &size,
|
2010-02-26 09:53:31 -07:00
|
|
|
entry0,
|
netfilter: x_tables: do compat validation via translate_table
This looks like refactoring, but its also a bug fix.
Problem is that the compat path (32bit iptables, 64bit kernel) lacks a few
sanity tests that are done in the normal path.
For example, we do not check for underflows and the base chain policies.
While its possible to also add such checks to the compat path, its more
copy&pastry, for instance we cannot reuse check_underflow() helper as
e->target_offset differs in the compat case.
Other problem is that it makes auditing for validation errors harder; two
places need to be checked and kept in sync.
At a high level 32 bit compat works like this:
1- initial pass over blob:
validate match/entry offsets, bounds checking
lookup all matches and targets
do bookkeeping wrt. size delta of 32/64bit structures
assign match/target.u.kernel pointer (points at kernel
implementation, needed to access ->compatsize etc.)
2- allocate memory according to the total bookkeeping size to
contain the translated ruleset
3- second pass over original blob:
for each entry, copy the 32bit representation to the newly allocated
memory. This also does any special match translations (e.g.
adjust 32bit to 64bit longs, etc).
4- check if ruleset is free of loops (chase all jumps)
5-first pass over translated blob:
call the checkentry function of all matches and targets.
The alternative implemented by this patch is to drop steps 3&4 from the
compat process, the translation is changed into an intermediate step
rather than a full 1:1 translate_table replacement.
In the 2nd pass (step #3), change the 64bit ruleset back to a kernel
representation, i.e. put() the kernel pointer and restore ->u.user.name .
This gets us a 64bit ruleset that is in the format generated by a 64bit
iptables userspace -- we can then use translate_table() to get the
'native' sanity checks.
This has two drawbacks:
1. we re-validate all the match and target entry structure sizes even
though compat translation is supposed to never generate bogus offsets.
2. we put and then re-lookup each match and target.
THe upside is that we get all sanity tests and ruleset validations
provided by the normal path and can remove some duplicated compat code.
iptables-restore time of autogenerated ruleset with 300k chains of form
-A CHAIN0001 -m limit --limit 1/s -j CHAIN0002
-A CHAIN0002 -m limit --limit 1/s -j CHAIN0003
shows no noticeable differences in restore times:
old: 0m30.796s
new: 0m31.521s
64bit: 0m25.674s
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2016-04-01 06:17:34 -06:00
|
|
|
entry0 + compatr->size);
|
2010-02-24 10:32:59 -07:00
|
|
|
if (ret != 0)
|
2010-02-24 10:33:43 -07:00
|
|
|
goto out_unlock;
|
|
|
|
++j;
|
2010-02-24 10:32:59 -07:00
|
|
|
}
|
2007-12-17 23:26:54 -07:00
|
|
|
|
|
|
|
ret = -EINVAL;
|
2016-05-03 05:54:23 -06:00
|
|
|
if (j != compatr->num_entries)
|
2007-12-17 23:26:54 -07:00
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
ret = -ENOMEM;
|
|
|
|
newinfo = xt_alloc_table_info(size);
|
|
|
|
if (!newinfo)
|
|
|
|
goto out_unlock;
|
|
|
|
|
2016-04-01 06:17:32 -06:00
|
|
|
newinfo->number = compatr->num_entries;
|
2007-12-17 23:26:54 -07:00
|
|
|
for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
|
2016-11-29 19:56:26 -07:00
|
|
|
newinfo->hook_entry[i] = compatr->hook_entry[i];
|
|
|
|
newinfo->underflow[i] = compatr->underflow[i];
|
2007-12-17 23:26:54 -07:00
|
|
|
}
|
2015-06-10 17:34:55 -06:00
|
|
|
entry1 = newinfo->entries;
|
2007-12-17 23:26:54 -07:00
|
|
|
pos = entry1;
|
2016-04-01 06:17:32 -06:00
|
|
|
size = compatr->size;
|
2016-04-01 06:17:33 -06:00
|
|
|
xt_entry_foreach(iter0, entry0, compatr->size)
|
|
|
|
compat_copy_entry_from_user(iter0, &pos, &size,
|
|
|
|
newinfo, entry1);
|
netfilter: x_tables: do compat validation via translate_table
This looks like refactoring, but its also a bug fix.
Problem is that the compat path (32bit iptables, 64bit kernel) lacks a few
sanity tests that are done in the normal path.
For example, we do not check for underflows and the base chain policies.
While its possible to also add such checks to the compat path, its more
copy&pastry, for instance we cannot reuse check_underflow() helper as
e->target_offset differs in the compat case.
Other problem is that it makes auditing for validation errors harder; two
places need to be checked and kept in sync.
At a high level 32 bit compat works like this:
1- initial pass over blob:
validate match/entry offsets, bounds checking
lookup all matches and targets
do bookkeeping wrt. size delta of 32/64bit structures
assign match/target.u.kernel pointer (points at kernel
implementation, needed to access ->compatsize etc.)
2- allocate memory according to the total bookkeeping size to
contain the translated ruleset
3- second pass over original blob:
for each entry, copy the 32bit representation to the newly allocated
memory. This also does any special match translations (e.g.
adjust 32bit to 64bit longs, etc).
4- check if ruleset is free of loops (chase all jumps)
5-first pass over translated blob:
call the checkentry function of all matches and targets.
The alternative implemented by this patch is to drop steps 3&4 from the
compat process, the translation is changed into an intermediate step
rather than a full 1:1 translate_table replacement.
In the 2nd pass (step #3), change the 64bit ruleset back to a kernel
representation, i.e. put() the kernel pointer and restore ->u.user.name .
This gets us a 64bit ruleset that is in the format generated by a 64bit
iptables userspace -- we can then use translate_table() to get the
'native' sanity checks.
This has two drawbacks:
1. we re-validate all the match and target entry structure sizes even
though compat translation is supposed to never generate bogus offsets.
2. we put and then re-lookup each match and target.
THe upside is that we get all sanity tests and ruleset validations
provided by the normal path and can remove some duplicated compat code.
iptables-restore time of autogenerated ruleset with 300k chains of form
-A CHAIN0001 -m limit --limit 1/s -j CHAIN0002
-A CHAIN0002 -m limit --limit 1/s -j CHAIN0003
shows no noticeable differences in restore times:
old: 0m30.796s
new: 0m31.521s
64bit: 0m25.674s
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2016-04-01 06:17:34 -06:00
|
|
|
|
|
|
|
/* all module references in entry0 are now gone */
|
|
|
|
|
2008-10-08 03:35:01 -06:00
|
|
|
xt_compat_flush_offsets(NFPROTO_ARP);
|
|
|
|
xt_compat_unlock(NFPROTO_ARP);
|
2007-12-17 23:26:54 -07:00
|
|
|
|
netfilter: x_tables: do compat validation via translate_table
This looks like refactoring, but its also a bug fix.
Problem is that the compat path (32bit iptables, 64bit kernel) lacks a few
sanity tests that are done in the normal path.
For example, we do not check for underflows and the base chain policies.
While its possible to also add such checks to the compat path, its more
copy&pastry, for instance we cannot reuse check_underflow() helper as
e->target_offset differs in the compat case.
Other problem is that it makes auditing for validation errors harder; two
places need to be checked and kept in sync.
At a high level 32 bit compat works like this:
1- initial pass over blob:
validate match/entry offsets, bounds checking
lookup all matches and targets
do bookkeeping wrt. size delta of 32/64bit structures
assign match/target.u.kernel pointer (points at kernel
implementation, needed to access ->compatsize etc.)
2- allocate memory according to the total bookkeeping size to
contain the translated ruleset
3- second pass over original blob:
for each entry, copy the 32bit representation to the newly allocated
memory. This also does any special match translations (e.g.
adjust 32bit to 64bit longs, etc).
4- check if ruleset is free of loops (chase all jumps)
5-first pass over translated blob:
call the checkentry function of all matches and targets.
The alternative implemented by this patch is to drop steps 3&4 from the
compat process, the translation is changed into an intermediate step
rather than a full 1:1 translate_table replacement.
In the 2nd pass (step #3), change the 64bit ruleset back to a kernel
representation, i.e. put() the kernel pointer and restore ->u.user.name .
This gets us a 64bit ruleset that is in the format generated by a 64bit
iptables userspace -- we can then use translate_table() to get the
'native' sanity checks.
This has two drawbacks:
1. we re-validate all the match and target entry structure sizes even
though compat translation is supposed to never generate bogus offsets.
2. we put and then re-lookup each match and target.
THe upside is that we get all sanity tests and ruleset validations
provided by the normal path and can remove some duplicated compat code.
iptables-restore time of autogenerated ruleset with 300k chains of form
-A CHAIN0001 -m limit --limit 1/s -j CHAIN0002
-A CHAIN0002 -m limit --limit 1/s -j CHAIN0003
shows no noticeable differences in restore times:
old: 0m30.796s
new: 0m31.521s
64bit: 0m25.674s
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2016-04-01 06:17:34 -06:00
|
|
|
memcpy(&repl, compatr, sizeof(*compatr));
|
2015-06-10 17:34:54 -06:00
|
|
|
|
netfilter: x_tables: do compat validation via translate_table
This looks like refactoring, but its also a bug fix.
Problem is that the compat path (32bit iptables, 64bit kernel) lacks a few
sanity tests that are done in the normal path.
For example, we do not check for underflows and the base chain policies.
While its possible to also add such checks to the compat path, its more
copy&pastry, for instance we cannot reuse check_underflow() helper as
e->target_offset differs in the compat case.
Other problem is that it makes auditing for validation errors harder; two
places need to be checked and kept in sync.
At a high level 32 bit compat works like this:
1- initial pass over blob:
validate match/entry offsets, bounds checking
lookup all matches and targets
do bookkeeping wrt. size delta of 32/64bit structures
assign match/target.u.kernel pointer (points at kernel
implementation, needed to access ->compatsize etc.)
2- allocate memory according to the total bookkeeping size to
contain the translated ruleset
3- second pass over original blob:
for each entry, copy the 32bit representation to the newly allocated
memory. This also does any special match translations (e.g.
adjust 32bit to 64bit longs, etc).
4- check if ruleset is free of loops (chase all jumps)
5-first pass over translated blob:
call the checkentry function of all matches and targets.
The alternative implemented by this patch is to drop steps 3&4 from the
compat process, the translation is changed into an intermediate step
rather than a full 1:1 translate_table replacement.
In the 2nd pass (step #3), change the 64bit ruleset back to a kernel
representation, i.e. put() the kernel pointer and restore ->u.user.name .
This gets us a 64bit ruleset that is in the format generated by a 64bit
iptables userspace -- we can then use translate_table() to get the
'native' sanity checks.
This has two drawbacks:
1. we re-validate all the match and target entry structure sizes even
though compat translation is supposed to never generate bogus offsets.
2. we put and then re-lookup each match and target.
THe upside is that we get all sanity tests and ruleset validations
provided by the normal path and can remove some duplicated compat code.
iptables-restore time of autogenerated ruleset with 300k chains of form
-A CHAIN0001 -m limit --limit 1/s -j CHAIN0002
-A CHAIN0002 -m limit --limit 1/s -j CHAIN0003
shows no noticeable differences in restore times:
old: 0m30.796s
new: 0m31.521s
64bit: 0m25.674s
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2016-04-01 06:17:34 -06:00
|
|
|
for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
|
|
|
|
repl.hook_entry[i] = newinfo->hook_entry[i];
|
|
|
|
repl.underflow[i] = newinfo->underflow[i];
|
2007-12-17 23:26:54 -07:00
|
|
|
}
|
|
|
|
|
netfilter: x_tables: do compat validation via translate_table
This looks like refactoring, but its also a bug fix.
Problem is that the compat path (32bit iptables, 64bit kernel) lacks a few
sanity tests that are done in the normal path.
For example, we do not check for underflows and the base chain policies.
While its possible to also add such checks to the compat path, its more
copy&pastry, for instance we cannot reuse check_underflow() helper as
e->target_offset differs in the compat case.
Other problem is that it makes auditing for validation errors harder; two
places need to be checked and kept in sync.
At a high level 32 bit compat works like this:
1- initial pass over blob:
validate match/entry offsets, bounds checking
lookup all matches and targets
do bookkeeping wrt. size delta of 32/64bit structures
assign match/target.u.kernel pointer (points at kernel
implementation, needed to access ->compatsize etc.)
2- allocate memory according to the total bookkeeping size to
contain the translated ruleset
3- second pass over original blob:
for each entry, copy the 32bit representation to the newly allocated
memory. This also does any special match translations (e.g.
adjust 32bit to 64bit longs, etc).
4- check if ruleset is free of loops (chase all jumps)
5-first pass over translated blob:
call the checkentry function of all matches and targets.
The alternative implemented by this patch is to drop steps 3&4 from the
compat process, the translation is changed into an intermediate step
rather than a full 1:1 translate_table replacement.
In the 2nd pass (step #3), change the 64bit ruleset back to a kernel
representation, i.e. put() the kernel pointer and restore ->u.user.name .
This gets us a 64bit ruleset that is in the format generated by a 64bit
iptables userspace -- we can then use translate_table() to get the
'native' sanity checks.
This has two drawbacks:
1. we re-validate all the match and target entry structure sizes even
though compat translation is supposed to never generate bogus offsets.
2. we put and then re-lookup each match and target.
THe upside is that we get all sanity tests and ruleset validations
provided by the normal path and can remove some duplicated compat code.
iptables-restore time of autogenerated ruleset with 300k chains of form
-A CHAIN0001 -m limit --limit 1/s -j CHAIN0002
-A CHAIN0002 -m limit --limit 1/s -j CHAIN0003
shows no noticeable differences in restore times:
old: 0m30.796s
new: 0m31.521s
64bit: 0m25.674s
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2016-04-01 06:17:34 -06:00
|
|
|
repl.num_counters = 0;
|
|
|
|
repl.counters = NULL;
|
|
|
|
repl.size = newinfo->size;
|
2019-12-26 17:33:10 -07:00
|
|
|
ret = translate_table(net, newinfo, entry1, &repl);
|
netfilter: x_tables: do compat validation via translate_table
This looks like refactoring, but its also a bug fix.
Problem is that the compat path (32bit iptables, 64bit kernel) lacks a few
sanity tests that are done in the normal path.
For example, we do not check for underflows and the base chain policies.
While its possible to also add such checks to the compat path, its more
copy&pastry, for instance we cannot reuse check_underflow() helper as
e->target_offset differs in the compat case.
Other problem is that it makes auditing for validation errors harder; two
places need to be checked and kept in sync.
At a high level 32 bit compat works like this:
1- initial pass over blob:
validate match/entry offsets, bounds checking
lookup all matches and targets
do bookkeeping wrt. size delta of 32/64bit structures
assign match/target.u.kernel pointer (points at kernel
implementation, needed to access ->compatsize etc.)
2- allocate memory according to the total bookkeeping size to
contain the translated ruleset
3- second pass over original blob:
for each entry, copy the 32bit representation to the newly allocated
memory. This also does any special match translations (e.g.
adjust 32bit to 64bit longs, etc).
4- check if ruleset is free of loops (chase all jumps)
5-first pass over translated blob:
call the checkentry function of all matches and targets.
The alternative implemented by this patch is to drop steps 3&4 from the
compat process, the translation is changed into an intermediate step
rather than a full 1:1 translate_table replacement.
In the 2nd pass (step #3), change the 64bit ruleset back to a kernel
representation, i.e. put() the kernel pointer and restore ->u.user.name .
This gets us a 64bit ruleset that is in the format generated by a 64bit
iptables userspace -- we can then use translate_table() to get the
'native' sanity checks.
This has two drawbacks:
1. we re-validate all the match and target entry structure sizes even
though compat translation is supposed to never generate bogus offsets.
2. we put and then re-lookup each match and target.
THe upside is that we get all sanity tests and ruleset validations
provided by the normal path and can remove some duplicated compat code.
iptables-restore time of autogenerated ruleset with 300k chains of form
-A CHAIN0001 -m limit --limit 1/s -j CHAIN0002
-A CHAIN0002 -m limit --limit 1/s -j CHAIN0003
shows no noticeable differences in restore times:
old: 0m30.796s
new: 0m31.521s
64bit: 0m25.674s
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2016-04-01 06:17:34 -06:00
|
|
|
if (ret)
|
|
|
|
goto free_newinfo;
|
|
|
|
|
2007-12-17 23:26:54 -07:00
|
|
|
*pinfo = newinfo;
|
|
|
|
*pentry0 = entry1;
|
|
|
|
xt_free_table_info(info);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
free_newinfo:
|
|
|
|
xt_free_table_info(newinfo);
|
netfilter: x_tables: do compat validation via translate_table
This looks like refactoring, but its also a bug fix.
Problem is that the compat path (32bit iptables, 64bit kernel) lacks a few
sanity tests that are done in the normal path.
For example, we do not check for underflows and the base chain policies.
While its possible to also add such checks to the compat path, its more
copy&pastry, for instance we cannot reuse check_underflow() helper as
e->target_offset differs in the compat case.
Other problem is that it makes auditing for validation errors harder; two
places need to be checked and kept in sync.
At a high level 32 bit compat works like this:
1- initial pass over blob:
validate match/entry offsets, bounds checking
lookup all matches and targets
do bookkeeping wrt. size delta of 32/64bit structures
assign match/target.u.kernel pointer (points at kernel
implementation, needed to access ->compatsize etc.)
2- allocate memory according to the total bookkeeping size to
contain the translated ruleset
3- second pass over original blob:
for each entry, copy the 32bit representation to the newly allocated
memory. This also does any special match translations (e.g.
adjust 32bit to 64bit longs, etc).
4- check if ruleset is free of loops (chase all jumps)
5-first pass over translated blob:
call the checkentry function of all matches and targets.
The alternative implemented by this patch is to drop steps 3&4 from the
compat process, the translation is changed into an intermediate step
rather than a full 1:1 translate_table replacement.
In the 2nd pass (step #3), change the 64bit ruleset back to a kernel
representation, i.e. put() the kernel pointer and restore ->u.user.name .
This gets us a 64bit ruleset that is in the format generated by a 64bit
iptables userspace -- we can then use translate_table() to get the
'native' sanity checks.
This has two drawbacks:
1. we re-validate all the match and target entry structure sizes even
though compat translation is supposed to never generate bogus offsets.
2. we put and then re-lookup each match and target.
THe upside is that we get all sanity tests and ruleset validations
provided by the normal path and can remove some duplicated compat code.
iptables-restore time of autogenerated ruleset with 300k chains of form
-A CHAIN0001 -m limit --limit 1/s -j CHAIN0002
-A CHAIN0002 -m limit --limit 1/s -j CHAIN0003
shows no noticeable differences in restore times:
old: 0m30.796s
new: 0m31.521s
64bit: 0m25.674s
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2016-04-01 06:17:34 -06:00
|
|
|
return ret;
|
|
|
|
out_unlock:
|
|
|
|
xt_compat_flush_offsets(NFPROTO_ARP);
|
|
|
|
xt_compat_unlock(NFPROTO_ARP);
|
2016-04-01 06:17:32 -06:00
|
|
|
xt_entry_foreach(iter0, entry0, compatr->size) {
|
2010-02-24 10:33:43 -07:00
|
|
|
if (j-- == 0)
|
2010-02-24 10:32:59 -07:00
|
|
|
break;
|
2010-02-24 10:33:43 -07:00
|
|
|
compat_release_entry(iter0);
|
|
|
|
}
|
2007-12-17 23:26:54 -07:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2008-01-31 05:04:32 -07:00
|
|
|
static int compat_do_replace(struct net *net, void __user *user,
|
|
|
|
unsigned int len)
|
2007-12-17 23:26:54 -07:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct compat_arpt_replace tmp;
|
|
|
|
struct xt_table_info *newinfo;
|
|
|
|
void *loc_cpu_entry;
|
2010-02-24 10:32:59 -07:00
|
|
|
struct arpt_entry *iter;
|
2007-12-17 23:26:54 -07:00
|
|
|
|
|
|
|
if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
/* overflow check */
|
|
|
|
if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
|
|
|
|
return -ENOMEM;
|
2015-05-19 18:55:17 -06:00
|
|
|
if (tmp.num_counters == 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2011-03-15 06:35:21 -06:00
|
|
|
tmp.name[sizeof(tmp.name)-1] = 0;
|
2007-12-17 23:26:54 -07:00
|
|
|
|
|
|
|
newinfo = xt_alloc_table_info(tmp.size);
|
|
|
|
if (!newinfo)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2015-06-10 17:34:55 -06:00
|
|
|
loc_cpu_entry = newinfo->entries;
|
2007-12-17 23:26:54 -07:00
|
|
|
if (copy_from_user(loc_cpu_entry, user + sizeof(tmp), tmp.size) != 0) {
|
|
|
|
ret = -EFAULT;
|
|
|
|
goto free_newinfo;
|
|
|
|
}
|
|
|
|
|
2019-12-26 17:33:10 -07:00
|
|
|
ret = translate_compat_table(net, &newinfo, &loc_cpu_entry, &tmp);
|
2007-12-17 23:26:54 -07:00
|
|
|
if (ret != 0)
|
|
|
|
goto free_newinfo;
|
|
|
|
|
2008-01-31 05:04:32 -07:00
|
|
|
ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
|
2007-12-17 23:26:54 -07:00
|
|
|
tmp.num_counters, compat_ptr(tmp.counters));
|
|
|
|
if (ret)
|
|
|
|
goto free_newinfo_untrans;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
free_newinfo_untrans:
|
2010-02-24 10:32:59 -07:00
|
|
|
xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
|
2020-01-11 15:19:53 -07:00
|
|
|
cleanup_entry(iter, net);
|
2007-12-17 23:26:54 -07:00
|
|
|
free_newinfo:
|
|
|
|
xt_free_table_info(newinfo);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int compat_do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user,
|
|
|
|
unsigned int len)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
net: Allow userns root to control ipv4
Allow an unpriviled user who has created a user namespace, and then
created a network namespace to effectively use the new network
namespace, by reducing capable(CAP_NET_ADMIN) and
capable(CAP_NET_RAW) calls to be ns_capable(net->user_ns,
CAP_NET_ADMIN), or capable(net->user_ns, CAP_NET_RAW) calls.
Settings that merely control a single network device are allowed.
Either the network device is a logical network device where
restrictions make no difference or the network device is hardware NIC
that has been explicity moved from the initial network namespace.
In general policy and network stack state changes are allowed
while resource control is left unchanged.
Allow creating raw sockets.
Allow the SIOCSARP ioctl to control the arp cache.
Allow the SIOCSIFFLAG ioctl to allow setting network device flags.
Allow the SIOCSIFADDR ioctl to allow setting a netdevice ipv4 address.
Allow the SIOCSIFBRDADDR ioctl to allow setting a netdevice ipv4 broadcast address.
Allow the SIOCSIFDSTADDR ioctl to allow setting a netdevice ipv4 destination address.
Allow the SIOCSIFNETMASK ioctl to allow setting a netdevice ipv4 netmask.
Allow the SIOCADDRT and SIOCDELRT ioctls to allow adding and deleting ipv4 routes.
Allow the SIOCADDTUNNEL, SIOCCHGTUNNEL and SIOCDELTUNNEL ioctls for
adding, changing and deleting gre tunnels.
Allow the SIOCADDTUNNEL, SIOCCHGTUNNEL and SIOCDELTUNNEL ioctls for
adding, changing and deleting ipip tunnels.
Allow the SIOCADDTUNNEL, SIOCCHGTUNNEL and SIOCDELTUNNEL ioctls for
adding, changing and deleting ipsec virtual tunnel interfaces.
Allow setting the MRT_INIT, MRT_DONE, MRT_ADD_VIF, MRT_DEL_VIF, MRT_ADD_MFC,
MRT_DEL_MFC, MRT_ASSERT, MRT_PIM, MRT_TABLE socket options on multicast routing
sockets.
Allow setting and receiving IPOPT_CIPSO, IP_OPT_SEC, IP_OPT_SID and
arbitrary ip options.
Allow setting IP_SEC_POLICY/IP_XFRM_POLICY ipv4 socket option.
Allow setting the IP_TRANSPARENT ipv4 socket option.
Allow setting the TCP_REPAIR socket option.
Allow setting the TCP_CONGESTION socket option.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2012-11-15 20:03:05 -07:00
|
|
|
if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
|
2007-12-17 23:26:54 -07:00
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case ARPT_SO_SET_REPLACE:
|
2008-03-25 11:26:21 -06:00
|
|
|
ret = compat_do_replace(sock_net(sk), user, len);
|
2007-12-17 23:26:54 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ARPT_SO_SET_ADD_COUNTERS:
|
2008-03-25 11:26:21 -06:00
|
|
|
ret = do_add_counters(sock_net(sk), user, len, 1);
|
2007-12-17 23:26:54 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
ret = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr,
|
|
|
|
compat_uint_t *size,
|
|
|
|
struct xt_counters *counters,
|
2010-02-24 10:33:43 -07:00
|
|
|
unsigned int i)
|
2007-12-17 23:26:54 -07:00
|
|
|
{
|
2010-10-13 08:11:22 -06:00
|
|
|
struct xt_entry_target *t;
|
2007-12-17 23:26:54 -07:00
|
|
|
struct compat_arpt_entry __user *ce;
|
|
|
|
u_int16_t target_offset, next_offset;
|
|
|
|
compat_uint_t origsize;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
origsize = *size;
|
2017-03-28 13:05:16 -06:00
|
|
|
ce = *dstptr;
|
2010-02-24 10:33:43 -07:00
|
|
|
if (copy_to_user(ce, e, sizeof(struct arpt_entry)) != 0 ||
|
|
|
|
copy_to_user(&ce->counters, &counters[i],
|
|
|
|
sizeof(counters[i])) != 0)
|
|
|
|
return -EFAULT;
|
2007-12-17 23:26:54 -07:00
|
|
|
|
|
|
|
*dstptr += sizeof(struct compat_arpt_entry);
|
|
|
|
*size -= sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry);
|
|
|
|
|
|
|
|
target_offset = e->target_offset - (origsize - *size);
|
|
|
|
|
|
|
|
t = arpt_get_target(e);
|
|
|
|
ret = xt_compat_target_to_user(t, dstptr, size);
|
|
|
|
if (ret)
|
2010-02-24 10:33:43 -07:00
|
|
|
return ret;
|
2007-12-17 23:26:54 -07:00
|
|
|
next_offset = e->next_offset - (origsize - *size);
|
2010-02-24 10:33:43 -07:00
|
|
|
if (put_user(target_offset, &ce->target_offset) != 0 ||
|
|
|
|
put_user(next_offset, &ce->next_offset) != 0)
|
|
|
|
return -EFAULT;
|
2007-12-17 23:26:54 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int compat_copy_entries_to_user(unsigned int total_size,
|
2008-04-14 03:15:43 -06:00
|
|
|
struct xt_table *table,
|
2007-12-17 23:26:54 -07:00
|
|
|
void __user *userptr)
|
|
|
|
{
|
|
|
|
struct xt_counters *counters;
|
2008-04-14 03:15:35 -06:00
|
|
|
const struct xt_table_info *private = table->private;
|
2007-12-17 23:26:54 -07:00
|
|
|
void __user *pos;
|
|
|
|
unsigned int size;
|
|
|
|
int ret = 0;
|
|
|
|
unsigned int i = 0;
|
2010-02-24 10:32:59 -07:00
|
|
|
struct arpt_entry *iter;
|
2007-12-17 23:26:54 -07:00
|
|
|
|
|
|
|
counters = alloc_counters(table);
|
|
|
|
if (IS_ERR(counters))
|
|
|
|
return PTR_ERR(counters);
|
|
|
|
|
|
|
|
pos = userptr;
|
|
|
|
size = total_size;
|
2015-06-10 17:34:55 -06:00
|
|
|
xt_entry_foreach(iter, private->entries, total_size) {
|
2010-02-24 10:32:59 -07:00
|
|
|
ret = compat_copy_entry_to_user(iter, &pos,
|
2010-02-26 09:53:31 -07:00
|
|
|
&size, counters, i++);
|
2010-02-24 10:32:59 -07:00
|
|
|
if (ret != 0)
|
|
|
|
break;
|
|
|
|
}
|
2007-12-17 23:26:54 -07:00
|
|
|
vfree(counters);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct compat_arpt_get_entries {
|
2010-10-13 07:56:56 -06:00
|
|
|
char name[XT_TABLE_MAXNAMELEN];
|
2007-12-17 23:26:54 -07:00
|
|
|
compat_uint_t size;
|
|
|
|
struct compat_arpt_entry entrytable[0];
|
|
|
|
};
|
|
|
|
|
2008-01-31 05:04:32 -07:00
|
|
|
static int compat_get_entries(struct net *net,
|
|
|
|
struct compat_arpt_get_entries __user *uptr,
|
2007-12-17 23:26:54 -07:00
|
|
|
int *len)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct compat_arpt_get_entries get;
|
2008-04-14 03:15:43 -06:00
|
|
|
struct xt_table *t;
|
2007-12-17 23:26:54 -07:00
|
|
|
|
2016-05-03 05:54:23 -06:00
|
|
|
if (*len < sizeof(get))
|
2007-12-17 23:26:54 -07:00
|
|
|
return -EINVAL;
|
|
|
|
if (copy_from_user(&get, uptr, sizeof(get)) != 0)
|
|
|
|
return -EFAULT;
|
2016-05-03 05:54:23 -06:00
|
|
|
if (*len != sizeof(struct compat_arpt_get_entries) + get.size)
|
2007-12-17 23:26:54 -07:00
|
|
|
return -EINVAL;
|
2016-05-03 05:54:23 -06:00
|
|
|
|
2016-03-24 14:29:53 -06:00
|
|
|
get.name[sizeof(get.name) - 1] = '\0';
|
2007-12-17 23:26:54 -07:00
|
|
|
|
2008-10-08 03:35:01 -06:00
|
|
|
xt_compat_lock(NFPROTO_ARP);
|
|
|
|
t = xt_find_table_lock(net, NFPROTO_ARP, get.name);
|
2017-12-08 09:01:53 -07:00
|
|
|
if (!IS_ERR(t)) {
|
2008-04-14 03:15:35 -06:00
|
|
|
const struct xt_table_info *private = t->private;
|
2007-12-17 23:26:54 -07:00
|
|
|
struct xt_table_info info;
|
|
|
|
|
|
|
|
ret = compat_table_info(private, &info);
|
|
|
|
if (!ret && get.size == info.size) {
|
|
|
|
ret = compat_copy_entries_to_user(private->size,
|
|
|
|
t, uptr->entrytable);
|
2016-05-03 05:54:23 -06:00
|
|
|
} else if (!ret)
|
2008-04-14 03:15:45 -06:00
|
|
|
ret = -EAGAIN;
|
2016-05-03 05:54:23 -06:00
|
|
|
|
2008-10-08 03:35:01 -06:00
|
|
|
xt_compat_flush_offsets(NFPROTO_ARP);
|
2007-12-17 23:26:54 -07:00
|
|
|
module_put(t->me);
|
|
|
|
xt_table_unlock(t);
|
|
|
|
} else
|
2017-12-08 09:01:53 -07:00
|
|
|
ret = PTR_ERR(t);
|
2007-12-17 23:26:54 -07:00
|
|
|
|
2008-10-08 03:35:01 -06:00
|
|
|
xt_compat_unlock(NFPROTO_ARP);
|
2007-12-17 23:26:54 -07:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int do_arpt_get_ctl(struct sock *, int, void __user *, int *);
|
|
|
|
|
|
|
|
static int compat_do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user,
|
|
|
|
int *len)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
net: Allow userns root to control ipv4
Allow an unpriviled user who has created a user namespace, and then
created a network namespace to effectively use the new network
namespace, by reducing capable(CAP_NET_ADMIN) and
capable(CAP_NET_RAW) calls to be ns_capable(net->user_ns,
CAP_NET_ADMIN), or capable(net->user_ns, CAP_NET_RAW) calls.
Settings that merely control a single network device are allowed.
Either the network device is a logical network device where
restrictions make no difference or the network device is hardware NIC
that has been explicity moved from the initial network namespace.
In general policy and network stack state changes are allowed
while resource control is left unchanged.
Allow creating raw sockets.
Allow the SIOCSARP ioctl to control the arp cache.
Allow the SIOCSIFFLAG ioctl to allow setting network device flags.
Allow the SIOCSIFADDR ioctl to allow setting a netdevice ipv4 address.
Allow the SIOCSIFBRDADDR ioctl to allow setting a netdevice ipv4 broadcast address.
Allow the SIOCSIFDSTADDR ioctl to allow setting a netdevice ipv4 destination address.
Allow the SIOCSIFNETMASK ioctl to allow setting a netdevice ipv4 netmask.
Allow the SIOCADDRT and SIOCDELRT ioctls to allow adding and deleting ipv4 routes.
Allow the SIOCADDTUNNEL, SIOCCHGTUNNEL and SIOCDELTUNNEL ioctls for
adding, changing and deleting gre tunnels.
Allow the SIOCADDTUNNEL, SIOCCHGTUNNEL and SIOCDELTUNNEL ioctls for
adding, changing and deleting ipip tunnels.
Allow the SIOCADDTUNNEL, SIOCCHGTUNNEL and SIOCDELTUNNEL ioctls for
adding, changing and deleting ipsec virtual tunnel interfaces.
Allow setting the MRT_INIT, MRT_DONE, MRT_ADD_VIF, MRT_DEL_VIF, MRT_ADD_MFC,
MRT_DEL_MFC, MRT_ASSERT, MRT_PIM, MRT_TABLE socket options on multicast routing
sockets.
Allow setting and receiving IPOPT_CIPSO, IP_OPT_SEC, IP_OPT_SID and
arbitrary ip options.
Allow setting IP_SEC_POLICY/IP_XFRM_POLICY ipv4 socket option.
Allow setting the IP_TRANSPARENT ipv4 socket option.
Allow setting the TCP_REPAIR socket option.
Allow setting the TCP_CONGESTION socket option.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2012-11-15 20:03:05 -07:00
|
|
|
if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
|
2007-12-17 23:26:54 -07:00
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case ARPT_SO_GET_INFO:
|
2008-03-25 11:26:21 -06:00
|
|
|
ret = get_info(sock_net(sk), user, len, 1);
|
2007-12-17 23:26:54 -07:00
|
|
|
break;
|
|
|
|
case ARPT_SO_GET_ENTRIES:
|
2008-03-25 11:26:21 -06:00
|
|
|
ret = compat_get_entries(sock_net(sk), user, len);
|
2007-12-17 23:26:54 -07:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ret = do_arpt_get_ctl(sk, cmd, user, len);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
static int do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
net: Allow userns root to control ipv4
Allow an unpriviled user who has created a user namespace, and then
created a network namespace to effectively use the new network
namespace, by reducing capable(CAP_NET_ADMIN) and
capable(CAP_NET_RAW) calls to be ns_capable(net->user_ns,
CAP_NET_ADMIN), or capable(net->user_ns, CAP_NET_RAW) calls.
Settings that merely control a single network device are allowed.
Either the network device is a logical network device where
restrictions make no difference or the network device is hardware NIC
that has been explicity moved from the initial network namespace.
In general policy and network stack state changes are allowed
while resource control is left unchanged.
Allow creating raw sockets.
Allow the SIOCSARP ioctl to control the arp cache.
Allow the SIOCSIFFLAG ioctl to allow setting network device flags.
Allow the SIOCSIFADDR ioctl to allow setting a netdevice ipv4 address.
Allow the SIOCSIFBRDADDR ioctl to allow setting a netdevice ipv4 broadcast address.
Allow the SIOCSIFDSTADDR ioctl to allow setting a netdevice ipv4 destination address.
Allow the SIOCSIFNETMASK ioctl to allow setting a netdevice ipv4 netmask.
Allow the SIOCADDRT and SIOCDELRT ioctls to allow adding and deleting ipv4 routes.
Allow the SIOCADDTUNNEL, SIOCCHGTUNNEL and SIOCDELTUNNEL ioctls for
adding, changing and deleting gre tunnels.
Allow the SIOCADDTUNNEL, SIOCCHGTUNNEL and SIOCDELTUNNEL ioctls for
adding, changing and deleting ipip tunnels.
Allow the SIOCADDTUNNEL, SIOCCHGTUNNEL and SIOCDELTUNNEL ioctls for
adding, changing and deleting ipsec virtual tunnel interfaces.
Allow setting the MRT_INIT, MRT_DONE, MRT_ADD_VIF, MRT_DEL_VIF, MRT_ADD_MFC,
MRT_DEL_MFC, MRT_ASSERT, MRT_PIM, MRT_TABLE socket options on multicast routing
sockets.
Allow setting and receiving IPOPT_CIPSO, IP_OPT_SEC, IP_OPT_SID and
arbitrary ip options.
Allow setting IP_SEC_POLICY/IP_XFRM_POLICY ipv4 socket option.
Allow setting the IP_TRANSPARENT ipv4 socket option.
Allow setting the TCP_REPAIR socket option.
Allow setting the TCP_CONGESTION socket option.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2012-11-15 20:03:05 -07:00
|
|
|
if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
|
2005-04-16 16:20:36 -06:00
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case ARPT_SO_SET_REPLACE:
|
2008-03-25 11:26:21 -06:00
|
|
|
ret = do_replace(sock_net(sk), user, len);
|
2005-04-16 16:20:36 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ARPT_SO_SET_ADD_COUNTERS:
|
2008-03-25 11:26:21 -06:00
|
|
|
ret = do_add_counters(sock_net(sk), user, len, 0);
|
2005-04-16 16:20:36 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
ret = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
net: Allow userns root to control ipv4
Allow an unpriviled user who has created a user namespace, and then
created a network namespace to effectively use the new network
namespace, by reducing capable(CAP_NET_ADMIN) and
capable(CAP_NET_RAW) calls to be ns_capable(net->user_ns,
CAP_NET_ADMIN), or capable(net->user_ns, CAP_NET_RAW) calls.
Settings that merely control a single network device are allowed.
Either the network device is a logical network device where
restrictions make no difference or the network device is hardware NIC
that has been explicity moved from the initial network namespace.
In general policy and network stack state changes are allowed
while resource control is left unchanged.
Allow creating raw sockets.
Allow the SIOCSARP ioctl to control the arp cache.
Allow the SIOCSIFFLAG ioctl to allow setting network device flags.
Allow the SIOCSIFADDR ioctl to allow setting a netdevice ipv4 address.
Allow the SIOCSIFBRDADDR ioctl to allow setting a netdevice ipv4 broadcast address.
Allow the SIOCSIFDSTADDR ioctl to allow setting a netdevice ipv4 destination address.
Allow the SIOCSIFNETMASK ioctl to allow setting a netdevice ipv4 netmask.
Allow the SIOCADDRT and SIOCDELRT ioctls to allow adding and deleting ipv4 routes.
Allow the SIOCADDTUNNEL, SIOCCHGTUNNEL and SIOCDELTUNNEL ioctls for
adding, changing and deleting gre tunnels.
Allow the SIOCADDTUNNEL, SIOCCHGTUNNEL and SIOCDELTUNNEL ioctls for
adding, changing and deleting ipip tunnels.
Allow the SIOCADDTUNNEL, SIOCCHGTUNNEL and SIOCDELTUNNEL ioctls for
adding, changing and deleting ipsec virtual tunnel interfaces.
Allow setting the MRT_INIT, MRT_DONE, MRT_ADD_VIF, MRT_DEL_VIF, MRT_ADD_MFC,
MRT_DEL_MFC, MRT_ASSERT, MRT_PIM, MRT_TABLE socket options on multicast routing
sockets.
Allow setting and receiving IPOPT_CIPSO, IP_OPT_SEC, IP_OPT_SID and
arbitrary ip options.
Allow setting IP_SEC_POLICY/IP_XFRM_POLICY ipv4 socket option.
Allow setting the IP_TRANSPARENT ipv4 socket option.
Allow setting the TCP_REPAIR socket option.
Allow setting the TCP_CONGESTION socket option.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2012-11-15 20:03:05 -07:00
|
|
|
if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
|
2005-04-16 16:20:36 -06:00
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
switch (cmd) {
|
2007-12-17 23:26:24 -07:00
|
|
|
case ARPT_SO_GET_INFO:
|
2008-03-25 11:26:21 -06:00
|
|
|
ret = get_info(sock_net(sk), user, len, 0);
|
2007-12-17 23:26:24 -07:00
|
|
|
break;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-12-17 23:26:38 -07:00
|
|
|
case ARPT_SO_GET_ENTRIES:
|
2008-03-25 11:26:21 -06:00
|
|
|
ret = get_entries(sock_net(sk), user, len);
|
2005-04-16 16:20:36 -06:00
|
|
|
break;
|
|
|
|
|
2005-10-26 01:34:24 -06:00
|
|
|
case ARPT_SO_GET_REVISION_TARGET: {
|
[NETFILTER] x_tables: Abstraction layer for {ip,ip6,arp}_tables
This monster-patch tries to do the best job for unifying the data
structures and backend interfaces for the three evil clones ip_tables,
ip6_tables and arp_tables. In an ideal world we would never have
allowed this kind of copy+paste programming... but well, our world
isn't (yet?) ideal.
o introduce a new x_tables module
o {ip,arp,ip6}_tables depend on this x_tables module
o registration functions for tables, matches and targets are only
wrappers around x_tables provided functions
o all matches/targets that are used from ip_tables and ip6_tables
are now implemented as xt_FOOBAR.c files and provide module aliases
to ipt_FOOBAR and ip6t_FOOBAR
o header files for xt_matches are in include/linux/netfilter/,
include/linux/netfilter_{ipv4,ipv6} contains compatibility wrappers
around the xt_FOOBAR.h headers
Based on this patchset we're going to further unify the code,
gradually getting rid of all the layer 3 specific assumptions.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-01-12 14:30:04 -07:00
|
|
|
struct xt_get_revision rev;
|
2005-10-26 01:34:24 -06:00
|
|
|
|
|
|
|
if (*len != sizeof(rev)) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
|
|
|
|
ret = -EFAULT;
|
|
|
|
break;
|
|
|
|
}
|
2011-03-15 06:35:21 -06:00
|
|
|
rev.name[sizeof(rev.name)-1] = 0;
|
2005-10-26 01:34:24 -06:00
|
|
|
|
2008-10-08 03:35:01 -06:00
|
|
|
try_then_request_module(xt_find_revision(NFPROTO_ARP, rev.name,
|
[NETFILTER] x_tables: Abstraction layer for {ip,ip6,arp}_tables
This monster-patch tries to do the best job for unifying the data
structures and backend interfaces for the three evil clones ip_tables,
ip6_tables and arp_tables. In an ideal world we would never have
allowed this kind of copy+paste programming... but well, our world
isn't (yet?) ideal.
o introduce a new x_tables module
o {ip,arp,ip6}_tables depend on this x_tables module
o registration functions for tables, matches and targets are only
wrappers around x_tables provided functions
o all matches/targets that are used from ip_tables and ip6_tables
are now implemented as xt_FOOBAR.c files and provide module aliases
to ipt_FOOBAR and ip6t_FOOBAR
o header files for xt_matches are in include/linux/netfilter/,
include/linux/netfilter_{ipv4,ipv6} contains compatibility wrappers
around the xt_FOOBAR.h headers
Based on this patchset we're going to further unify the code,
gradually getting rid of all the layer 3 specific assumptions.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-01-12 14:30:04 -07:00
|
|
|
rev.revision, 1, &ret),
|
2005-10-26 01:34:24 -06:00
|
|
|
"arpt_%s", rev.name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
default:
|
|
|
|
ret = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-01-11 15:19:53 -07:00
|
|
|
static void __arpt_unregister_table(struct net *net, struct xt_table *table)
|
netfilter: xtables: don't hook tables by default
delay hook registration until the table is being requested inside a
namespace.
Historically, a particular table (iptables mangle, ip6tables filter, etc)
was registered on module load.
When netns support was added to iptables only the ip/ip6tables ruleset was
made namespace aware, not the actual hook points.
This means f.e. that when ipt_filter table/module is loaded on a system,
then each namespace on that system has an (empty) iptables filter ruleset.
In other words, if a namespace sends a packet, such skb is 'caught' by
netfilter machinery and fed to hooking points for that table (i.e. INPUT,
FORWARD, etc).
Thanks to Eric Biederman, hooks are no longer global, but per namespace.
This means that we can avoid allocation of empty ruleset in a namespace and
defer hook registration until we need the functionality.
We register a tables hook entry points ONLY in the initial namespace.
When an iptables get/setockopt is issued inside a given namespace, we check
if the table is found in the per-namespace list.
If not, we attempt to find it in the initial namespace, and, if found,
create an empty default table in the requesting namespace and register the
needed hooks.
Hook points are destroyed only once namespace is deleted, there is no
'usage count' (it makes no sense since there is no 'remove table' operation
in xtables api).
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2016-02-25 02:08:36 -07:00
|
|
|
{
|
|
|
|
struct xt_table_info *private;
|
|
|
|
void *loc_cpu_entry;
|
|
|
|
struct module *table_owner = table->me;
|
|
|
|
struct arpt_entry *iter;
|
|
|
|
|
|
|
|
private = xt_unregister_table(table);
|
|
|
|
|
|
|
|
/* Decrease module usage counts and free resources */
|
|
|
|
loc_cpu_entry = private->entries;
|
|
|
|
xt_entry_foreach(iter, loc_cpu_entry, private->size)
|
2020-01-11 15:19:53 -07:00
|
|
|
cleanup_entry(iter, net);
|
netfilter: xtables: don't hook tables by default
delay hook registration until the table is being requested inside a
namespace.
Historically, a particular table (iptables mangle, ip6tables filter, etc)
was registered on module load.
When netns support was added to iptables only the ip/ip6tables ruleset was
made namespace aware, not the actual hook points.
This means f.e. that when ipt_filter table/module is loaded on a system,
then each namespace on that system has an (empty) iptables filter ruleset.
In other words, if a namespace sends a packet, such skb is 'caught' by
netfilter machinery and fed to hooking points for that table (i.e. INPUT,
FORWARD, etc).
Thanks to Eric Biederman, hooks are no longer global, but per namespace.
This means that we can avoid allocation of empty ruleset in a namespace and
defer hook registration until we need the functionality.
We register a tables hook entry points ONLY in the initial namespace.
When an iptables get/setockopt is issued inside a given namespace, we check
if the table is found in the per-namespace list.
If not, we attempt to find it in the initial namespace, and, if found,
create an empty default table in the requesting namespace and register the
needed hooks.
Hook points are destroyed only once namespace is deleted, there is no
'usage count' (it makes no sense since there is no 'remove table' operation
in xtables api).
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2016-02-25 02:08:36 -07:00
|
|
|
if (private->number > private->initial_entries)
|
|
|
|
module_put(table_owner);
|
|
|
|
xt_free_table_info(private);
|
|
|
|
}
|
|
|
|
|
2016-02-25 02:08:35 -07:00
|
|
|
int arpt_register_table(struct net *net,
|
|
|
|
const struct xt_table *table,
|
|
|
|
const struct arpt_replace *repl,
|
|
|
|
const struct nf_hook_ops *ops,
|
|
|
|
struct xt_table **res)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
int ret;
|
[NETFILTER] x_tables: Abstraction layer for {ip,ip6,arp}_tables
This monster-patch tries to do the best job for unifying the data
structures and backend interfaces for the three evil clones ip_tables,
ip6_tables and arp_tables. In an ideal world we would never have
allowed this kind of copy+paste programming... but well, our world
isn't (yet?) ideal.
o introduce a new x_tables module
o {ip,arp,ip6}_tables depend on this x_tables module
o registration functions for tables, matches and targets are only
wrappers around x_tables provided functions
o all matches/targets that are used from ip_tables and ip6_tables
are now implemented as xt_FOOBAR.c files and provide module aliases
to ipt_FOOBAR and ip6t_FOOBAR
o header files for xt_matches are in include/linux/netfilter/,
include/linux/netfilter_{ipv4,ipv6} contains compatibility wrappers
around the xt_FOOBAR.h headers
Based on this patchset we're going to further unify the code,
gradually getting rid of all the layer 3 specific assumptions.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-01-12 14:30:04 -07:00
|
|
|
struct xt_table_info *newinfo;
|
2010-04-19 08:05:10 -06:00
|
|
|
struct xt_table_info bootstrap = {0};
|
2005-12-14 00:13:48 -07:00
|
|
|
void *loc_cpu_entry;
|
2008-01-31 05:01:49 -07:00
|
|
|
struct xt_table *new_table;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
[NETFILTER] x_tables: Abstraction layer for {ip,ip6,arp}_tables
This monster-patch tries to do the best job for unifying the data
structures and backend interfaces for the three evil clones ip_tables,
ip6_tables and arp_tables. In an ideal world we would never have
allowed this kind of copy+paste programming... but well, our world
isn't (yet?) ideal.
o introduce a new x_tables module
o {ip,arp,ip6}_tables depend on this x_tables module
o registration functions for tables, matches and targets are only
wrappers around x_tables provided functions
o all matches/targets that are used from ip_tables and ip6_tables
are now implemented as xt_FOOBAR.c files and provide module aliases
to ipt_FOOBAR and ip6t_FOOBAR
o header files for xt_matches are in include/linux/netfilter/,
include/linux/netfilter_{ipv4,ipv6} contains compatibility wrappers
around the xt_FOOBAR.h headers
Based on this patchset we're going to further unify the code,
gradually getting rid of all the layer 3 specific assumptions.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-01-12 14:30:04 -07:00
|
|
|
newinfo = xt_alloc_table_info(repl->size);
|
2016-02-25 02:08:35 -07:00
|
|
|
if (!newinfo)
|
|
|
|
return -ENOMEM;
|
2005-12-14 00:13:48 -07:00
|
|
|
|
2015-06-10 17:34:55 -06:00
|
|
|
loc_cpu_entry = newinfo->entries;
|
2005-12-14 00:13:48 -07:00
|
|
|
memcpy(loc_cpu_entry, repl->entries, repl->size);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2019-12-26 17:33:10 -07:00
|
|
|
ret = translate_table(net, newinfo, loc_cpu_entry, repl);
|
2008-01-31 05:02:44 -07:00
|
|
|
if (ret != 0)
|
|
|
|
goto out_free;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2008-01-31 05:04:32 -07:00
|
|
|
new_table = xt_register_table(net, table, &bootstrap, newinfo);
|
2008-01-31 05:01:49 -07:00
|
|
|
if (IS_ERR(new_table)) {
|
2008-01-31 05:02:44 -07:00
|
|
|
ret = PTR_ERR(new_table);
|
|
|
|
goto out_free;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
2016-02-25 02:08:35 -07:00
|
|
|
|
netfilter: xtables: don't hook tables by default
delay hook registration until the table is being requested inside a
namespace.
Historically, a particular table (iptables mangle, ip6tables filter, etc)
was registered on module load.
When netns support was added to iptables only the ip/ip6tables ruleset was
made namespace aware, not the actual hook points.
This means f.e. that when ipt_filter table/module is loaded on a system,
then each namespace on that system has an (empty) iptables filter ruleset.
In other words, if a namespace sends a packet, such skb is 'caught' by
netfilter machinery and fed to hooking points for that table (i.e. INPUT,
FORWARD, etc).
Thanks to Eric Biederman, hooks are no longer global, but per namespace.
This means that we can avoid allocation of empty ruleset in a namespace and
defer hook registration until we need the functionality.
We register a tables hook entry points ONLY in the initial namespace.
When an iptables get/setockopt is issued inside a given namespace, we check
if the table is found in the per-namespace list.
If not, we attempt to find it in the initial namespace, and, if found,
create an empty default table in the requesting namespace and register the
needed hooks.
Hook points are destroyed only once namespace is deleted, there is no
'usage count' (it makes no sense since there is no 'remove table' operation
in xtables api).
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2016-02-25 02:08:36 -07:00
|
|
|
/* set res now, will see skbs right after nf_register_net_hooks */
|
2016-02-25 02:08:35 -07:00
|
|
|
WRITE_ONCE(*res, new_table);
|
|
|
|
|
netfilter: xtables: don't hook tables by default
delay hook registration until the table is being requested inside a
namespace.
Historically, a particular table (iptables mangle, ip6tables filter, etc)
was registered on module load.
When netns support was added to iptables only the ip/ip6tables ruleset was
made namespace aware, not the actual hook points.
This means f.e. that when ipt_filter table/module is loaded on a system,
then each namespace on that system has an (empty) iptables filter ruleset.
In other words, if a namespace sends a packet, such skb is 'caught' by
netfilter machinery and fed to hooking points for that table (i.e. INPUT,
FORWARD, etc).
Thanks to Eric Biederman, hooks are no longer global, but per namespace.
This means that we can avoid allocation of empty ruleset in a namespace and
defer hook registration until we need the functionality.
We register a tables hook entry points ONLY in the initial namespace.
When an iptables get/setockopt is issued inside a given namespace, we check
if the table is found in the per-namespace list.
If not, we attempt to find it in the initial namespace, and, if found,
create an empty default table in the requesting namespace and register the
needed hooks.
Hook points are destroyed only once namespace is deleted, there is no
'usage count' (it makes no sense since there is no 'remove table' operation
in xtables api).
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2016-02-25 02:08:36 -07:00
|
|
|
ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));
|
|
|
|
if (ret != 0) {
|
2020-01-11 15:19:53 -07:00
|
|
|
__arpt_unregister_table(net, new_table);
|
netfilter: xtables: don't hook tables by default
delay hook registration until the table is being requested inside a
namespace.
Historically, a particular table (iptables mangle, ip6tables filter, etc)
was registered on module load.
When netns support was added to iptables only the ip/ip6tables ruleset was
made namespace aware, not the actual hook points.
This means f.e. that when ipt_filter table/module is loaded on a system,
then each namespace on that system has an (empty) iptables filter ruleset.
In other words, if a namespace sends a packet, such skb is 'caught' by
netfilter machinery and fed to hooking points for that table (i.e. INPUT,
FORWARD, etc).
Thanks to Eric Biederman, hooks are no longer global, but per namespace.
This means that we can avoid allocation of empty ruleset in a namespace and
defer hook registration until we need the functionality.
We register a tables hook entry points ONLY in the initial namespace.
When an iptables get/setockopt is issued inside a given namespace, we check
if the table is found in the per-namespace list.
If not, we attempt to find it in the initial namespace, and, if found,
create an empty default table in the requesting namespace and register the
needed hooks.
Hook points are destroyed only once namespace is deleted, there is no
'usage count' (it makes no sense since there is no 'remove table' operation
in xtables api).
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2016-02-25 02:08:36 -07:00
|
|
|
*res = NULL;
|
|
|
|
}
|
|
|
|
|
2016-02-25 02:08:35 -07:00
|
|
|
return ret;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2008-01-31 05:02:44 -07:00
|
|
|
out_free:
|
|
|
|
xt_free_table_info(newinfo);
|
2016-02-25 02:08:35 -07:00
|
|
|
return ret;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
2016-02-25 02:08:35 -07:00
|
|
|
void arpt_unregister_table(struct net *net, struct xt_table *table,
|
|
|
|
const struct nf_hook_ops *ops)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
netfilter: xtables: don't hook tables by default
delay hook registration until the table is being requested inside a
namespace.
Historically, a particular table (iptables mangle, ip6tables filter, etc)
was registered on module load.
When netns support was added to iptables only the ip/ip6tables ruleset was
made namespace aware, not the actual hook points.
This means f.e. that when ipt_filter table/module is loaded on a system,
then each namespace on that system has an (empty) iptables filter ruleset.
In other words, if a namespace sends a packet, such skb is 'caught' by
netfilter machinery and fed to hooking points for that table (i.e. INPUT,
FORWARD, etc).
Thanks to Eric Biederman, hooks are no longer global, but per namespace.
This means that we can avoid allocation of empty ruleset in a namespace and
defer hook registration until we need the functionality.
We register a tables hook entry points ONLY in the initial namespace.
When an iptables get/setockopt is issued inside a given namespace, we check
if the table is found in the per-namespace list.
If not, we attempt to find it in the initial namespace, and, if found,
create an empty default table in the requesting namespace and register the
needed hooks.
Hook points are destroyed only once namespace is deleted, there is no
'usage count' (it makes no sense since there is no 'remove table' operation
in xtables api).
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2016-02-25 02:08:36 -07:00
|
|
|
nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
|
2020-01-11 15:19:53 -07:00
|
|
|
__arpt_unregister_table(net, table);
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/* The built-in targets: standard (NULL) and error. */
|
2009-07-04 04:50:00 -06:00
|
|
|
static struct xt_target arpt_builtin_tg[] __read_mostly = {
|
|
|
|
{
|
2010-10-13 08:28:00 -06:00
|
|
|
.name = XT_STANDARD_TARGET,
|
2009-07-04 04:50:00 -06:00
|
|
|
.targetsize = sizeof(int),
|
|
|
|
.family = NFPROTO_ARP,
|
2007-12-17 23:26:54 -07:00
|
|
|
#ifdef CONFIG_COMPAT
|
2009-07-04 04:50:00 -06:00
|
|
|
.compatsize = sizeof(compat_int_t),
|
|
|
|
.compat_from_user = compat_standard_from_user,
|
|
|
|
.compat_to_user = compat_standard_to_user,
|
2007-12-17 23:26:54 -07:00
|
|
|
#endif
|
2009-07-04 04:50:00 -06:00
|
|
|
},
|
|
|
|
{
|
2010-10-13 08:28:00 -06:00
|
|
|
.name = XT_ERROR_TARGET,
|
2009-07-04 04:50:00 -06:00
|
|
|
.target = arpt_error,
|
2010-10-13 07:56:56 -06:00
|
|
|
.targetsize = XT_FUNCTION_MAXNAMELEN,
|
2009-07-04 04:50:00 -06:00
|
|
|
.family = NFPROTO_ARP,
|
|
|
|
},
|
2005-04-16 16:20:36 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct nf_sockopt_ops arpt_sockopts = {
|
|
|
|
.pf = PF_INET,
|
|
|
|
.set_optmin = ARPT_BASE_CTL,
|
|
|
|
.set_optmax = ARPT_SO_SET_MAX+1,
|
|
|
|
.set = do_arpt_set_ctl,
|
2007-12-17 23:26:54 -07:00
|
|
|
#ifdef CONFIG_COMPAT
|
|
|
|
.compat_set = compat_do_arpt_set_ctl,
|
|
|
|
#endif
|
2005-04-16 16:20:36 -06:00
|
|
|
.get_optmin = ARPT_BASE_CTL,
|
|
|
|
.get_optmax = ARPT_SO_GET_MAX+1,
|
|
|
|
.get = do_arpt_get_ctl,
|
2007-12-17 23:26:54 -07:00
|
|
|
#ifdef CONFIG_COMPAT
|
|
|
|
.compat_get = compat_do_arpt_get_ctl,
|
|
|
|
#endif
|
[NETFILTER]: Fix/improve deadlock condition on module removal netfilter
So I've had a deadlock reported to me. I've found that the sequence of
events goes like this:
1) process A (modprobe) runs to remove ip_tables.ko
2) process B (iptables-restore) runs and calls setsockopt on a netfilter socket,
increasing the ip_tables socket_ops use count
3) process A acquires a file lock on the file ip_tables.ko, calls remove_module
in the kernel, which in turn executes the ip_tables module cleanup routine,
which calls nf_unregister_sockopt
4) nf_unregister_sockopt, seeing that the use count is non-zero, puts the
calling process into uninterruptible sleep, expecting the process using the
socket option code to wake it up when it exits the kernel
4) the user of the socket option code (process B) in do_ipt_get_ctl, calls
ipt_find_table_lock, which in this case calls request_module to load
ip_tables_nat.ko
5) request_module forks a copy of modprobe (process C) to load the module and
blocks until modprobe exits.
6) Process C. forked by request_module process the dependencies of
ip_tables_nat.ko, of which ip_tables.ko is one.
7) Process C attempts to lock the request module and all its dependencies, it
blocks when it attempts to lock ip_tables.ko (which was previously locked in
step 3)
Theres not really any great permanent solution to this that I can see, but I've
developed a two part solution that corrects the problem
Part 1) Modifies the nf_sockopt registration code so that, instead of using a
use counter internal to the nf_sockopt_ops structure, we instead use a pointer
to the registering modules owner to do module reference counting when nf_sockopt
calls a modules set/get routine. This prevents the deadlock by preventing set 4
from happening.
Part 2) Enhances the modprobe utilty so that by default it preforms non-blocking
remove operations (the same way rmmod does), and add an option to explicity
request blocking operation. So if you select blocking operation in modprobe you
can still cause the above deadlock, but only if you explicity try (and since
root can do any old stupid thing it would like.... :) ).
Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-09-11 03:28:26 -06:00
|
|
|
.owner = THIS_MODULE,
|
2005-04-16 16:20:36 -06:00
|
|
|
};
|
|
|
|
|
2008-01-31 05:49:35 -07:00
|
|
|
static int __net_init arp_tables_net_init(struct net *net)
|
|
|
|
{
|
2008-10-08 03:35:01 -06:00
|
|
|
return xt_proto_init(net, NFPROTO_ARP);
|
2008-01-31 05:49:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void __net_exit arp_tables_net_exit(struct net *net)
|
|
|
|
{
|
2008-10-08 03:35:01 -06:00
|
|
|
xt_proto_fini(net, NFPROTO_ARP);
|
2008-01-31 05:49:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct pernet_operations arp_tables_net_ops = {
|
|
|
|
.init = arp_tables_net_init,
|
|
|
|
.exit = arp_tables_net_exit,
|
|
|
|
};
|
|
|
|
|
2006-03-28 17:37:06 -07:00
|
|
|
static int __init arp_tables_init(void)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2008-01-31 05:49:35 -07:00
|
|
|
ret = register_pernet_subsys(&arp_tables_net_ops);
|
2006-08-13 19:57:28 -06:00
|
|
|
if (ret < 0)
|
|
|
|
goto err1;
|
[NETFILTER] x_tables: Abstraction layer for {ip,ip6,arp}_tables
This monster-patch tries to do the best job for unifying the data
structures and backend interfaces for the three evil clones ip_tables,
ip6_tables and arp_tables. In an ideal world we would never have
allowed this kind of copy+paste programming... but well, our world
isn't (yet?) ideal.
o introduce a new x_tables module
o {ip,arp,ip6}_tables depend on this x_tables module
o registration functions for tables, matches and targets are only
wrappers around x_tables provided functions
o all matches/targets that are used from ip_tables and ip6_tables
are now implemented as xt_FOOBAR.c files and provide module aliases
to ipt_FOOBAR and ip6t_FOOBAR
o header files for xt_matches are in include/linux/netfilter/,
include/linux/netfilter_{ipv4,ipv6} contains compatibility wrappers
around the xt_FOOBAR.h headers
Based on this patchset we're going to further unify the code,
gradually getting rid of all the layer 3 specific assumptions.
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-01-12 14:30:04 -07:00
|
|
|
|
2011-03-30 19:57:33 -06:00
|
|
|
/* No one else will be downing sem now, so we won't sleep */
|
2009-07-04 04:50:00 -06:00
|
|
|
ret = xt_register_targets(arpt_builtin_tg, ARRAY_SIZE(arpt_builtin_tg));
|
2006-08-13 19:57:28 -06:00
|
|
|
if (ret < 0)
|
|
|
|
goto err2;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* Register setsockopt */
|
|
|
|
ret = nf_register_sockopt(&arpt_sockopts);
|
2006-08-13 19:57:28 -06:00
|
|
|
if (ret < 0)
|
|
|
|
goto err4;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
return 0;
|
2006-08-13 19:57:28 -06:00
|
|
|
|
|
|
|
err4:
|
2009-07-04 04:50:00 -06:00
|
|
|
xt_unregister_targets(arpt_builtin_tg, ARRAY_SIZE(arpt_builtin_tg));
|
2006-08-13 19:57:28 -06:00
|
|
|
err2:
|
2008-01-31 05:49:35 -07:00
|
|
|
unregister_pernet_subsys(&arp_tables_net_ops);
|
2006-08-13 19:57:28 -06:00
|
|
|
err1:
|
|
|
|
return ret;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
2006-03-28 17:37:06 -07:00
|
|
|
static void __exit arp_tables_fini(void)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
nf_unregister_sockopt(&arpt_sockopts);
|
2009-07-04 04:50:00 -06:00
|
|
|
xt_unregister_targets(arpt_builtin_tg, ARRAY_SIZE(arpt_builtin_tg));
|
2008-01-31 05:49:35 -07:00
|
|
|
unregister_pernet_subsys(&arp_tables_net_ops);
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_SYMBOL(arpt_register_table);
|
|
|
|
EXPORT_SYMBOL(arpt_unregister_table);
|
|
|
|
EXPORT_SYMBOL(arpt_do_table);
|
|
|
|
|
2006-03-28 17:37:06 -07:00
|
|
|
module_init(arp_tables_init);
|
|
|
|
module_exit(arp_tables_fini);
|