Skip to content

Commit

Permalink
netfilter: allow to turn off xtables compat layer
Browse files Browse the repository at this point in the history
The compat layer needs to parse untrusted input (the ruleset)
to translate it to a 64bit compatible format.

We had a number of bugs in this department in the past, so allow users
to turn this feature off.

Add CONFIG_NETFILTER_XTABLES_COMPAT kconfig knob and make it default to y
to keep existing behaviour.

Signed-off-by: Florian Westphal <[email protected]>
Signed-off-by: Pablo Neira Ayuso <[email protected]>
  • Loading branch information
Florian Westphal authored and ummakynes committed Apr 26, 2021
1 parent 50f2db9 commit 47a6959
Show file tree
Hide file tree
Showing 15 changed files with 70 additions and 60 deletions.
12 changes: 6 additions & 6 deletions include/linux/netfilter/x_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ struct xt_match {

/* Called when entry of this type deleted. */
void (*destroy)(const struct xt_mtdtor_param *);
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/* Called when userspace align differs from kernel space one */
void (*compat_from_user)(void *dst, const void *src);
int (*compat_to_user)(void __user *dst, const void *src);
Expand All @@ -169,7 +169,7 @@ struct xt_match {
const char *table;
unsigned int matchsize;
unsigned int usersize;
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
unsigned int compatsize;
#endif
unsigned int hooks;
Expand Down Expand Up @@ -199,7 +199,7 @@ struct xt_target {

/* Called when entry of this type deleted. */
void (*destroy)(const struct xt_tgdtor_param *);
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/* Called when userspace align differs from kernel space one */
void (*compat_from_user)(void *dst, const void *src);
int (*compat_to_user)(void __user *dst, const void *src);
Expand All @@ -210,7 +210,7 @@ struct xt_target {
const char *table;
unsigned int targetsize;
unsigned int usersize;
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
unsigned int compatsize;
#endif
unsigned int hooks;
Expand Down Expand Up @@ -452,7 +452,7 @@ xt_get_per_cpu_counter(struct xt_counters *cnt, unsigned int cpu)

struct nf_hook_ops *xt_hook_ops_alloc(const struct xt_table *, nf_hookfn *);

#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
#include <net/compat.h>

struct compat_xt_entry_match {
Expand Down Expand Up @@ -533,5 +533,5 @@ int xt_compat_check_entry_offsets(const void *base, const char *elems,
unsigned int target_offset,
unsigned int next_offset);

#endif /* CONFIG_COMPAT */
#endif /* CONFIG_NETFILTER_XTABLES_COMPAT */
#endif /* _X_TABLES_H */
2 changes: 1 addition & 1 deletion include/linux/netfilter_arp/arp_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ extern unsigned int arpt_do_table(struct sk_buff *skb,
const struct nf_hook_state *state,
struct xt_table *table);

#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
#include <net/compat.h>

struct compat_arpt_entry {
Expand Down
2 changes: 1 addition & 1 deletion include/linux/netfilter_ipv4/ip_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ extern unsigned int ipt_do_table(struct sk_buff *skb,
const struct nf_hook_state *state,
struct xt_table *table);

#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
#include <net/compat.h>

struct compat_ipt_entry {
Expand Down
2 changes: 1 addition & 1 deletion include/linux/netfilter_ipv6/ip6_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ extern unsigned int ip6t_do_table(struct sk_buff *skb,
const struct nf_hook_state *state,
struct xt_table *table);

#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
#include <net/compat.h>

struct compat_ip6t_entry {
Expand Down
4 changes: 2 additions & 2 deletions net/bridge/netfilter/ebt_limit.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ static int ebt_limit_mt_check(const struct xt_mtchk_param *par)
}


#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/*
* no conversion function needed --
* only avg/burst have meaningful values in userspace.
Expand All @@ -107,7 +107,7 @@ static struct xt_match ebt_limit_mt_reg __read_mostly = {
.checkentry = ebt_limit_mt_check,
.matchsize = sizeof(struct ebt_limit_info),
.usersize = offsetof(struct ebt_limit_info, prev),
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct ebt_compat_limit_info),
#endif
.me = THIS_MODULE,
Expand Down
4 changes: 2 additions & 2 deletions net/bridge/netfilter/ebt_mark.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ static int ebt_mark_tg_check(const struct xt_tgchk_param *par)
return -EINVAL;
return 0;
}
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ebt_mark_t_info {
compat_ulong_t mark;
compat_uint_t target;
Expand Down Expand Up @@ -87,7 +87,7 @@ static struct xt_target ebt_mark_tg_reg __read_mostly = {
.target = ebt_mark_tg,
.checkentry = ebt_mark_tg_check,
.targetsize = sizeof(struct ebt_mark_t_info),
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct compat_ebt_mark_t_info),
.compat_from_user = mark_tg_compat_from_user,
.compat_to_user = mark_tg_compat_to_user,
Expand Down
4 changes: 2 additions & 2 deletions net/bridge/netfilter/ebt_mark_m.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ static int ebt_mark_mt_check(const struct xt_mtchk_param *par)
}


#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ebt_mark_m_info {
compat_ulong_t mark, mask;
uint8_t invert, bitmask;
Expand Down Expand Up @@ -75,7 +75,7 @@ static struct xt_match ebt_mark_mt_reg __read_mostly = {
.match = ebt_mark_mt,
.checkentry = ebt_mark_mt_check,
.matchsize = sizeof(struct ebt_mark_m_info),
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct compat_ebt_mark_m_info),
.compat_from_user = mark_mt_compat_from_user,
.compat_to_user = mark_mt_compat_to_user,
Expand Down
12 changes: 6 additions & 6 deletions net/bridge/netfilter/ebtables.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ struct ebt_pernet {
static unsigned int ebt_pernet_id __read_mostly;
static DEFINE_MUTEX(ebt_mutex);

#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
static void ebt_standard_compat_from_user(void *dst, const void *src)
{
int v = *(compat_int_t *)src;
Expand All @@ -73,7 +73,7 @@ static struct xt_target ebt_standard_target = {
.revision = 0,
.family = NFPROTO_BRIDGE,
.targetsize = sizeof(int),
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(compat_int_t),
.compat_from_user = ebt_standard_compat_from_user,
.compat_to_user = ebt_standard_compat_to_user,
Expand Down Expand Up @@ -1502,7 +1502,7 @@ static int copy_everything_to_user(struct ebt_table *t, void __user *user,
ebt_entry_to_user, entries, tmp.entries);
}

#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/* 32 bit-userspace compatibility definitions. */
struct compat_ebt_replace {
char name[EBT_TABLE_MAXNAMELEN];
Expand Down Expand Up @@ -2367,7 +2367,7 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EPERM;

#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/* try real handler in case userland supplied needed padding */
if (in_compat_syscall() &&
((cmd != EBT_SO_GET_INFO && cmd != EBT_SO_GET_INIT_INFO) ||
Expand Down Expand Up @@ -2434,15 +2434,15 @@ static int do_ebt_set_ctl(struct sock *sk, int cmd, sockptr_t arg,

switch (cmd) {
case EBT_SO_SET_ENTRIES:
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
ret = compat_do_replace(net, arg, len);
else
#endif
ret = do_replace(net, arg, len);
break;
case EBT_SO_SET_COUNTERS:
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
ret = compat_update_counters(net, arg, len);
else
Expand Down
16 changes: 8 additions & 8 deletions net/ipv4/netfilter/arp_tables.c
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,7 @@ static int copy_entries_to_user(unsigned int total_size,
return ret;
}

#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
static void compat_standard_from_user(void *dst, const void *src)
{
int v = *(compat_int_t *)src;
Expand Down Expand Up @@ -800,15 +800,15 @@ static int get_info(struct net *net, void __user *user, const int *len)
return -EFAULT;

name[XT_TABLE_MAXNAMELEN-1] = '\0';
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
xt_compat_lock(NFPROTO_ARP);
#endif
t = xt_request_find_table_lock(net, NFPROTO_ARP, name);
if (!IS_ERR(t)) {
struct arpt_getinfo info;
const struct xt_table_info *private = t->private;
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct xt_table_info tmp;

if (in_compat_syscall()) {
Expand All @@ -835,7 +835,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
module_put(t->me);
} else
ret = PTR_ERR(t);
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
xt_compat_unlock(NFPROTO_ARP);
#endif
Expand Down Expand Up @@ -1044,7 +1044,7 @@ static int do_add_counters(struct net *net, sockptr_t arg, unsigned int len)
return ret;
}

#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_arpt_replace {
char name[XT_TABLE_MAXNAMELEN];
u32 valid_hooks;
Expand Down Expand Up @@ -1412,7 +1412,7 @@ static int do_arpt_set_ctl(struct sock *sk, int cmd, sockptr_t arg,

switch (cmd) {
case ARPT_SO_SET_REPLACE:
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
ret = compat_do_replace(sock_net(sk), arg, len);
else
Expand Down Expand Up @@ -1444,7 +1444,7 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
break;

case ARPT_SO_GET_ENTRIES:
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
ret = compat_get_entries(sock_net(sk), user, len);
else
Expand Down Expand Up @@ -1580,7 +1580,7 @@ static struct xt_target arpt_builtin_tg[] __read_mostly = {
.name = XT_STANDARD_TARGET,
.targetsize = sizeof(int),
.family = NFPROTO_ARP,
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(compat_int_t),
.compat_from_user = compat_standard_from_user,
.compat_to_user = compat_standard_to_user,
Expand Down
16 changes: 8 additions & 8 deletions net/ipv4/netfilter/ip_tables.c
Original file line number Diff line number Diff line change
Expand Up @@ -868,7 +868,7 @@ copy_entries_to_user(unsigned int total_size,
return ret;
}

#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
static void compat_standard_from_user(void *dst, const void *src)
{
int v = *(compat_int_t *)src;
Expand Down Expand Up @@ -957,15 +957,15 @@ static int get_info(struct net *net, void __user *user, const int *len)
return -EFAULT;

name[XT_TABLE_MAXNAMELEN-1] = '\0';
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
xt_compat_lock(AF_INET);
#endif
t = xt_request_find_table_lock(net, AF_INET, name);
if (!IS_ERR(t)) {
struct ipt_getinfo info;
const struct xt_table_info *private = t->private;
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct xt_table_info tmp;

if (in_compat_syscall()) {
Expand Down Expand Up @@ -993,7 +993,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
module_put(t->me);
} else
ret = PTR_ERR(t);
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
xt_compat_unlock(AF_INET);
#endif
Expand Down Expand Up @@ -1199,7 +1199,7 @@ do_add_counters(struct net *net, sockptr_t arg, unsigned int len)
return ret;
}

#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ipt_replace {
char name[XT_TABLE_MAXNAMELEN];
u32 valid_hooks;
Expand Down Expand Up @@ -1621,7 +1621,7 @@ do_ipt_set_ctl(struct sock *sk, int cmd, sockptr_t arg, unsigned int len)

switch (cmd) {
case IPT_SO_SET_REPLACE:
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
ret = compat_do_replace(sock_net(sk), arg, len);
else
Expand Down Expand Up @@ -1654,7 +1654,7 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
break;

case IPT_SO_GET_ENTRIES:
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
ret = compat_get_entries(sock_net(sk), user, len);
else
Expand Down Expand Up @@ -1846,7 +1846,7 @@ static struct xt_target ipt_builtin_tg[] __read_mostly = {
.name = XT_STANDARD_TARGET,
.targetsize = sizeof(int),
.family = NFPROTO_IPV4,
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(compat_int_t),
.compat_from_user = compat_standard_from_user,
.compat_to_user = compat_standard_to_user,
Expand Down
8 changes: 4 additions & 4 deletions net/ipv4/netfilter/ipt_CLUSTERIP.c
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ static void clusterip_tg_destroy(const struct xt_tgdtor_param *par)
nf_ct_netns_put(par->net, par->family);
}

#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ipt_clusterip_tgt_info
{
u_int32_t flags;
Expand All @@ -553,7 +553,7 @@ struct compat_ipt_clusterip_tgt_info
u_int32_t hash_initval;
compat_uptr_t config;
};
#endif /* CONFIG_COMPAT */
#endif /* CONFIG_NETFILTER_XTABLES_COMPAT */

static struct xt_target clusterip_tg_reg __read_mostly = {
.name = "CLUSTERIP",
Expand All @@ -563,9 +563,9 @@ static struct xt_target clusterip_tg_reg __read_mostly = {
.destroy = clusterip_tg_destroy,
.targetsize = sizeof(struct ipt_clusterip_tgt_info),
.usersize = offsetof(struct ipt_clusterip_tgt_info, config),
#ifdef CONFIG_COMPAT
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct compat_ipt_clusterip_tgt_info),
#endif /* CONFIG_COMPAT */
#endif /* CONFIG_NETFILTER_XTABLES_COMPAT */
.me = THIS_MODULE
};

Expand Down
Loading

0 comments on commit 47a6959

Please sign in to comment.