Commit 53409afd authored by David S. Miller's avatar David S. Miller

Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf

Pablo Neira Ayuso says:

====================
Netfilter fixes for net

The following patchset contains Netfilter updates for your net tree,
they are:

1) Dump only conntrack that belong to this namespace via /proc file.
   This is some fallout from the conversion to single conntrack table
   for all netns, patch from Liping Zhang.

2) Missing MODULE_ALIAS_NF_LOGGER() for the ARP family that prevents
   module autoloading, also from Liping Zhang.

3) Report overquota event to the right netnamespace, again from Liping.

4) Fix tproxy listener sk refcount that leads to crash, from
   Eric Dumazet.

5) Fix racy refcounting on object deletion from nfnetlink and rule
   removal both for nfacct and cttimeout, from Liping Zhang.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 184ca823 b75911b6
...@@ -15,6 +15,6 @@ struct nf_acct; ...@@ -15,6 +15,6 @@ struct nf_acct;
struct nf_acct *nfnl_acct_find_get(struct net *net, const char *filter_name); struct nf_acct *nfnl_acct_find_get(struct net *net, const char *filter_name);
void nfnl_acct_put(struct nf_acct *acct); void nfnl_acct_put(struct nf_acct *acct);
void nfnl_acct_update(const struct sk_buff *skb, struct nf_acct *nfacct); void nfnl_acct_update(const struct sk_buff *skb, struct nf_acct *nfacct);
extern int nfnl_acct_overquota(const struct sk_buff *skb, int nfnl_acct_overquota(struct net *net, const struct sk_buff *skb,
struct nf_acct *nfacct); struct nf_acct *nfacct);
#endif /* _NFNL_ACCT_H */ #endif /* _NFNL_ACCT_H */
...@@ -205,6 +205,7 @@ static int ct_seq_show(struct seq_file *s, void *v) ...@@ -205,6 +205,7 @@ static int ct_seq_show(struct seq_file *s, void *v)
struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash); struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash);
const struct nf_conntrack_l3proto *l3proto; const struct nf_conntrack_l3proto *l3proto;
const struct nf_conntrack_l4proto *l4proto; const struct nf_conntrack_l4proto *l4proto;
struct net *net = seq_file_net(s);
int ret = 0; int ret = 0;
NF_CT_ASSERT(ct); NF_CT_ASSERT(ct);
...@@ -215,6 +216,9 @@ static int ct_seq_show(struct seq_file *s, void *v) ...@@ -215,6 +216,9 @@ static int ct_seq_show(struct seq_file *s, void *v)
if (NF_CT_DIRECTION(hash)) if (NF_CT_DIRECTION(hash))
goto release; goto release;
if (!net_eq(nf_ct_net(ct), net))
goto release;
l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct)); l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct));
NF_CT_ASSERT(l3proto); NF_CT_ASSERT(l3proto);
l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
......
...@@ -326,14 +326,14 @@ static int nfnl_acct_try_del(struct nf_acct *cur) ...@@ -326,14 +326,14 @@ static int nfnl_acct_try_del(struct nf_acct *cur)
{ {
int ret = 0; int ret = 0;
/* we want to avoid races with nfnl_acct_find_get. */ /* We want to avoid races with nfnl_acct_put. So only when the current
if (atomic_dec_and_test(&cur->refcnt)) { * refcnt is 1, we decrease it to 0.
*/
if (atomic_cmpxchg(&cur->refcnt, 1, 0) == 1) {
/* We are protected by nfnl mutex. */ /* We are protected by nfnl mutex. */
list_del_rcu(&cur->head); list_del_rcu(&cur->head);
kfree_rcu(cur, rcu_head); kfree_rcu(cur, rcu_head);
} else { } else {
/* still in use, restore reference counter. */
atomic_inc(&cur->refcnt);
ret = -EBUSY; ret = -EBUSY;
} }
return ret; return ret;
...@@ -443,7 +443,7 @@ void nfnl_acct_update(const struct sk_buff *skb, struct nf_acct *nfacct) ...@@ -443,7 +443,7 @@ void nfnl_acct_update(const struct sk_buff *skb, struct nf_acct *nfacct)
} }
EXPORT_SYMBOL_GPL(nfnl_acct_update); EXPORT_SYMBOL_GPL(nfnl_acct_update);
static void nfnl_overquota_report(struct nf_acct *nfacct) static void nfnl_overquota_report(struct net *net, struct nf_acct *nfacct)
{ {
int ret; int ret;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -458,11 +458,12 @@ static void nfnl_overquota_report(struct nf_acct *nfacct) ...@@ -458,11 +458,12 @@ static void nfnl_overquota_report(struct nf_acct *nfacct)
kfree_skb(skb); kfree_skb(skb);
return; return;
} }
netlink_broadcast(init_net.nfnl, skb, 0, NFNLGRP_ACCT_QUOTA, netlink_broadcast(net->nfnl, skb, 0, NFNLGRP_ACCT_QUOTA,
GFP_ATOMIC); GFP_ATOMIC);
} }
int nfnl_acct_overquota(const struct sk_buff *skb, struct nf_acct *nfacct) int nfnl_acct_overquota(struct net *net, const struct sk_buff *skb,
struct nf_acct *nfacct)
{ {
u64 now; u64 now;
u64 *quota; u64 *quota;
...@@ -480,7 +481,7 @@ int nfnl_acct_overquota(const struct sk_buff *skb, struct nf_acct *nfacct) ...@@ -480,7 +481,7 @@ int nfnl_acct_overquota(const struct sk_buff *skb, struct nf_acct *nfacct)
if (now >= *quota && if (now >= *quota &&
!test_and_set_bit(NFACCT_OVERQUOTA_BIT, &nfacct->flags)) { !test_and_set_bit(NFACCT_OVERQUOTA_BIT, &nfacct->flags)) {
nfnl_overquota_report(nfacct); nfnl_overquota_report(net, nfacct);
} }
return ret; return ret;
......
...@@ -330,16 +330,16 @@ static int ctnl_timeout_try_del(struct net *net, struct ctnl_timeout *timeout) ...@@ -330,16 +330,16 @@ static int ctnl_timeout_try_del(struct net *net, struct ctnl_timeout *timeout)
{ {
int ret = 0; int ret = 0;
/* we want to avoid races with nf_ct_timeout_find_get. */ /* We want to avoid races with ctnl_timeout_put. So only when the
if (atomic_dec_and_test(&timeout->refcnt)) { * current refcnt is 1, we decrease it to 0.
*/
if (atomic_cmpxchg(&timeout->refcnt, 1, 0) == 1) {
/* We are protected by nfnl mutex. */ /* We are protected by nfnl mutex. */
list_del_rcu(&timeout->head); list_del_rcu(&timeout->head);
nf_ct_l4proto_put(timeout->l4proto); nf_ct_l4proto_put(timeout->l4proto);
ctnl_untimeout(net, timeout); ctnl_untimeout(net, timeout);
kfree_rcu(timeout, rcu_head); kfree_rcu(timeout, rcu_head);
} else { } else {
/* still in use, restore reference counter. */
atomic_inc(&timeout->refcnt);
ret = -EBUSY; ret = -EBUSY;
} }
return ret; return ret;
...@@ -543,7 +543,9 @@ ctnl_timeout_find_get(struct net *net, const char *name) ...@@ -543,7 +543,9 @@ ctnl_timeout_find_get(struct net *net, const char *name)
static void ctnl_timeout_put(struct ctnl_timeout *timeout) static void ctnl_timeout_put(struct ctnl_timeout *timeout)
{ {
atomic_dec(&timeout->refcnt); if (atomic_dec_and_test(&timeout->refcnt))
kfree_rcu(timeout, rcu_head);
module_put(THIS_MODULE); module_put(THIS_MODULE);
} }
#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
...@@ -591,6 +593,8 @@ static void __net_exit cttimeout_net_exit(struct net *net) ...@@ -591,6 +593,8 @@ static void __net_exit cttimeout_net_exit(struct net *net)
list_for_each_entry_safe(cur, tmp, &net->nfct_timeout_list, head) { list_for_each_entry_safe(cur, tmp, &net->nfct_timeout_list, head) {
list_del_rcu(&cur->head); list_del_rcu(&cur->head);
nf_ct_l4proto_put(cur->l4proto); nf_ct_l4proto_put(cur->l4proto);
if (atomic_dec_and_test(&cur->refcnt))
kfree_rcu(cur, rcu_head); kfree_rcu(cur, rcu_head);
} }
} }
......
...@@ -1147,6 +1147,7 @@ MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_ULOG); ...@@ -1147,6 +1147,7 @@ MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_ULOG);
MODULE_ALIAS_NF_LOGGER(AF_INET, 1); MODULE_ALIAS_NF_LOGGER(AF_INET, 1);
MODULE_ALIAS_NF_LOGGER(AF_INET6, 1); MODULE_ALIAS_NF_LOGGER(AF_INET6, 1);
MODULE_ALIAS_NF_LOGGER(AF_BRIDGE, 1); MODULE_ALIAS_NF_LOGGER(AF_BRIDGE, 1);
MODULE_ALIAS_NF_LOGGER(3, 1); /* NFPROTO_ARP */
module_init(nfnetlink_log_init); module_init(nfnetlink_log_init);
module_exit(nfnetlink_log_fini); module_exit(nfnetlink_log_fini);
...@@ -127,6 +127,8 @@ nf_tproxy_get_sock_v4(struct net *net, struct sk_buff *skb, void *hp, ...@@ -127,6 +127,8 @@ nf_tproxy_get_sock_v4(struct net *net, struct sk_buff *skb, void *hp,
daddr, dport, daddr, dport,
in->ifindex); in->ifindex);
if (sk && !atomic_inc_not_zero(&sk->sk_refcnt))
sk = NULL;
/* NOTE: we return listeners even if bound to /* NOTE: we return listeners even if bound to
* 0.0.0.0, those are filtered out in * 0.0.0.0, those are filtered out in
* xt_socket, since xt_TPROXY needs 0 bound * xt_socket, since xt_TPROXY needs 0 bound
...@@ -195,6 +197,8 @@ nf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff, void *hp, ...@@ -195,6 +197,8 @@ nf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff, void *hp,
daddr, ntohs(dport), daddr, ntohs(dport),
in->ifindex); in->ifindex);
if (sk && !atomic_inc_not_zero(&sk->sk_refcnt))
sk = NULL;
/* NOTE: we return listeners even if bound to /* NOTE: we return listeners even if bound to
* 0.0.0.0, those are filtered out in * 0.0.0.0, those are filtered out in
* xt_socket, since xt_TPROXY needs 0 bound * xt_socket, since xt_TPROXY needs 0 bound
......
...@@ -26,7 +26,7 @@ static bool nfacct_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -26,7 +26,7 @@ static bool nfacct_mt(const struct sk_buff *skb, struct xt_action_param *par)
nfnl_acct_update(skb, info->nfacct); nfnl_acct_update(skb, info->nfacct);
overquota = nfnl_acct_overquota(skb, info->nfacct); overquota = nfnl_acct_overquota(par->net, skb, info->nfacct);
return overquota == NFACCT_UNDERQUOTA ? false : true; return overquota == NFACCT_UNDERQUOTA ? false : true;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment