Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Pablo Neira Ayuso says: ==================== Netfilter fixes for net The following patchset contain Netfilter fixes for your net tree, they are: 1) Fix a race in nfnetlink_log and nfnetlink_queue that can lead to a crash. This problem is due to wrong order in the per-net registration and netlink socket events. Patch from Francesco Ruggeri. 2) Make sure that counters that userspace pass us are higher than 0 in all the x_tables frontends. Discovered via Trinity, patch from Dave Jones. 3) Revert a patch for br_netfilter to rely on the conntrack status bits. This breaks stateless IPv6 NAT transformations. Patch from Florian Westphal. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Коммит
572152adfb
|
@ -176,6 +176,7 @@ struct nf_bridge_info {
|
|||
struct net_device *physindev;
|
||||
struct net_device *physoutdev;
|
||||
char neigh_header[8];
|
||||
__be32 ipv4_daddr;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
|
|
@ -37,10 +37,6 @@
|
|||
#include <net/route.h>
|
||||
#include <net/netfilter/br_netfilter.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_NF_CONNTRACK)
|
||||
#include <net/netfilter/nf_conntrack.h>
|
||||
#endif
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include "br_private.h"
|
||||
#ifdef CONFIG_SYSCTL
|
||||
|
@ -350,24 +346,15 @@ free_skb:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool dnat_took_place(const struct sk_buff *skb)
|
||||
static bool daddr_was_changed(const struct sk_buff *skb,
|
||||
const struct nf_bridge_info *nf_bridge)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_NF_CONNTRACK)
|
||||
enum ip_conntrack_info ctinfo;
|
||||
struct nf_conn *ct;
|
||||
|
||||
ct = nf_ct_get(skb, &ctinfo);
|
||||
if (!ct || nf_ct_is_untracked(ct))
|
||||
return false;
|
||||
|
||||
return test_bit(IPS_DST_NAT_BIT, &ct->status);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
return ip_hdr(skb)->daddr != nf_bridge->ipv4_daddr;
|
||||
}
|
||||
|
||||
/* This requires some explaining. If DNAT has taken place,
|
||||
* we will need to fix up the destination Ethernet address.
|
||||
* This is also true when SNAT takes place (for the reply direction).
|
||||
*
|
||||
* There are two cases to consider:
|
||||
* 1. The packet was DNAT'ed to a device in the same bridge
|
||||
|
@ -421,7 +408,7 @@ static int br_nf_pre_routing_finish(struct sock *sk, struct sk_buff *skb)
|
|||
nf_bridge->pkt_otherhost = false;
|
||||
}
|
||||
nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
|
||||
if (dnat_took_place(skb)) {
|
||||
if (daddr_was_changed(skb, nf_bridge)) {
|
||||
if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) {
|
||||
struct in_device *in_dev = __in_dev_get_rcu(dev);
|
||||
|
||||
|
@ -632,6 +619,7 @@ static unsigned int br_nf_pre_routing(const struct nf_hook_ops *ops,
|
|||
struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
{
|
||||
struct nf_bridge_info *nf_bridge;
|
||||
struct net_bridge_port *p;
|
||||
struct net_bridge *br;
|
||||
__u32 len = nf_bridge_encap_header_len(skb);
|
||||
|
@ -669,6 +657,9 @@ static unsigned int br_nf_pre_routing(const struct nf_hook_ops *ops,
|
|||
if (!setup_pre_routing(skb))
|
||||
return NF_DROP;
|
||||
|
||||
nf_bridge = nf_bridge_info_get(skb);
|
||||
nf_bridge->ipv4_daddr = ip_hdr(skb)->daddr;
|
||||
|
||||
skb->protocol = htons(ETH_P_IP);
|
||||
|
||||
NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, state->sk, skb,
|
||||
|
|
|
@ -1117,6 +1117,8 @@ static int do_replace(struct net *net, const void __user *user,
|
|||
return -ENOMEM;
|
||||
if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
|
||||
return -ENOMEM;
|
||||
if (tmp.num_counters == 0)
|
||||
return -EINVAL;
|
||||
|
||||
tmp.name[sizeof(tmp.name) - 1] = 0;
|
||||
|
||||
|
@ -2159,6 +2161,8 @@ static int compat_copy_ebt_replace_from_user(struct ebt_replace *repl,
|
|||
return -ENOMEM;
|
||||
if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
|
||||
return -ENOMEM;
|
||||
if (tmp.num_counters == 0)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(repl, &tmp, offsetof(struct ebt_replace, hook_entry));
|
||||
|
||||
|
|
|
@ -1075,6 +1075,9 @@ static int do_replace(struct net *net, const void __user *user,
|
|||
/* overflow check */
|
||||
if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
|
||||
return -ENOMEM;
|
||||
if (tmp.num_counters == 0)
|
||||
return -EINVAL;
|
||||
|
||||
tmp.name[sizeof(tmp.name)-1] = 0;
|
||||
|
||||
newinfo = xt_alloc_table_info(tmp.size);
|
||||
|
@ -1499,6 +1502,9 @@ static int compat_do_replace(struct net *net, void __user *user,
|
|||
return -ENOMEM;
|
||||
if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
|
||||
return -ENOMEM;
|
||||
if (tmp.num_counters == 0)
|
||||
return -EINVAL;
|
||||
|
||||
tmp.name[sizeof(tmp.name)-1] = 0;
|
||||
|
||||
newinfo = xt_alloc_table_info(tmp.size);
|
||||
|
|
|
@ -1262,6 +1262,9 @@ do_replace(struct net *net, const void __user *user, unsigned int len)
|
|||
/* overflow check */
|
||||
if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
|
||||
return -ENOMEM;
|
||||
if (tmp.num_counters == 0)
|
||||
return -EINVAL;
|
||||
|
||||
tmp.name[sizeof(tmp.name)-1] = 0;
|
||||
|
||||
newinfo = xt_alloc_table_info(tmp.size);
|
||||
|
@ -1809,6 +1812,9 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len)
|
|||
return -ENOMEM;
|
||||
if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
|
||||
return -ENOMEM;
|
||||
if (tmp.num_counters == 0)
|
||||
return -EINVAL;
|
||||
|
||||
tmp.name[sizeof(tmp.name)-1] = 0;
|
||||
|
||||
newinfo = xt_alloc_table_info(tmp.size);
|
||||
|
|
|
@ -1275,6 +1275,9 @@ do_replace(struct net *net, const void __user *user, unsigned int len)
|
|||
/* overflow check */
|
||||
if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
|
||||
return -ENOMEM;
|
||||
if (tmp.num_counters == 0)
|
||||
return -EINVAL;
|
||||
|
||||
tmp.name[sizeof(tmp.name)-1] = 0;
|
||||
|
||||
newinfo = xt_alloc_table_info(tmp.size);
|
||||
|
@ -1822,6 +1825,9 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len)
|
|||
return -ENOMEM;
|
||||
if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
|
||||
return -ENOMEM;
|
||||
if (tmp.num_counters == 0)
|
||||
return -EINVAL;
|
||||
|
||||
tmp.name[sizeof(tmp.name)-1] = 0;
|
||||
|
||||
newinfo = xt_alloc_table_info(tmp.size);
|
||||
|
|
|
@ -1073,7 +1073,13 @@ static struct pernet_operations nfnl_log_net_ops = {
|
|||
|
||||
static int __init nfnetlink_log_init(void)
|
||||
{
|
||||
int status = -ENOMEM;
|
||||
int status;
|
||||
|
||||
status = register_pernet_subsys(&nfnl_log_net_ops);
|
||||
if (status < 0) {
|
||||
pr_err("failed to register pernet ops\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
netlink_register_notifier(&nfulnl_rtnl_notifier);
|
||||
status = nfnetlink_subsys_register(&nfulnl_subsys);
|
||||
|
@ -1088,28 +1094,23 @@ static int __init nfnetlink_log_init(void)
|
|||
goto cleanup_subsys;
|
||||
}
|
||||
|
||||
status = register_pernet_subsys(&nfnl_log_net_ops);
|
||||
if (status < 0) {
|
||||
pr_err("failed to register pernet ops\n");
|
||||
goto cleanup_logger;
|
||||
}
|
||||
return status;
|
||||
|
||||
cleanup_logger:
|
||||
nf_log_unregister(&nfulnl_logger);
|
||||
cleanup_subsys:
|
||||
nfnetlink_subsys_unregister(&nfulnl_subsys);
|
||||
cleanup_netlink_notifier:
|
||||
netlink_unregister_notifier(&nfulnl_rtnl_notifier);
|
||||
unregister_pernet_subsys(&nfnl_log_net_ops);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
static void __exit nfnetlink_log_fini(void)
|
||||
{
|
||||
unregister_pernet_subsys(&nfnl_log_net_ops);
|
||||
nf_log_unregister(&nfulnl_logger);
|
||||
nfnetlink_subsys_unregister(&nfulnl_subsys);
|
||||
netlink_unregister_notifier(&nfulnl_rtnl_notifier);
|
||||
unregister_pernet_subsys(&nfnl_log_net_ops);
|
||||
}
|
||||
|
||||
MODULE_DESCRIPTION("netfilter userspace logging");
|
||||
|
|
|
@ -1317,7 +1317,13 @@ static struct pernet_operations nfnl_queue_net_ops = {
|
|||
|
||||
static int __init nfnetlink_queue_init(void)
|
||||
{
|
||||
int status = -ENOMEM;
|
||||
int status;
|
||||
|
||||
status = register_pernet_subsys(&nfnl_queue_net_ops);
|
||||
if (status < 0) {
|
||||
pr_err("nf_queue: failed to register pernet ops\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
netlink_register_notifier(&nfqnl_rtnl_notifier);
|
||||
status = nfnetlink_subsys_register(&nfqnl_subsys);
|
||||
|
@ -1326,19 +1332,13 @@ static int __init nfnetlink_queue_init(void)
|
|||
goto cleanup_netlink_notifier;
|
||||
}
|
||||
|
||||
status = register_pernet_subsys(&nfnl_queue_net_ops);
|
||||
if (status < 0) {
|
||||
pr_err("nf_queue: failed to register pernet ops\n");
|
||||
goto cleanup_subsys;
|
||||
}
|
||||
register_netdevice_notifier(&nfqnl_dev_notifier);
|
||||
nf_register_queue_handler(&nfqh);
|
||||
return status;
|
||||
|
||||
cleanup_subsys:
|
||||
nfnetlink_subsys_unregister(&nfqnl_subsys);
|
||||
cleanup_netlink_notifier:
|
||||
netlink_unregister_notifier(&nfqnl_rtnl_notifier);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -1346,9 +1346,9 @@ static void __exit nfnetlink_queue_fini(void)
|
|||
{
|
||||
nf_unregister_queue_handler();
|
||||
unregister_netdevice_notifier(&nfqnl_dev_notifier);
|
||||
unregister_pernet_subsys(&nfnl_queue_net_ops);
|
||||
nfnetlink_subsys_unregister(&nfqnl_subsys);
|
||||
netlink_unregister_notifier(&nfqnl_rtnl_notifier);
|
||||
unregister_pernet_subsys(&nfnl_queue_net_ops);
|
||||
|
||||
rcu_barrier(); /* Wait for completion of call_rcu()'s */
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче