Re: [PATCH] netfilter: fix clusterip_net_exit build regression

2017-12-07 Thread Vasily Averin
thank you,
it was mu fault.

Reviewed-by: Vasily Averin <v...@virtuozzo.com>

On 2017-12-07 16:26, Arnd Bergmann wrote:
> The added check produces a build error when CONFIG_PROC_FS is
> disabled:
> 
> net/ipv4/netfilter/ipt_CLUSTERIP.c: In function 'clusterip_net_exit':
> net/ipv4/netfilter/ipt_CLUSTERIP.c:822:28: error: 'cn' undeclared (first use 
> in this function)
> 
> This moves the variable declaration out of the #ifdef to make it
> available to the WARN_ON_ONCE().
> 
> Fixes: 613d0776d3fe ("netfilter: exit_net cleanup check added")
> Signed-off-by: Arnd Bergmann <a...@arndb.de>
> ---
>  net/ipv4/netfilter/ipt_CLUSTERIP.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c 
> b/net/ipv4/netfilter/ipt_CLUSTERIP.c
> index e35b8d074f06..69060e3abe85 100644
> --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
> +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
> @@ -813,8 +813,8 @@ static int clusterip_net_init(struct net *net)
>  
>  static void clusterip_net_exit(struct net *net)
>  {
> -#ifdef CONFIG_PROC_FS
>   struct clusterip_net *cn = net_generic(net, clusterip_net_id);
> +#ifdef CONFIG_PROC_FS
>   proc_remove(cn->procdir);
>   cn->procdir = NULL;
>  #endif
> 


Re: [PATCH v5 00/13] exit_net checks for objects initialized in net_init hook

2017-11-14 Thread Vasily Averin
On 2017-11-14 09:47, David Miller wrote:
> From: Vasily Averin <v...@virtuozzo.com>
> Date: Sun, 12 Nov 2017 22:26:44 +0300
> 
>> OpenVz kernel team have a long history of fighting against namespace-related 
>> bugs,
>> some of them could be prevented by using simple checks described below.
>>
>> One of typical errors is related to live cycle of namespaces:
>> usually objects created for some namespace should not live longer than 
>> namespace itself.
> 
> All applied to net-next except patch #9 and #10 which need to go via the
> NFS maintainer.

As far as I see Anna included them into Anna's linux-nfs work git.

Thank you!
Vasily Averin


[PATCH v5 13/13] xfrm6_tunnel: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that spi_byaddr and spi_byspi arrays initialized in net_init hook
were return to initial state

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/ipv6/xfrm6_tunnel.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index 4e438bc..f85f0d7 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -338,6 +338,14 @@ static int __net_init xfrm6_tunnel_net_init(struct net 
*net)
 
 static void __net_exit xfrm6_tunnel_net_exit(struct net *net)
 {
+   struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
+   unsigned int i;
+
+   for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++)
+   WARN_ON_ONCE(!hlist_empty(_tn->spi_byaddr[i]));
+
+   for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++)
+   WARN_ON_ONCE(!hlist_empty(_tn->spi_byspi[i]));
 }
 
 static struct pernet_operations xfrm6_tunnel_net_ops = {
-- 
2.7.4



[PATCH v5 12/13] ppp: exit_net cleanup checks added

2017-11-12 Thread Vasily Averin
Be sure that lists initialized in net_init hook were return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 drivers/net/ppp/ppp_generic.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index e365866..30744ce 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -960,6 +960,8 @@ static __net_exit void ppp_exit_net(struct net *net)
rtnl_unlock();
 
idr_destroy(>units_idr);
+   WARN_ON_ONCE(!list_empty(>all_channels));
+   WARN_ON_ONCE(!list_empty(>new_channels));
 }
 
 static struct pernet_operations ppp_net_ops = {
-- 
2.7.4



[PATCH v5 11/13] phonet: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that pndevs.list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/phonet/pn_dev.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index 2cb4c5d..7778751 100644
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@ -331,7 +331,10 @@ static int __net_init phonet_init_net(struct net *net)
 
 static void __net_exit phonet_exit_net(struct net *net)
 {
+   struct phonet_net *pnn = phonet_pernet(net);
+
remove_proc_entry("phonet", net->proc_net);
+   WARN_ON_ONCE(!list_empty(>pndevs.list));
 }
 
 static struct pernet_operations phonet_net_ops = {
-- 
2.7.4



[PATCH v5 10/13] sunrpc: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that all_clients list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/sunrpc/sunrpc_syms.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index c73de18..56f9eff 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -65,10 +65,13 @@ static __net_init int sunrpc_init_net(struct net *net)
 
 static __net_exit void sunrpc_exit_net(struct net *net)
 {
+   struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
rpc_pipefs_exit_net(net);
unix_gid_cache_destroy(net);
ip_map_cache_destroy(net);
rpc_proc_exit(net);
+   WARN_ON_ONCE(!list_empty(>all_clients));
 }
 
 static struct pernet_operations sunrpc_net_ops = {
-- 
2.7.4



[PATCH v5 09/13] nfs client: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that nfs_client_list and nfs_volume_list lists initialized
in net_init hook were return to initial state in net_exit hook.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 fs/nfs/inode.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 134d9f5..4ef515f 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -2084,8 +2084,12 @@ static int nfs_net_init(struct net *net)
 
 static void nfs_net_exit(struct net *net)
 {
+   struct nfs_net *nn = net_generic(net, nfs_net_id);
+
nfs_fs_proc_net_exit(net);
nfs_cleanup_cb_ident_idr(net);
+   WARN_ON_ONCE(!list_empty(>nfs_client_list));
+   WARN_ON_ONCE(!list_empty(>nfs_volume_list));
 }
 
 static struct pernet_operations nfs_net_ops = {
-- 
2.7.4



[PATCH v5 07/13] fib_rules: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that rules_ops list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/core/fib_rules.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 9a6d97c..c029192 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -1019,8 +1019,14 @@ static int __net_init fib_rules_net_init(struct net *net)
return 0;
 }
 
+static void __net_exit fib_rules_net_exit(struct net *net)
+{
+   WARN_ON_ONCE(!list_empty(>rules_ops));
+}
+
 static struct pernet_operations fib_rules_net_ops = {
.init = fib_rules_net_init,
+   .exit = fib_rules_net_exit,
 };
 
 static int __init fib_rules_init(void)
-- 
2.7.4



[PATCH v5 08/13] l2tp: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that l2tp_session_hlist array initialized in net_init hook
was return to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/l2tp/l2tp_core.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 02d6110..fabc404 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1888,6 +1888,7 @@ static __net_exit void l2tp_exit_net(struct net *net)
 {
struct l2tp_net *pn = l2tp_pernet(net);
struct l2tp_tunnel *tunnel = NULL;
+   int hash;
 
rcu_read_lock_bh();
list_for_each_entry_rcu(tunnel, >l2tp_tunnel_list, list) {
@@ -1897,6 +1898,9 @@ static __net_exit void l2tp_exit_net(struct net *net)
 
flush_workqueue(l2tp_wq);
rcu_barrier();
+
+   for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++)
+   WARN_ON_ONCE(!hlist_empty(>l2tp_session_hlist[hash]));
 }
 
 static struct pernet_operations l2tp_net_ops = {
-- 
2.7.4



[PATCH v5 06/13] fib_notifier: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that fib_notifier_ops list initilized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/core/fib_notifier.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/net/core/fib_notifier.c b/net/core/fib_notifier.c
index 4fc202d..6b8cd49 100644
--- a/net/core/fib_notifier.c
+++ b/net/core/fib_notifier.c
@@ -161,8 +161,14 @@ static int __net_init fib_notifier_net_init(struct net 
*net)
return 0;
 }
 
+static void __net_exit fib_notifier_net_exit(struct net *net)
+{
+   WARN_ON_ONCE(!list_empty(>fib_notifier_ops));
+}
+
 static struct pernet_operations fib_notifier_net_ops = {
.init = fib_notifier_net_init,
+   .exit = fib_notifier_net_exit,
 };
 
 static int __init fib_notifier_init(void)
-- 
2.7.4



[PATCH v5 05/13] netdev: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that dev_base_head list initialized in net_init hook was return
to initial state

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/core/dev.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/net/core/dev.c b/net/core/dev.c
index 588b473..56fece7 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -8562,6 +8562,8 @@ static void __net_exit netdev_exit(struct net *net)
 {
kfree(net->dev_name_head);
kfree(net->dev_index_head);
+   if (net != _net)
+   WARN_ON_ONCE(!list_empty(>dev_base_head));
 }
 
 static struct pernet_operations __net_initdata netdev_net_ops = {
-- 
2.7.4



[PATCH v5 04/13] vxlan: exit_net cleanup checks added

2017-11-12 Thread Vasily Averin
Be sure that sock_list array initialized in net_init hook was return
to initial state

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 drivers/net/vxlan.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index d7c49cf..c02d856 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -3704,6 +3704,7 @@ static void __net_exit vxlan_exit_net(struct net *net)
struct vxlan_net *vn = net_generic(net, vxlan_net_id);
struct vxlan_dev *vxlan, *next;
struct net_device *dev, *aux;
+   unsigned int h;
LIST_HEAD(list);
 
rtnl_lock();
@@ -3723,6 +3724,9 @@ static void __net_exit vxlan_exit_net(struct net *net)
 
unregister_netdevice_many();
rtnl_unlock();
+
+   for (h = 0; h < PORT_HASH_SIZE; ++h)
+   WARN_ON_ONCE(!hlist_empty(>sock_list[h]));
 }
 
 static struct pernet_operations vxlan_net_ops = {
-- 
2.7.4



[PATCH v5 03/13] packet: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that packet.sklist initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/packet/af_packet.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index bec01a3..4b58c4a 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -4562,6 +4562,7 @@ static int __net_init packet_net_init(struct net *net)
 static void __net_exit packet_net_exit(struct net *net)
 {
remove_proc_entry("packet", net->proc_net);
+   WARN_ON_ONCE(!hlist_empty(>packet.sklist));
 }
 
 static struct pernet_operations packet_net_ops = {
-- 
2.7.4



[PATCH v5 02/13] geneve: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that sock_list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 drivers/net/geneve.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index f640407..6bc5721 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -1673,6 +1673,7 @@ static void __net_exit geneve_exit_net(struct net *net)
/* unregister the devices gathered above */
unregister_netdevice_many();
rtnl_unlock();
+   WARN_ON_ONCE(!list_empty(>sock_list));
 }
 
 static struct pernet_operations geneve_net_ops = {
-- 
2.7.4



[PATCH v5 01/13] af_key: replace BUG_ON on WARN_ON in net_exit hook

2017-11-12 Thread Vasily Averin
Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/key/af_key.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/key/af_key.c b/net/key/af_key.c
index a00d607..3dffb89 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -3845,7 +3845,7 @@ static void __net_exit pfkey_net_exit(struct net *net)
struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
 
pfkey_exit_proc(net);
-   BUG_ON(!hlist_empty(_pfkey->table));
+   WARN_ON(!hlist_empty(_pfkey->table));
 }
 
 static struct pernet_operations pfkey_net_ops = {
-- 
2.7.4



[PATCH v5 00/13] exit_net checks for objects initialized in net_init hook

2017-11-12 Thread Vasily Averin
OpenVz kernel team have a long history of fighting against namespace-related 
bugs,
some of them could be prevented by using simple checks described below.

One of typical errors is related to live cycle of namespaces:
usually objects created for some namespace should not live longer than 
namespace itself.

Such kind of issues can be invisible on usual systems where additional 
namespaces
are not used, because initial namespaces usually lives forever and never 
destroyed.

However in systems with namespaces it can lead to memory leaks or to 
use-after-free.
Both of them are critical for systems with running containers.
As you knows it's quite hard to find the reason of such issues,
especially in rarely-triggered scenarios on production nodes on default kernels
without specially enabled debug settings. Any additional hints can be useful 
here.

This patch set should help to detect some of these issues.
It is based on assumption that objects initialized in init hook of 
pernet_operations
should return to initial state until end of exit hook.

Many drivers and subsystems already have such checks, however I've found number
of places where list_empty check would be useful at least as smoke test.

These checks are useful for long-term stable kernels,
they allows to detect problems related to incomplete or incorrectly
backported patches.

Changes:
v5:
- fixed nit pointed by Florian Westphal
- netfilter patches are send separately to netfilter-devel@

v4:
- excluded grace and lockd patches taken by Bruce Fields
- let's use WARN_ON_ONCE without any extra messages
   adobriyan@ is right, output of net Id gives nothing to host admin,
   and developers in any case will extract information from core dump
- updated description in cover letter
- dropped nfs4blocklayout patch: waitqueue check does not look useful
- patches was reordered to be per-subsystem grouped
- cover letter should be sent to all people included into cc: of any patches
- minor cosmetic changes in some patches

v3:
- use net->ns.inum as net Id
- removed patches for hashlimit and recent,
they handle tables list in exit_net hook.
- added patches for grace and lockd

v2:
- net pointer removed from output
- fixed compilation for phonet driver


Vasily Averin (13):
  af_key: replace BUG_ON on WARN_ON in net_exit hook
  geneve: exit_net cleanup check added
  packet: exit_net cleanup check added
  vxlan: exit_net cleanup checks added
  netdev: exit_net cleanup check added
  fib_notifier: exit_net cleanup check added
  fib_rules: exit_net cleanup check added
  l2tp: exit_net cleanup check added
  nfs client: exit_net cleanup check added
  sunrpc: exit_net cleanup check added
  phonet: exit_net cleanup check added
  ppp: exit_net cleanup checks added
  xfrm6_tunnel: exit_net cleanup check added

 drivers/net/geneve.c  | 1 +
 drivers/net/ppp/ppp_generic.c | 2 ++
 drivers/net/vxlan.c   | 4 
 fs/nfs/inode.c| 4 
 net/core/dev.c| 2 ++
 net/core/fib_notifier.c   | 6 ++
 net/core/fib_rules.c  | 6 ++
 net/ipv6/xfrm6_tunnel.c   | 8 
 net/key/af_key.c  | 2 +-
 net/l2tp/l2tp_core.c  | 4 
 net/packet/af_packet.c| 1 +
 net/phonet/pn_dev.c   | 3 +++
 net/sunrpc/sunrpc_syms.c  | 3 +++
 13 files changed, 45 insertions(+), 1 deletion(-)

-- 
2.7.4



Re: [PATCH v4 00/18] exit_net checks for objects initialized in net_init hook

2017-11-12 Thread Vasily Averin
On 2017-11-12 11:39, Vasily Averin wrote:
>   clusterip: exit_net cleanup check added
>   nf_tables: exit_net cleanup check added
>   nfnetlink_log: exit_net cleanup check added
>   nfnetlink_gueue: exit_net cleanup check added
>   x_tables: exit_net cleanup check added

netfilter-related patches was sent separately to netfilter-devel@ mailing list


Re: [PATCH v3 20/21] phonet: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
On 2017-11-06 22:37, Rémi Denis-Courmont wrote:
> In my opinon, tis is still utterly pointless. Really, what bug did this 
> specific patch help to fix?

I'm maintainer of legacy OpenVz kernels, we release containers-ready kernels 
15+ years,
they are widely used by hosting providers, usually they use 30-300 containers 
per node.
In this scenario if any of container causes the problem it affects many other.

For many years we got lot of strange memory corruptions and found lot of memory 
leaks
in namespace-fied subsytems.

These bugs are invisible on usual kernls, because init_net lives forever and 
never destroyed.
However they are quite important for systems running lott of independent 
namespaces,
that can be restarted many times without host admin assistance.
Each memory leak can be repeated many times and finally it enables OOM-killer 
that disables whole node. And nobody understand what's happen.

Such kind of checks allows to be sure that net namespace exit was clear and 
leaked nothing.

> If you want to debug network namespaces, I have a feeling that the network 
> namespace code is a better place to do so than individual protocol stacks.

Common network namespace code knows nothing about specific of each individual 
driver/subsystem.
I do not understand how it's possible to do it in common netns code.

Thank you,
    Vasily Averin


Re: [PATCH v4 12/18] nfnetlink_gueue: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
On 2017-11-12 11:52, Florian Westphal wrote:
> Vasily Averin <v...@virtuozzo.com> wrote:
>> Be sure that instance_table array initialized in net_init hook
>> was return to initial state.
> 
>> +for (i = 0; i < INSTANCE_BUCKETS; i++)
>> +if (WARN_ON_ONCE(!hlist_empty(>instance_table[i])))
>> +break;
> 
> This looks strange, why if/break?

I did not want to generate huge number of messages on each non-empty hash 
bucket.

> Plain WARN_ON_ONCE should be enough, but thats a nit so:

Oh, you're right.
In first patch version WARN_ON  was used here.
I've missed that only first message will be printed with _ONCE check.

> Acked-by: Florian Westphal <f...@strlen.de>
> 


[PATCH v4 18/18] xfrm6_tunnel: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that spi_byaddr and spi_byspi arrays initialized in net_init hook
were return to initial state

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/ipv6/xfrm6_tunnel.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index 4e438bc..09ec069 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -338,6 +338,16 @@ static int __net_init xfrm6_tunnel_net_init(struct net 
*net)
 
 static void __net_exit xfrm6_tunnel_net_exit(struct net *net)
 {
+   struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
+   unsigned int i;
+
+   for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++)
+   if (WARN_ON_ONCE(!hlist_empty(_tn->spi_byaddr[i])))
+   break;
+
+   for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++)
+   if (WARN_ON_ONCE(!hlist_empty(_tn->spi_byspi[i])))
+   break;
 }
 
 static struct pernet_operations xfrm6_tunnel_net_ops = {
-- 
2.7.4



[PATCH v4 17/18] ppp: exit_net cleanup checks added

2017-11-12 Thread Vasily Averin
Be sure that lists initialized in net_init hook were return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 drivers/net/ppp/ppp_generic.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index e365866..30744ce 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -960,6 +960,8 @@ static __net_exit void ppp_exit_net(struct net *net)
rtnl_unlock();
 
idr_destroy(>units_idr);
+   WARN_ON_ONCE(!list_empty(>all_channels));
+   WARN_ON_ONCE(!list_empty(>new_channels));
 }
 
 static struct pernet_operations ppp_net_ops = {
-- 
2.7.4



[PATCH v4 16/18] phonet: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that pndevs.list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/phonet/pn_dev.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index 2cb4c5d..7778751 100644
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@ -331,7 +331,10 @@ static int __net_init phonet_init_net(struct net *net)
 
 static void __net_exit phonet_exit_net(struct net *net)
 {
+   struct phonet_net *pnn = phonet_pernet(net);
+
remove_proc_entry("phonet", net->proc_net);
+   WARN_ON_ONCE(!list_empty(>pndevs.list));
 }
 
 static struct pernet_operations phonet_net_ops = {
-- 
2.7.4



[PATCH v4 15/18] sunrpc: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that all_clients list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/sunrpc/sunrpc_syms.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index c73de18..56f9eff 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -65,10 +65,13 @@ static __net_init int sunrpc_init_net(struct net *net)
 
 static __net_exit void sunrpc_exit_net(struct net *net)
 {
+   struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
rpc_pipefs_exit_net(net);
unix_gid_cache_destroy(net);
ip_map_cache_destroy(net);
rpc_proc_exit(net);
+   WARN_ON_ONCE(!list_empty(>all_clients));
 }
 
 static struct pernet_operations sunrpc_net_ops = {
-- 
2.7.4



[PATCH v4 14/18] nfs client: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that nfs_client_list and nfs_volume_list lists initialized
in net_init hook were return to initial state in net_exit hook.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 fs/nfs/inode.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 134d9f5..4ef515f 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -2084,8 +2084,12 @@ static int nfs_net_init(struct net *net)
 
 static void nfs_net_exit(struct net *net)
 {
+   struct nfs_net *nn = net_generic(net, nfs_net_id);
+
nfs_fs_proc_net_exit(net);
nfs_cleanup_cb_ident_idr(net);
+   WARN_ON_ONCE(!list_empty(>nfs_client_list));
+   WARN_ON_ONCE(!list_empty(>nfs_volume_list));
 }
 
 static struct pernet_operations nfs_net_ops = {
-- 
2.7.4



[PATCH v4 13/18] x_tables: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that xt.tables array initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/netfilter/x_tables.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index d8571f4..119b670 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1714,8 +1714,18 @@ static int __net_init xt_net_init(struct net *net)
return 0;
 }
 
+static void __net_exit xt_net_exit(struct net *net)
+{
+   int i;
+
+   for (i = 0; i < NFPROTO_NUMPROTO; i++)
+   if (WARN_ON_ONCE(!list_empty(>xt.tables[i])))
+   break;
+}
+
 static struct pernet_operations xt_net_ops = {
.init = xt_net_init,
+   .exit = xt_net_exit,
 };
 
 static int __init xt_init(void)
-- 
2.7.4



[PATCH v4 12/18] nfnetlink_gueue: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that instance_table array initialized in net_init hook
was return to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/netfilter/nfnetlink_queue.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index c979662..fd41077 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -1512,10 +1512,16 @@ static int __net_init nfnl_queue_net_init(struct net 
*net)
 
 static void __net_exit nfnl_queue_net_exit(struct net *net)
 {
+   unsigned int i;
+   struct nfnl_queue_net *q = nfnl_queue_pernet(net);
+
nf_unregister_queue_handler(net);
 #ifdef CONFIG_PROC_FS
remove_proc_entry("nfnetlink_queue", net->nf.proc_netfilter);
 #endif
+   for (i = 0; i < INSTANCE_BUCKETS; i++)
+   if (WARN_ON_ONCE(!hlist_empty(>instance_table[i])))
+   break;
 }
 
 static void nfnl_queue_net_exit_batch(struct list_head *net_exit_list)
-- 
2.7.4



[PATCH v4 11/18] nfnetlink_log: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that instance_table array initialized in net_init hook
was return to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/netfilter/nfnetlink_log.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index cad6498..80236a2 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -1093,10 +1093,15 @@ static int __net_init nfnl_log_net_init(struct net *net)
 
 static void __net_exit nfnl_log_net_exit(struct net *net)
 {
+   unsigned int i;
+   struct nfnl_log_net *log = nfnl_log_pernet(net);
 #ifdef CONFIG_PROC_FS
remove_proc_entry("nfnetlink_log", net->nf.proc_netfilter);
 #endif
nf_log_unset(net, _logger);
+   for (i = 0; i < INSTANCE_BUCKETS; i++)
+   if (WARN_ON_ONCE(!hlist_empty(>instance_table[i])))
+   break;
 }
 
 static struct pernet_operations nfnl_log_net_ops = {
-- 
2.7.4



[PATCH v4 10/18] nf_tables: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that lists initialized in net_init hook were return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/netfilter/nf_tables_api.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 64e1ee0..f432b53 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -5778,6 +5778,12 @@ static int __net_init nf_tables_init_net(struct net *net)
return 0;
 }
 
+static void __net_exit nf_tables_exit_net(struct net *net)
+{
+   WARN_ON_ONCE(!list_empty(>nft.af_info));
+   WARN_ON_ONCE(!list_empty(>nft.commit_list));
+}
+
 int __nft_release_basechain(struct nft_ctx *ctx)
 {
struct nft_rule *rule, *nr;
@@ -5848,6 +5854,7 @@ static void __nft_release_afinfo(struct net *net, struct 
nft_af_info *afi)
 
 static struct pernet_operations nf_tables_net_ops = {
.init   = nf_tables_init_net,
+   .exit   = nf_tables_exit_net,
 };
 
 static int __init nf_tables_module_init(void)
-- 
2.7.4



[PATCH v4 09/18] clusterip: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that configs list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/ipv4/netfilter/ipt_CLUSTERIP.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c 
b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 17b4ca5..e35b8d0 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -819,6 +819,7 @@ static void clusterip_net_exit(struct net *net)
cn->procdir = NULL;
 #endif
nf_unregister_net_hook(net, _arp_ops);
+   WARN_ON_ONCE(!list_empty(>configs));
 }
 
 static struct pernet_operations clusterip_net_ops = {
-- 
2.7.4



[PATCH v4 07/18] fib_rules: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that rules_ops list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/core/fib_rules.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 9a6d97c..c029192 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -1019,8 +1019,14 @@ static int __net_init fib_rules_net_init(struct net *net)
return 0;
 }
 
+static void __net_exit fib_rules_net_exit(struct net *net)
+{
+   WARN_ON_ONCE(!list_empty(>rules_ops));
+}
+
 static struct pernet_operations fib_rules_net_ops = {
.init = fib_rules_net_init,
+   .exit = fib_rules_net_exit,
 };
 
 static int __init fib_rules_init(void)
-- 
2.7.4



[PATCH v4 08/18] l2tp: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that l2tp_session_hlist array initialized in net_init hook
was return to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/l2tp/l2tp_core.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 02d6110..eed1e21 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1888,6 +1888,7 @@ static __net_exit void l2tp_exit_net(struct net *net)
 {
struct l2tp_net *pn = l2tp_pernet(net);
struct l2tp_tunnel *tunnel = NULL;
+   int hash;
 
rcu_read_lock_bh();
list_for_each_entry_rcu(tunnel, >l2tp_tunnel_list, list) {
@@ -1897,6 +1898,10 @@ static __net_exit void l2tp_exit_net(struct net *net)
 
flush_workqueue(l2tp_wq);
rcu_barrier();
+
+   for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++)
+   if (WARN_ON_ONCE(!hlist_empty(>l2tp_session_hlist[hash])))
+   break;
 }
 
 static struct pernet_operations l2tp_net_ops = {
-- 
2.7.4



[PATCH v4 06/18] fib_notifier: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that fib_notifier_ops list initilized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/core/fib_notifier.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/net/core/fib_notifier.c b/net/core/fib_notifier.c
index 4fc202d..6b8cd49 100644
--- a/net/core/fib_notifier.c
+++ b/net/core/fib_notifier.c
@@ -161,8 +161,14 @@ static int __net_init fib_notifier_net_init(struct net 
*net)
return 0;
 }
 
+static void __net_exit fib_notifier_net_exit(struct net *net)
+{
+   WARN_ON_ONCE(!list_empty(>fib_notifier_ops));
+}
+
 static struct pernet_operations fib_notifier_net_ops = {
.init = fib_notifier_net_init,
+   .exit = fib_notifier_net_exit,
 };
 
 static int __init fib_notifier_init(void)
-- 
2.7.4



[PATCH v4 05/18] netdev: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that dev_base_head list initialized in net_init hook was return
to initial state

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/core/dev.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/net/core/dev.c b/net/core/dev.c
index 588b473..56fece7 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -8562,6 +8562,8 @@ static void __net_exit netdev_exit(struct net *net)
 {
kfree(net->dev_name_head);
kfree(net->dev_index_head);
+   if (net != _net)
+   WARN_ON_ONCE(!list_empty(>dev_base_head));
 }
 
 static struct pernet_operations __net_initdata netdev_net_ops = {
-- 
2.7.4



[PATCH v4 04/18] vxlan: exit_net cleanup checks added

2017-11-12 Thread Vasily Averin
Be sure that sock_list array initialized in net_init hook was return
to initial state

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 drivers/net/vxlan.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index d7c49cf..766a41b 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -3704,6 +3704,7 @@ static void __net_exit vxlan_exit_net(struct net *net)
struct vxlan_net *vn = net_generic(net, vxlan_net_id);
struct vxlan_dev *vxlan, *next;
struct net_device *dev, *aux;
+   unsigned int h;
LIST_HEAD(list);
 
rtnl_lock();
@@ -3723,6 +3724,10 @@ static void __net_exit vxlan_exit_net(struct net *net)
 
unregister_netdevice_many();
rtnl_unlock();
+
+   for (h = 0; h < PORT_HASH_SIZE; ++h)
+   if (WARN_ON_ONCE(!hlist_empty(>sock_list[h])))
+   break;
 }
 
 static struct pernet_operations vxlan_net_ops = {
-- 
2.7.4



[PATCH v4 03/18] packet: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that packet.sklist initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/packet/af_packet.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index bec01a3..4b58c4a 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -4562,6 +4562,7 @@ static int __net_init packet_net_init(struct net *net)
 static void __net_exit packet_net_exit(struct net *net)
 {
remove_proc_entry("packet", net->proc_net);
+   WARN_ON_ONCE(!hlist_empty(>packet.sklist));
 }
 
 static struct pernet_operations packet_net_ops = {
-- 
2.7.4



[PATCH v4 01/18] af_key: replace BUG_ON on WARN_ON in net_exit hook

2017-11-12 Thread Vasily Averin
Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/key/af_key.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/key/af_key.c b/net/key/af_key.c
index a00d607..3dffb89 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -3845,7 +3845,7 @@ static void __net_exit pfkey_net_exit(struct net *net)
struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
 
pfkey_exit_proc(net);
-   BUG_ON(!hlist_empty(_pfkey->table));
+   WARN_ON(!hlist_empty(_pfkey->table));
 }
 
 static struct pernet_operations pfkey_net_ops = {
-- 
2.7.4



[PATCH v4 02/18] geneve: exit_net cleanup check added

2017-11-12 Thread Vasily Averin
Be sure that sock_list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 drivers/net/geneve.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index f640407..6bc5721 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -1673,6 +1673,7 @@ static void __net_exit geneve_exit_net(struct net *net)
/* unregister the devices gathered above */
unregister_netdevice_many();
rtnl_unlock();
+   WARN_ON_ONCE(!list_empty(>sock_list));
 }
 
 static struct pernet_operations geneve_net_ops = {
-- 
2.7.4



[PATCH v4 00/18] exit_net checks for objects initialized in net_init hook

2017-11-12 Thread Vasily Averin
OpenVz kernel team have a long history of fighting against namespace-related 
bugs,
some of them could be excluded by using simple checks described below.

One of typical errors is related to live cycle of namespaces:
usually objects created for some namespace should not live longer than 
namespace itself.

Such kind of issues can be invisible on usual systems where additional 
namespaces
are not used, because initial namespaces usually lives forever and never 
destroyed.

However in systems with namespaces it can lead to memory leaks or to 
use-after-free.
Both of them are critical for systems with running containers.
As you knows it's quite hard to find the reason of such issues,
especially in rarely-triggered scenarios on production nodes on default kernels
without specially enabled debug settings. Any additional hints can be useful 
here.

This patch set should help to detect some of these issues.
It is based on assumption that objects initialized in init hook of 
pernet_operations
should return to initial state until end of exit hook.

Many drivers and subsystems already have such checks, however I've found number
of places where list_empty check would be useful at least as smoke test.

These checks are useful for long-term stable kernels,
they allows to detect problems related to incomplete or incorrectly
backported patches.

Also this patch set replaces BUG_ON in existing checks:
memory leaks and possible memory corruptions are bad of course,
however in many cases they are not fatal 
and should not crash production hosts unconditionally.

Changes:
v4:
- excluded grace and lockd patches taken by Bruce Fields
- let's use WARN_ON_ONCE without any extra messages
   adobriyan@ is right, output of net Id gives nothing to host admin,
   and developers in any case will extract information from core dump
- updated description in cover letter
- dropped nfs4blocklayout patch: waitqueue check does not look useful
- patches was reordered to be per-subsystem grouped
- cover letter should be sent to all people included into cc: of any patches
- minor cosmetic changes in some patches

v3:
- use net->ns.inum as net Id
- removed patches for hashlimit and recent,
they handle tables list in exit_net hook.
- added patches for grace and lockd

v2:
- net pointer removed from output
- fixed compilation for phonet driver


Vasily Averin (18):
  af_key: replace BUG_ON on WARN_ON in net_exit hook
  geneve: exit_net cleanup check added
  packet: exit_net cleanup check added
  vxlan: exit_net cleanup checks added
  netdev: exit_net cleanup check added
  fib_notifier: exit_net cleanup check added
  fib_rules: exit_net cleanup check added
  l2tp: exit_net cleanup check added
  clusterip: exit_net cleanup check added
  nf_tables: exit_net cleanup check added
  nfnetlink_log: exit_net cleanup check added
  nfnetlink_gueue: exit_net cleanup check added
  x_tables: exit_net cleanup check added
  nfs client: exit_net cleanup check added
  sunrpc: exit_net cleanup check added
  phonet: exit_net cleanup check added
  ppp: exit_net cleanup checks added
  xfrm6_tunnel: exit_net cleanup check added

 drivers/net/geneve.c   |  1 +
 drivers/net/ppp/ppp_generic.c  |  2 ++
 drivers/net/vxlan.c|  5 +
 fs/nfs/inode.c |  4 
 net/core/dev.c |  2 ++
 net/core/fib_notifier.c|  6 ++
 net/core/fib_rules.c   |  6 ++
 net/ipv4/netfilter/ipt_CLUSTERIP.c |  1 +
 net/ipv6/xfrm6_tunnel.c| 10 ++
 net/key/af_key.c   |  2 +-
 net/l2tp/l2tp_core.c   |  5 +
 net/netfilter/nf_tables_api.c  |  7 +++
 net/netfilter/nfnetlink_log.c  |  5 +
 net/netfilter/nfnetlink_queue.c|  6 ++
 net/netfilter/x_tables.c   | 10 ++
 net/packet/af_packet.c |  1 +
 net/phonet/pn_dev.c|  3 +++
 net/sunrpc/sunrpc_syms.c   |  3 +++
 18 files changed, 78 insertions(+), 1 deletion(-)

-- 
2.7.4



Re: [PATCH 21/21] sunrpc: exit_net cleanup check added

2017-11-07 Thread Vasily Averin
On 2017-11-08 04:22, Stephen Hemminger wrote:
> On Sun, 5 Nov 2017 13:02:44 +0300
> Vasily Averin <v...@virtuozzo.com> wrote:
>> +WARN(!list_empty(>all_clients),
>> + "net %p exit: sunrpc all_clients list is not empty\n", net);
> 
> Don't print a kernel pointer, this is a security leak.

Yes, you're right, I've submitted fixed patch in v3 already,
but seems will prepare v4 with simple  WARN_ON_ONCE(!list_empty())


[PATCH v3 20/21] phonet: exit_net cleanup check added

2017-11-06 Thread Vasily Averin
Be sure that pndevs.list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/phonet/pn_dev.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index 2cb4c5d..f0ab85d 100644
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@ -331,7 +331,12 @@ static int __net_init phonet_init_net(struct net *net)
 
 static void __net_exit phonet_exit_net(struct net *net)
 {
+   struct phonet_net *pnn = phonet_pernet(net);
+
remove_proc_entry("phonet", net->proc_net);
+   WARN_ONCE(!list_empty(>pndevs.list),
+ "net %x %s: pndevs.list is not empty\n",
+ net->ns.inum, __func__);
 }
 
 static struct pernet_operations phonet_net_ops = {
-- 
2.7.4



[PATCH v3 21/21] sunrpc: exit_net cleanup check added

2017-11-06 Thread Vasily Averin
Be sure that all_clients list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/sunrpc/sunrpc_syms.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index c73de18..3ee6d8e 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -65,10 +65,15 @@ static __net_init int sunrpc_init_net(struct net *net)
 
 static __net_exit void sunrpc_exit_net(struct net *net)
 {
+   struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
rpc_pipefs_exit_net(net);
unix_gid_cache_destroy(net);
ip_map_cache_destroy(net);
rpc_proc_exit(net);
+   WARN_ONCE(!list_empty(>all_clients),
+ "net %x %s: all_clients list is not empty\n",
+ net->ns.inum, __func__);
 }
 
 static struct pernet_operations sunrpc_net_ops = {
-- 
2.7.4



[PATCH v3 17/21] nfnetlink_gueue: exit_net cleanup check added

2017-11-06 Thread Vasily Averin
Be sure that instance_table array initialized in net_init hook
was return to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/netfilter/nfnetlink_queue.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index c979662..139d2b5 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -1512,10 +1512,18 @@ static int __net_init nfnl_queue_net_init(struct net 
*net)
 
 static void __net_exit nfnl_queue_net_exit(struct net *net)
 {
+   unsigned int i;
+   struct nfnl_queue_net *q = nfnl_queue_pernet(net);
+
nf_unregister_queue_handler(net);
 #ifdef CONFIG_PROC_FS
remove_proc_entry("nfnetlink_queue", net->nf.proc_netfilter);
 #endif
+   for (i = 0; i < INSTANCE_BUCKETS; i++)
+   if (WARN_ONCE(!hlist_empty(>instance_table[i]),
+ "net %x %s: instance_table isn't empty\n",
+ net->ns.inum, __func__))
+   break;
 }
 
 static void nfnl_queue_net_exit_batch(struct list_head *net_exit_list)
-- 
2.7.4



[PATCH v3 19/21] packet: exit_net cleanup check added

2017-11-06 Thread Vasily Averin
Be sure that packet.sklist initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/packet/af_packet.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index bec01a3..cdd4ce6 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -4562,6 +4562,8 @@ static int __net_init packet_net_init(struct net *net)
 static void __net_exit packet_net_exit(struct net *net)
 {
remove_proc_entry("packet", net->proc_net);
+   WARN_ONCE(!hlist_empty(>packet.sklist),
+ "net %x %s: sklist is not empty\n", net->ns.inum, __func__);
 }
 
 static struct pernet_operations packet_net_ops = {
-- 
2.7.4



[PATCH v3 18/21] x_tables: exit_net cleanup check added

2017-11-06 Thread Vasily Averin
Be sure that xt.tables array initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/netfilter/x_tables.c | 12 
 1 file changed, 12 insertions(+)

diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index d8571f4..dcdaf96 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1714,8 +1714,20 @@ static int __net_init xt_net_init(struct net *net)
return 0;
 }
 
+static void __net_exit xt_net_exit(struct net *net)
+{
+   int i;
+
+   for (i = 0; i < NFPROTO_NUMPROTO; i++)
+   if (WARN_ONCE(!list_empty(>xt.tables[i]),
+ "net %x %s: tables list is not empty\n",
+ net->ns.inum. __func__)
+   break;
+}
+
 static struct pernet_operations xt_net_ops = {
.init = xt_net_init,
+   .exit = xt_net_exit,
 };
 
 static int __init xt_init(void)
-- 
2.7.4



[PATCH v3 16/21] nfnetlink_log: exit_net cleanup check added

2017-11-06 Thread Vasily Averin
Be sure that instance_table array initialized in net_init hook
was return to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/netfilter/nfnetlink_log.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index cad6498..85bc47a 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -1093,10 +1093,17 @@ static int __net_init nfnl_log_net_init(struct net *net)
 
 static void __net_exit nfnl_log_net_exit(struct net *net)
 {
+   unsigned int i;
+   struct nfnl_log_net *log = nfnl_log_pernet(net);
 #ifdef CONFIG_PROC_FS
remove_proc_entry("nfnetlink_log", net->nf.proc_netfilter);
 #endif
nf_log_unset(net, _logger);
+   for (i = 0; i < INSTANCE_BUCKETS; i++)
+   if (WARN_ONCE(!hlist_empty(>instance_table[i]),
+ "net %x %s: instance_table is not empty\n",
+ net->ns.inum, __func__))
+   break;
 }
 
 static struct pernet_operations nfnl_log_net_ops = {
-- 
2.7.4



[PATCH v3 15/21] nf_tables: exit_net cleanup check added

2017-11-06 Thread Vasily Averin
Be sure that lists initialized in net_init hook were return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/netfilter/nf_tables_api.c | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 64e1ee0..3b7f518 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -5778,6 +5778,16 @@ static int __net_init nf_tables_init_net(struct net *net)
return 0;
 }
 
+static void __net_exit nf_tables_exit_net(struct net *net)
+{
+   WARN_ONCE(!list_empty(>nft.af_info),
+ "net %x %s: af_info list is not empty\n",
+ net->ns.inum, __func__);
+   WARN_ONCE(!list_empty(>nft.commit_list),
+ "net %x %s: commit_list is not empty\n",
+ net->ns.inum, __func__);
+}
+
 int __nft_release_basechain(struct nft_ctx *ctx)
 {
struct nft_rule *rule, *nr;
@@ -5848,6 +5858,7 @@ static void __nft_release_afinfo(struct net *net, struct 
nft_af_info *afi)
 
 static struct pernet_operations nf_tables_net_ops = {
.init   = nf_tables_init_net,
+   .exit   = nf_tables_exit_net,
 };
 
 static int __init nf_tables_module_init(void)
-- 
2.7.4



[PATCH v3 12/21] xfrm6_tunnel: exit_net cleanup check added

2017-11-06 Thread Vasily Averin
Be sure that spi_byaddr and spi_byspi arrays initialized in net_init hook
were return to initial state

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/ipv6/xfrm6_tunnel.c | 14 ++
 1 file changed, 14 insertions(+)

diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index 4e438bc..5ac3c90 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -338,6 +338,20 @@ static int __net_init xfrm6_tunnel_net_init(struct net 
*net)
 
 static void __net_exit xfrm6_tunnel_net_exit(struct net *net)
 {
+   struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
+   unsigned int i;
+
+   for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++)
+   if (WARN_ONCE(!hlist_empty(_tn->spi_byaddr[i]),
+ "net %x %s: spi_byaddr is not empty\n",
+ net->ns.inum, __func__))
+   break;
+
+   for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++)
+   if (WARN_ONCE(!hlist_empty(_tn->spi_byspi[i]),
+ "net %x %s: spi_byspi is not empty\n",
+ net->ns.inum, __func__))
+   break;
 }
 
 static struct pernet_operations xfrm6_tunnel_net_ops = {
-- 
2.7.4



[PATCH v3 13/21] af_key: replace BUG_ON on WARN_ONCE in net_exit hook

2017-11-06 Thread Vasily Averin
Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/key/af_key.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/net/key/af_key.c b/net/key/af_key.c
index a00d607..61d1b58 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -3845,7 +3845,9 @@ static void __net_exit pfkey_net_exit(struct net *net)
struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
 
pfkey_exit_proc(net);
-   BUG_ON(!hlist_empty(_pfkey->table));
+   WARN_ONCE(!hlist_empty(_pfkey->table),
+ "net %x %s table hlist is not empty\n",
+ net->ns.inum, __func__);
 }
 
 static struct pernet_operations pfkey_net_ops = {
-- 
2.7.4



[PATCH v3 11/21] clusterip: exit_net cleanup check added

2017-11-06 Thread Vasily Averin
Be sure that configs list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/ipv4/netfilter/ipt_CLUSTERIP.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c 
b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 17b4ca5..4364a88 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -819,6 +819,9 @@ static void clusterip_net_exit(struct net *net)
cn->procdir = NULL;
 #endif
nf_unregister_net_hook(net, _arp_ops);
+   WARN_ONCE(!list_empty(>configs),
+ "net %x %s: configs list is not empty\n",
+ net->ns.inum, __func__);
 }
 
 static struct pernet_operations clusterip_net_ops = {
-- 
2.7.4



[PATCH v3 14/21] l2tp: exit_net cleanup check added

2017-11-06 Thread Vasily Averin
Be sure that l2tp_session_hlist array initialized in net_init hook
was return to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/l2tp/l2tp_core.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 02d6110..249a2ed 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1888,6 +1888,7 @@ static __net_exit void l2tp_exit_net(struct net *net)
 {
struct l2tp_net *pn = l2tp_pernet(net);
struct l2tp_tunnel *tunnel = NULL;
+   int hash;
 
rcu_read_lock_bh();
list_for_each_entry_rcu(tunnel, >l2tp_tunnel_list, list) {
@@ -1897,6 +1898,12 @@ static __net_exit void l2tp_exit_net(struct net *net)
 
flush_workqueue(l2tp_wq);
rcu_barrier();
+
+   for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++)
+   if (WARN_ONCE(!hlist_empty(>l2tp_session_hlist[hash]),
+ "net %x %s: session_hlist is not empty\n",
+ net->ns.inum, __func__))
+   break;
 }
 
 static struct pernet_operations l2tp_net_ops = {
-- 
2.7.4



[PATCH v3 10/21] fib_rules: exit_net cleanup check added

2017-11-06 Thread Vasily Averin
Be sure that rules_ops list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/core/fib_rules.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 9a6d97c..0049272 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -1019,8 +1019,16 @@ static int __net_init fib_rules_net_init(struct net *net)
return 0;
 }
 
+static void __net_exit fib_rules_net_exit(struct net *net)
+{
+   WARN_ONCE(!list_empty(>rules_ops),
+ "net %x %s: rules_ops list is not empty\n",
+ net->ns.inum, __func__);
+}
+
 static struct pernet_operations fib_rules_net_ops = {
.init = fib_rules_net_init,
+   .exit = fib_rules_net_exit,
 };
 
 static int __init fib_rules_init(void)
-- 
2.7.4



[PATCH v3 07/21] nfs4blocklayout: exit_net cleanup check added

2017-11-06 Thread Vasily Averin
Be sure that bl_wq wait queue initialized in net_init hook
is not used anymore.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 fs/nfs/blocklayout/rpc_pipefs.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/fs/nfs/blocklayout/rpc_pipefs.c b/fs/nfs/blocklayout/rpc_pipefs.c
index 9fb067a6..8c3941b 100644
--- a/fs/nfs/blocklayout/rpc_pipefs.c
+++ b/fs/nfs/blocklayout/rpc_pipefs.c
@@ -256,6 +256,9 @@ static void nfs4blocklayout_net_exit(struct net *net)
nfs4blocklayout_unregister_net(net, nn->bl_device_pipe);
rpc_destroy_pipe_data(nn->bl_device_pipe);
nn->bl_device_pipe = NULL;
+   WARN_ONCE(!list_empty(>bl_wq.head),
+ "net %x %s: bl_wq head is not empty\n",
+ net->ns.inum, __func__);
 }
 
 static struct pernet_operations nfs4blocklayout_net_ops = {
-- 
2.7.4



[PATCH v3 09/21] fib_notifier: exit_net cleanup check added

2017-11-06 Thread Vasily Averin
Be sure that fib_notifier_ops list initilized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/core/fib_notifier.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/net/core/fib_notifier.c b/net/core/fib_notifier.c
index 4fc202d..57aec96 100644
--- a/net/core/fib_notifier.c
+++ b/net/core/fib_notifier.c
@@ -161,8 +161,16 @@ static int __net_init fib_notifier_net_init(struct net 
*net)
return 0;
 }
 
+static void __net_exit fib_notifier_net_exit(struct net *net)
+{
+   WARN_ONCE(!list_empty(>fib_notifier_ops),
+ "net %x %s: fib_notifier_ops list is not empty\n",
+ net->ns.inum, __func__);
+}
+
 static struct pernet_operations fib_notifier_net_ops = {
.init = fib_notifier_net_init,
+   .exit = fib_notifier_net_exit,
 };
 
 static int __init fib_notifier_init(void)
-- 
2.7.4



[PATCH v3 08/21] nfs client: exit_net cleanup check added

2017-11-06 Thread Vasily Averin
Be sure that nfs_client_list and nfs_volume_list lists initialized
in net_init hook were return to initial state in net_exit hook.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 fs/nfs/client.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 22880ef..3966c98 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -204,6 +204,10 @@ void nfs_cleanup_cb_ident_idr(struct net *net)
struct nfs_net *nn = net_generic(net, nfs_net_id);
 
idr_destroy(>cb_ident_idr);
+   WARN_ONCE(!list_empty(>nfs_client_list),
+ "net %x exit: nfs_client_list is not empty\n", net->ns.inum);
+   WARN_ONCE(!list_empty(>nfs_volume_list),
+ "net %x exit: nfs_volume_list is not empty\n", net->ns.inum);
 }
 
 /* nfs_client_lock held */
-- 
2.7.4



[PATCH v3 06/21] netdev: exit_net cleanup check added

2017-11-06 Thread Vasily Averin
Be sure that dev_base_head list initialized in net_init hook was return
to initial state

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/core/dev.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/net/core/dev.c b/net/core/dev.c
index 588b473..34f88fc 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -8562,6 +8562,10 @@ static void __net_exit netdev_exit(struct net *net)
 {
kfree(net->dev_name_head);
kfree(net->dev_index_head);
+   if (net != _net)
+   WARN_ONCE(!list_empty(>dev_base_head),
+ "net %x %s: dev_base_head is not empty\n",
+ net->ns.inum, __func__);
 }
 
 static struct pernet_operations __net_initdata netdev_net_ops = {
-- 
2.7.4



[PATCH v3 05/21] vxlan: exit_net cleanup checks added

2017-11-06 Thread Vasily Averin
Be sure that sock_list array initialized in net_init hook was return
to initial state

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 drivers/net/vxlan.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index d7c49cf..acf5763 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -3704,6 +3704,7 @@ static void __net_exit vxlan_exit_net(struct net *net)
struct vxlan_net *vn = net_generic(net, vxlan_net_id);
struct vxlan_dev *vxlan, *next;
struct net_device *dev, *aux;
+   unsigned int h;
LIST_HEAD(list);
 
rtnl_lock();
@@ -3723,6 +3724,12 @@ static void __net_exit vxlan_exit_net(struct net *net)
 
unregister_netdevice_many();
rtnl_unlock();
+
+   for (h = 0; h < PORT_HASH_SIZE; ++h)
+   if (WARN_ONCE(!hlist_empty(>sock_list[h]),
+ "net %x %s: sock_list is not empty\n",
+ net->ns.inum, __func__))
+   break;
 }
 
 static struct pernet_operations vxlan_net_ops = {
-- 
2.7.4



[PATCH v3 04/21] ppp: exit_net cleanup checks added

2017-11-06 Thread Vasily Averin
Be sure that lists initialized in net_init hook were return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 drivers/net/ppp/ppp_generic.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index e365866..c0861d1 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -960,6 +960,12 @@ static __net_exit void ppp_exit_net(struct net *net)
rtnl_unlock();
 
idr_destroy(>units_idr);
+   WARN_ONCE(!list_empty(>all_channels),
+ "net %x %s: all_channels list is not empty\n",
+ net->ns.inum, __func__);
+   WARN_ONCE(!list_empty(>new_channels),
+ "net %x %s: new_channels list is not empty\n",
+ net->ns.inum, __func__);
 }
 
 static struct pernet_operations ppp_net_ops = {
-- 
2.7.4



[PATCH v3 03/21] exit_net cleanup: geneve sock_list check

2017-11-06 Thread Vasily Averin
Be sure that sock_list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 drivers/net/geneve.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index f640407..4e3a344 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -1673,6 +1673,9 @@ static void __net_exit geneve_exit_net(struct net *net)
/* unregister the devices gathered above */
unregister_netdevice_many();
rtnl_unlock();
+   WARN_ONCE(!list_empty(>sock_list),
+ "net %x : sock_list is not empty\n",
+ net->ns.inum, __func__);
 }
 
 static struct pernet_operations geneve_net_ops = {
-- 
2.7.4



[PATCH v3 02/21] lockd: added cleanup checks in exit_net hook

2017-11-06 Thread Vasily Averin
Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 fs/lockd/svc.c | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 809cbcc..2a48558 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -690,6 +690,17 @@ static int lockd_init_net(struct net *net)
 
 static void lockd_exit_net(struct net *net)
 {
+   struct lockd_net *ln = net_generic(net, lockd_net_id);
+
+   WARN_ONCE(!list_empty(>lockd_manager.list),
+ "net %x %s: lockd_manager.list is not empty\n",
+ net->ns.inum, __func__);
+   WARN_ONCE(!list_empty(>nsm_handles),
+ "net %x %s: nsm_handles list is not empty\n",
+ net->ns.inum, __func__);
+   WARN_ONCE(delayed_work_pending(>grace_period_end),
+ "net %x %s: grace_period_end was not cancelled\n",
+ net->ns.inum, __func__);
 }
 
 static struct pernet_operations lockd_net_ops = {
-- 
2.7.4



[PATCH v3 01/21] grace: replace BUG_ON by WARN_ONCE in exit_net hook

2017-11-06 Thread Vasily Averin
Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 fs/nfs_common/grace.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/fs/nfs_common/grace.c b/fs/nfs_common/grace.c
index 420d3a0..1bd6599 100644
--- a/fs/nfs_common/grace.c
+++ b/fs/nfs_common/grace.c
@@ -104,7 +104,9 @@ grace_exit_net(struct net *net)
 {
struct list_head *grace_list = net_generic(net, grace_net_id);
 
-   BUG_ON(!list_empty(grace_list));
+   WARN_ONCE(!list_empty(grace_list),
+ "net %x %s: grace_list is not empty\n",
+ net->ns.inum, __func__);
 }
 
 static struct pernet_operations grace_net_ops = {
-- 
2.7.4



[PATCH v3 00/21] exit_net checks for objects initialized in net_init hook

2017-11-06 Thread Vasily Averin
This patch set checks that lists initialized in net_init hooks were
return to initial state at end of net_exit hooks.

I hope such checks allows to detect leaked per-netns objects.
Also I hope that all new pernet_operations will inherit such checks too.

I assume that elements added into per-net lists should not live longer than net 
namespace,
and should be deleted from the list. I think exit_net hook is good place for 
such check.

Recently I've found lost list_entry and enabled timer on stop of net namespace.
Then I've reviewed all existing pernet_operations and found that many drivers
have such checks already. So I decided to complete this task and add such checks
into all affected subsystems.

v3:
- use net->ns.inum as net Id
- removed patches for hashlimit and recent,
they handle tables list in exit_net hook.
- added patches for grace and lockd

v2:
- net pointer removed from output
- fixed compilation for phonet driver

Vasily Averin (21):
  grace: replace BUG_ON by WARN_ONCE in exit_net hook
  lockd: added cleanup checks in exit_net hook
  exit_net cleanup: geneve sock_list check
  ppp: exit_net cleanup checks added
  vxlan: exit_net cleanup checks added
  netdev: exit_net cleanup check added
  nfs4blocklayout: exit_net cleanup check added
  nfs client: exit_net cleanup check added
  fib_notifier: exit_net cleanup check added
  fib_rules: exit_net cleanup check added
  clusterip: exit_net cleanup check added
  xfrm6_tunnel: exit_net cleanup check added
  af_key: replace BUG_ON on WARN_ONCE in net_exit hook
  l2tp: exit_net cleanup check added
  nf_tables: exit_net cleanup check added
  nfnetlink_log: exit_net cleanup check added
  nfnetlink_gueue: exit_net cleanup check added
  x_tables: exit_net cleanup check added
  packet: exit_net cleanup check added
  phonet: exit_net cleanup check added
  sunrpc: exit_net cleanup check added

 drivers/net/geneve.c   |  3 +++
 drivers/net/ppp/ppp_generic.c  |  6 ++
 drivers/net/vxlan.c|  7 +++
 fs/lockd/svc.c | 11 +++
 fs/nfs/blocklayout/rpc_pipefs.c|  3 +++
 fs/nfs/client.c|  4 
 fs/nfs_common/grace.c  |  4 +++-
 net/core/dev.c |  4 
 net/core/fib_notifier.c|  8 
 net/core/fib_rules.c   |  8 
 net/ipv4/netfilter/ipt_CLUSTERIP.c |  3 +++
 net/ipv6/xfrm6_tunnel.c| 14 ++
 net/key/af_key.c   |  4 +++-
 net/l2tp/l2tp_core.c   |  7 +++
 net/netfilter/nf_tables_api.c  | 11 +++
 net/netfilter/nfnetlink_log.c  |  7 +++
 net/netfilter/nfnetlink_queue.c|  8 
 net/netfilter/x_tables.c   | 12 
 net/packet/af_packet.c |  2 ++
 net/phonet/pn_dev.c|  5 +
 net/sunrpc/sunrpc_syms.c   |  5 +
 21 files changed, 134 insertions(+), 2 deletions(-)

-- 
2.7.4



How to identify net namespace in kernel messages?

2017-11-05 Thread Vasily Averin
On 2017-11-05 15:48, David Miller wrote:
> From: Vasily Averin <v...@virtuozzo.com>
>> I doubt that pointer to freed net have value for someone except
>> developers, on the other hand it helps to speed up the problem
>> investigation.
> 
> Any kernel pointer printed has value to attackers.

David, could you please advise how to identify net namespace in kernel messages?

In OpenVz we got many requests from host admins, they need to understand
which container triggered the message. In such cases we have added our custom
Container Id, but mainline lacks it.

I expected that mainline can use net pointer for such purposes,
nfsd does it for example:

 NFSD: starting 90-second grace period (net 880e307fe240)

Now you recommend do not use net pointer.
However could you please advise some alternative?


[PATCH v2 21/21] sunrpc: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that all_clients list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/sunrpc/sunrpc_syms.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index c73de18..4a25658 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -65,10 +65,14 @@ static __net_init int sunrpc_init_net(struct net *net)
 
 static __net_exit void sunrpc_exit_net(struct net *net)
 {
+   struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
rpc_pipefs_exit_net(net);
unix_gid_cache_destroy(net);
ip_map_cache_destroy(net);
rpc_proc_exit(net);
+   WARN(!list_empty(>all_clients),
+"%s: all_clients list is not empty\n", __func__);
 }
 
 static struct pernet_operations sunrpc_net_ops = {
-- 
2.7.4



[PATCH v2 20/21] phonet: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that pndevs.list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/phonet/pn_dev.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index 2cb4c5d..81b4eb0 100644
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@ -331,7 +331,11 @@ static int __net_init phonet_init_net(struct net *net)
 
 static void __net_exit phonet_exit_net(struct net *net)
 {
+   struct phonet_net *pnn = phonet_pernet(net);
+
remove_proc_entry("phonet", net->proc_net);
+   WARN(!list_empty(>pndevs.list),
+"%s: pndevs.list is not empty\n", __func__);
 }
 
 static struct pernet_operations phonet_net_ops = {
-- 
2.7.4



[PATCH v2 19/21] packet: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that packet.sklist initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/packet/af_packet.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index bec01a3..7ceb97c 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -4562,6 +4562,8 @@ static int __net_init packet_net_init(struct net *net)
 static void __net_exit packet_net_exit(struct net *net)
 {
remove_proc_entry("packet", net->proc_net);
+   WARN(!hlist_empty(>packet.sklist),
+"%s: sklist is not empty\n", __func__);
 }
 
 static struct pernet_operations packet_net_ops = {
-- 
2.7.4



[PATCH v2 18/21] recent: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that tables list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/netfilter/xt_recent.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c
index 245fa35..230d00f 100644
--- a/net/netfilter/xt_recent.c
+++ b/net/netfilter/xt_recent.c
@@ -681,7 +681,11 @@ static int __net_init recent_net_init(struct net *net)
 
 static void __net_exit recent_net_exit(struct net *net)
 {
+   struct recent_net *recent_net = recent_pernet(net);
+
recent_proc_net_exit(net);
+   WARN(!list_empty(_net->tables),
+"%s: tables list is not empty\n", __func__);
 }
 
 static struct pernet_operations recent_net_ops = {
-- 
2.7.4



[PATCH v2 17/21] hashlimit: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that htables array initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/netfilter/xt_hashlimit.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index 5da8746..abef6b4 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -1338,7 +1338,11 @@ static int __net_init hashlimit_net_init(struct net *net)
 
 static void __net_exit hashlimit_net_exit(struct net *net)
 {
+   struct hashlimit_net *hashlimit_net = hashlimit_pernet(net);
+
hashlimit_proc_net_exit(net);
+   WARN(!hlist_empty(_net->htables),
+"%s: htables hlist is not empty\n", __func__);
 }
 
 static struct pernet_operations hashlimit_net_ops = {
-- 
2.7.4



[PATCH v2 16/21] x_tables: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that xt.tables array initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/netfilter/x_tables.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index d8571f4..8125363 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1714,8 +1714,18 @@ static int __net_init xt_net_init(struct net *net)
return 0;
 }
 
+static void __net_exit xt_net_exit(struct net *net)
+{
+   int i;
+
+   for (i = 0; i < NFPROTO_NUMPROTO; i++)
+   WARN(!list_empty(>xt.tables[i]),
+"%s: tables list is not empty\n", __func__);
+}
+
 static struct pernet_operations xt_net_ops = {
.init = xt_net_init,
+   .exit = xt_net_exit,
 };
 
 static int __init xt_init(void)
-- 
2.7.4



[PATCH v2 14/21] nfnetlink_log: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that instance_table array initialized in net_init hook
was return to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/netfilter/nfnetlink_log.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index cad6498..c99f427 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -1093,10 +1093,16 @@ static int __net_init nfnl_log_net_init(struct net *net)
 
 static void __net_exit nfnl_log_net_exit(struct net *net)
 {
+   unsigned int i;
+   struct nfnl_log_net *log = nfnl_log_pernet(net);
 #ifdef CONFIG_PROC_FS
remove_proc_entry("nfnetlink_log", net->nf.proc_netfilter);
 #endif
nf_log_unset(net, _logger);
+   for (i = 0; i < INSTANCE_BUCKETS; i++)
+   if (WARN(!hlist_empty(>instance_table[i]),
+"%s: instance_table is not empty\n", __func__))
+   break;
 }
 
 static struct pernet_operations nfnl_log_net_ops = {
-- 
2.7.4



[PATCH v2 13/21] nf_tables: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that lists initialized in net_init hook were return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/netfilter/nf_tables_api.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 64e1ee0..8219b2f 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -5778,6 +5778,14 @@ static int __net_init nf_tables_init_net(struct net *net)
return 0;
 }
 
+static void __net_exit nf_tables_exit_net(struct net *net)
+{
+   WARN(!list_empty(>nft.af_info),
+"%s: af_info list is not empty\n", __func__);
+   WARN(!list_empty(>nft.commit_list),
+"%s: commit_list is not empty\n", __func__);
+}
+
 int __nft_release_basechain(struct nft_ctx *ctx)
 {
struct nft_rule *rule, *nr;
@@ -5848,6 +5856,7 @@ static void __nft_release_afinfo(struct net *net, struct 
nft_af_info *afi)
 
 static struct pernet_operations nf_tables_net_ops = {
.init   = nf_tables_init_net,
+   .exit   = nf_tables_exit_net,
 };
 
 static int __init nf_tables_module_init(void)
-- 
2.7.4



[PATCH v2 15/21] nfnetlink_gueue: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that instance_table array initialized in net_init hook
was return to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/netfilter/nfnetlink_queue.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index c979662..0fa56d9 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -1512,10 +1512,17 @@ static int __net_init nfnl_queue_net_init(struct net 
*net)
 
 static void __net_exit nfnl_queue_net_exit(struct net *net)
 {
+   unsigned int i;
+   struct nfnl_queue_net *q = nfnl_queue_pernet(net);
+
nf_unregister_queue_handler(net);
 #ifdef CONFIG_PROC_FS
remove_proc_entry("nfnetlink_queue", net->nf.proc_netfilter);
 #endif
+   for (i = 0; i < INSTANCE_BUCKETS; i++)
+   if (WARN(!hlist_empty(>instance_table[i]),
+"%s: instance_table isn't empty\n", __func__))
+   break;
 }
 
 static void nfnl_queue_net_exit_batch(struct list_head *net_exit_list)
-- 
2.7.4



[PATCH v2 09/21] clusterip: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that configs list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/ipv4/netfilter/ipt_CLUSTERIP.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c 
b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 17b4ca5..038f0a9 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -819,6 +819,8 @@ static void clusterip_net_exit(struct net *net)
cn->procdir = NULL;
 #endif
nf_unregister_net_hook(net, _arp_ops);
+   WARN(!list_empty(>configs),
+"%s: configs list is not empty\n"i, __func__);
 }
 
 static struct pernet_operations clusterip_net_ops = {
-- 
2.7.4



[PATCH v2 11/21] af_key: replace BUG_ON on WARN_ON in net_exit hook

2017-11-05 Thread Vasily Averin
Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/key/af_key.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/key/af_key.c b/net/key/af_key.c
index a00d607..3dffb89 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -3845,7 +3845,7 @@ static void __net_exit pfkey_net_exit(struct net *net)
struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
 
pfkey_exit_proc(net);
-   BUG_ON(!hlist_empty(_pfkey->table));
+   WARN_ON(!hlist_empty(_pfkey->table));
 }
 
 static struct pernet_operations pfkey_net_ops = {
-- 
2.7.4



[PATCH v2 12/21] l2tp: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that l2tp_session_hlist array initialized in net_init hook
was return to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/l2tp/l2tp_core.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 02d6110..1136341 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1888,6 +1888,7 @@ static __net_exit void l2tp_exit_net(struct net *net)
 {
struct l2tp_net *pn = l2tp_pernet(net);
struct l2tp_tunnel *tunnel = NULL;
+   int hash;
 
rcu_read_lock_bh();
list_for_each_entry_rcu(tunnel, >l2tp_tunnel_list, list) {
@@ -1897,6 +1898,11 @@ static __net_exit void l2tp_exit_net(struct net *net)
 
flush_workqueue(l2tp_wq);
rcu_barrier();
+
+   for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++)
+   if (WARN(!hlist_empty(>l2tp_session_hlist[hash]),
+"%s: session_hlist is not empty\n", __func__))
+   break;
 }
 
 static struct pernet_operations l2tp_net_ops = {
-- 
2.7.4



[PATCH v2 10/21] xfrm6_tunnel: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that spi_byaddr and spi_byspi arrays initialized in net_init hook
were return to initial state

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/ipv6/xfrm6_tunnel.c | 12 
 1 file changed, 12 insertions(+)

diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index 4e438bc..8280152 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -338,6 +338,18 @@ static int __net_init xfrm6_tunnel_net_init(struct net 
*net)
 
 static void __net_exit xfrm6_tunnel_net_exit(struct net *net)
 {
+   struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
+   unsigned int i;
+
+   for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++)
+   if (WARN(!hlist_empty(_tn->spi_byaddr[i]),
+"%s: spi_byaddr is not empty\n", __func__))
+   break;
+
+   for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++)
+   if (WARN(!hlist_empty(_tn->spi_byspi[i]),
+"%s: spi_byspi is not empty\n", __func__))
+   break;
 }
 
 static struct pernet_operations xfrm6_tunnel_net_ops = {
-- 
2.7.4



[PATCH v2 08/21] fib_rules: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that rules_ops list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/core/fib_rules.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 9a6d97c..5ab4fac 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -1019,8 +1019,15 @@ static int __net_init fib_rules_net_init(struct net *net)
return 0;
 }
 
+static void __net_exit fib_rules_net_exit(struct net *net)
+{
+   WARN(!list_empty(>rules_ops),
+"%s: rules_ops list is not empty\n", __func__);
+}
+
 static struct pernet_operations fib_rules_net_ops = {
.init = fib_rules_net_init,
+   .exit = fib_rules_net_exit,
 };
 
 static int __init fib_rules_init(void)
-- 
2.7.4



[PATCH v2 07/21] fib_notifier: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that fib_notifier_ops list initilized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/core/fib_notifier.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/net/core/fib_notifier.c b/net/core/fib_notifier.c
index 4fc202d..1f57ec0 100644
--- a/net/core/fib_notifier.c
+++ b/net/core/fib_notifier.c
@@ -161,8 +161,15 @@ static int __net_init fib_notifier_net_init(struct net 
*net)
return 0;
 }
 
+static void __net_exit fib_notifier_net_exit(struct net *net)
+{
+   WARN(!list_empty(>fib_notifier_ops),
+"%s: fib_notifier_ops list is not empty\n", __func__);
+}
+
 static struct pernet_operations fib_notifier_net_ops = {
.init = fib_notifier_net_init,
+   .exit = fib_notifier_net_exit,
 };
 
 static int __init fib_notifier_init(void)
-- 
2.7.4



[PATCH v2 06/21] nfs client: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that nfs_client_list and nfs_volume_list lists initialized
in net_init hook were return to initial state in net_exit hook.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 fs/nfs/client.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 22880ef..e099a01 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -204,6 +204,10 @@ void nfs_cleanup_cb_ident_idr(struct net *net)
struct nfs_net *nn = net_generic(net, nfs_net_id);
 
idr_destroy(>cb_ident_idr);
+   WARN(!list_empty(>nfs_client_list),
+"nfs net_exit: nfs_client_list is not empty\n");
+   WARN(!list_empty(>nfs_volume_list),
+"nfs net_exit: nfs_volume_list is not empty\n");
 }
 
 /* nfs_client_lock held */
-- 
2.7.4



[PATCH v2 05/21] nfs4blocklayout: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that bl_wq wait queue initialized in net_init hook
is not used anymore.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 fs/nfs/blocklayout/rpc_pipefs.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fs/nfs/blocklayout/rpc_pipefs.c b/fs/nfs/blocklayout/rpc_pipefs.c
index 9fb067a6..faae48f 100644
--- a/fs/nfs/blocklayout/rpc_pipefs.c
+++ b/fs/nfs/blocklayout/rpc_pipefs.c
@@ -256,6 +256,8 @@ static void nfs4blocklayout_net_exit(struct net *net)
nfs4blocklayout_unregister_net(net, nn->bl_device_pipe);
rpc_destroy_pipe_data(nn->bl_device_pipe);
nn->bl_device_pipe = NULL;
+   WARN(!list_empty(>bl_wq.head),
+"%s: bl_wq head is not empty\n", __func__);
 }
 
 static struct pernet_operations nfs4blocklayout_net_ops = {
-- 
2.7.4



[PATCH v2 02/21] ppp: exit_net cleanup checks added

2017-11-05 Thread Vasily Averin
Be sure that lists initialized in net_init hook were return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 drivers/net/ppp/ppp_generic.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index e365866..10cee62 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -960,6 +960,10 @@ static __net_exit void ppp_exit_net(struct net *net)
rtnl_unlock();
 
idr_destroy(>units_idr);
+   WARN(!list_empty(>all_channels),
+"%s: all_channels list is not empty\n", __func__);
+   WARN(!list_empty(>new_channels),
+"%s: new_channels list is not empty\n", __func__);
 }
 
 static struct pernet_operations ppp_net_ops = {
-- 
2.7.4



[PATCH v2 04/21] netdev: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that dev_base_head list initialized in net_init hook was return
to initial state

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/core/dev.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/net/core/dev.c b/net/core/dev.c
index 588b473..198f137 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -8562,6 +8562,9 @@ static void __net_exit netdev_exit(struct net *net)
 {
kfree(net->dev_name_head);
kfree(net->dev_index_head);
+   if (net != _net)
+   WARN(!list_empty(>dev_base_head),
+"%s: dev_base_head is not empty\n", __func__);
 }
 
 static struct pernet_operations __net_initdata netdev_net_ops = {
-- 
2.7.4



[PATCH v2 01/21] exit_net cleanup: geneve sock_list check

2017-11-05 Thread Vasily Averin
Be sure that sock_list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 drivers/net/geneve.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index f640407..dece711 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -1673,6 +1673,8 @@ static void __net_exit geneve_exit_net(struct net *net)
/* unregister the devices gathered above */
unregister_netdevice_many();
rtnl_unlock();
+   WARN(!list_empty(>sock_list),
+": sock_list is not empty\n", __func__);
 }
 
 static struct pernet_operations geneve_net_ops = {
-- 
2.7.4



[PATCH v2 03/21] vxlan: exit_net cleanup checks added

2017-11-05 Thread Vasily Averin
Be sure that sock_list array initialized in net_init hook was return
to initial state

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 drivers/net/vxlan.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index d7c49cf..f72c1de 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -3704,6 +3704,7 @@ static void __net_exit vxlan_exit_net(struct net *net)
struct vxlan_net *vn = net_generic(net, vxlan_net_id);
struct vxlan_dev *vxlan, *next;
struct net_device *dev, *aux;
+   unsigned int h;
LIST_HEAD(list);
 
rtnl_lock();
@@ -3723,6 +3724,11 @@ static void __net_exit vxlan_exit_net(struct net *net)
 
unregister_netdevice_many();
rtnl_unlock();
+
+   for (h = 0; h < PORT_HASH_SIZE; ++h)
+   if (WARN(!hlist_empty(>sock_list[h]),
+"%s: sock_list is not empty\n", __func__))
+   break;
 }
 
 static struct pernet_operations vxlan_net_ops = {
-- 
2.7.4



[PATCH v2 00/21] exit_net checks for objects initialized in net_init hook

2017-11-05 Thread Vasily Averin
This patch set checks that lists initialized in net_init hooks were
return to initial state at end of net_exit hooks.

I hope such checks allows to detect leaked per-netns objects.
Also I hope that all new pernet_operations will inherit such checks too.

I assume that elements added into per-net lists should not live longer than net 
namespace,
and should be deleted from the list. I think exit_net hook is good place for 
such check.

Recently I've found lost list_entry and enabled timer on stop of net namespace.
Then I've reviewed all existing pernet_operations and found that many drivers
have such checks already. So I decided to complete this task and add such checks
into all affected subsystems.

v2:
- net pointer removed from output
- fixed compilation for phonet driver

Vasily Averin (21):
  exit_net cleanup: geneve sock_list check
  ppp: exit_net cleanup checks added
  vxlan: exit_net cleanup checks added
  netdev: exit_net cleanup check added
  nfs4blocklayout: exit_net cleanup check added
  nfs client: exit_net cleanup check added
  fib_notifier: exit_net cleanup check added
  fib_rules: exit_net cleanup check added
  clusterip: exit_net cleanup check added
  xfrm6_tunnel: exit_net cleanup check added
  af_key: replace BUG_ON on WARN_ON in net_exit hook
  l2tp: exit_net cleanup check added
  nf_tables: exit_net cleanup check added
  nfnetlink_log: exit_net cleanup check added
  nfnetlink_gueue: exit_net cleanup check added
  x_tables: exit_net cleanup check added
  hashlimit: exit_net cleanup check added
  recent: exit_net cleanup check added
  packet: exit_net cleanup check added
  phonet: exit_net cleanup check added
  sunrpc: exit_net cleanup check added

 drivers/net/geneve.c   |  2 ++
 drivers/net/ppp/ppp_generic.c  |  4 
 drivers/net/vxlan.c|  6 ++
 fs/nfs/blocklayout/rpc_pipefs.c|  2 ++
 fs/nfs/client.c|  4 
 net/core/dev.c |  3 +++
 net/core/fib_notifier.c|  7 +++
 net/core/fib_rules.c   |  7 +++
 net/ipv4/netfilter/ipt_CLUSTERIP.c |  2 ++
 net/ipv6/xfrm6_tunnel.c| 12 
 net/key/af_key.c   |  2 +-
 net/l2tp/l2tp_core.c   |  6 ++
 net/netfilter/nf_tables_api.c  |  9 +
 net/netfilter/nfnetlink_log.c  |  6 ++
 net/netfilter/nfnetlink_queue.c|  7 +++
 net/netfilter/x_tables.c   | 10 ++
 net/netfilter/xt_hashlimit.c   |  4 
 net/netfilter/xt_recent.c  |  4 
 net/packet/af_packet.c |  2 ++
 net/phonet/pn_dev.c|  4 
 net/sunrpc/sunrpc_syms.c   |  4 
 21 files changed, 106 insertions(+), 1 deletion(-)

-- 
2.7.4



Re: [PATCH 06/21] nfs client: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
On 2017-11-05 19:02, Trond Myklebust wrote:
> On Sun, 2017-11-05 at 13:00 +0300, Vasily Averin wrote:
>> Be sure that nfs_client_list and nfs_volume_list lists initialized
>> in net_init hook were return to initial state in net_exit hook.
>>
>> Signed-off-by: Vasily Averin <v...@virtuozzo.com>
>> ---
>>  fs/nfs/client.c | 4 
>>  1 file changed, 4 insertions(+)
>>
>> diff --git a/fs/nfs/client.c b/fs/nfs/client.c
>> index 22880ef..7c0691c 100644
>> --- a/fs/nfs/client.c
>> +++ b/fs/nfs/client.c
>> @@ -204,6 +204,10 @@ void nfs_cleanup_cb_ident_idr(struct net *net)
>>  struct nfs_net *nn = net_generic(net, nfs_net_id);
>>  
>>  idr_destroy(>cb_ident_idr);
>> +WARN(!list_empty(>nfs_client_list),
>> + "net %p exit: nfs_client_list is not empty\n", net);
>> +WARN(!list_empty(>nfs_volume_list),
>> + "net %p exit: nfs_volume_list is not empty\n", net);
>>  }
>>  
> 
> Why do we need these? Is there a specific bug that you are trying to
> track down?

I hope such checks allows to detect leaked per-netns objects.
Also I hope that all new pernet_operations will inherit such checks too.

I assume that elements added into per-net lists should not live longer than net 
namespace,
and should be deleted from the list. I think exit_net hook is good place for 
such check.

Recently I've found lost list_entry and enabled timer on stop of net namespace.
Then I've reviewed all existing pernet_operations and found that many drivers
have such checks already. So I decided to complete this task and add such checks
into all affected subsystems.


Re: [PATCH 20/21] phonet: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
On 2017-11-05 13:17, Rémi Denis-Courmont wrote:
> Le 5 novembre 2017 12:02:34 GMT+02:00, Vasily Averin <v...@virtuozzo.com> a 
> écrit :
>> Be sure that pndevs.list initialized in net_init hook was return
>> to initial state.
>>
>> Signed-off-by: Vasily Averin <v...@virtuozzo.com>
>> ---
>> net/phonet/pn_dev.c | 2 ++
>> 1 file changed, 2 insertions(+)
>>
>> diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
>> index 2cb4c5d..1024851 100644
>> --- a/net/phonet/pn_dev.c
>> +++ b/net/phonet/pn_dev.c
>> @@ -332,6 +332,8 @@ static int __net_init phonet_init_net(struct net
>> *net)
>> static void __net_exit phonet_exit_net(struct net *net)
>> {
>>  remove_proc_entry("phonet", net->proc_net);
>> +WARN(!list_empty(>pndevs.list),
>> + "net %p exit: phonet pndevs.list is not empty\n", net);
>> }
>>
>> static struct pernet_operations phonet_net_ops = {
> 
> Hello,
> 
> TBH, I am not clear what the benefit of this is supposed to be... also, does 
> this not leak a pointer to userspace, breaking ASLR?

Dear Rémi,
I assume that elements added into per-netns list should not live longer then 
netns.
Such check allows to be sure that driver works with list correctly and lost no 
entries.
Many drivers does it already, and my current patch sent just makes this praxis 
global.

I doubt that pointer to freed net have value for someone except developers,
on the other hand it helps to speed up the problem investigation.

Thank you,
Vasily Averin


[PATCH 21/21] sunrpc: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that all_clients list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/sunrpc/sunrpc_syms.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index c73de18..0c5a90f 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -65,10 +65,14 @@ static __net_init int sunrpc_init_net(struct net *net)
 
 static __net_exit void sunrpc_exit_net(struct net *net)
 {
+   struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
rpc_pipefs_exit_net(net);
unix_gid_cache_destroy(net);
ip_map_cache_destroy(net);
rpc_proc_exit(net);
+   WARN(!list_empty(>all_clients),
+"net %p exit: sunrpc all_clients list is not empty\n", net);
 }
 
 static struct pernet_operations sunrpc_net_ops = {
-- 
2.7.4



[PATCH 19/21] packet: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that packet.sklist initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/packet/af_packet.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index bec01a3..16bbc0e 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -4562,6 +4562,8 @@ static int __net_init packet_net_init(struct net *net)
 static void __net_exit packet_net_exit(struct net *net)
 {
remove_proc_entry("packet", net->proc_net);
+   WARN(!hlist_empty(>packet.sklist),
+"net %p exit: packet sklist is not empty\n", net);
 }
 
 static struct pernet_operations packet_net_ops = {
-- 
2.7.4



[PATCH 18/21] recent: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that tables list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/netfilter/xt_recent.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c
index 245fa35..7e29d30 100644
--- a/net/netfilter/xt_recent.c
+++ b/net/netfilter/xt_recent.c
@@ -681,7 +681,11 @@ static int __net_init recent_net_init(struct net *net)
 
 static void __net_exit recent_net_exit(struct net *net)
 {
+   struct recent_net *recent_net = recent_pernet(net);
+
recent_proc_net_exit(net);
+   WARN(!list_empty(_net->tables),
+"net %p exit: recent tables list is not empty\n", net);
 }
 
 static struct pernet_operations recent_net_ops = {
-- 
2.7.4



[PATCH 20/21] phonet: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that pndevs.list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/phonet/pn_dev.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index 2cb4c5d..1024851 100644
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@ -332,6 +332,8 @@ static int __net_init phonet_init_net(struct net *net)
 static void __net_exit phonet_exit_net(struct net *net)
 {
remove_proc_entry("phonet", net->proc_net);
+   WARN(!list_empty(>pndevs.list),
+"net %p exit: phonet pndevs.list is not empty\n", net);
 }
 
 static struct pernet_operations phonet_net_ops = {
-- 
2.7.4



[PATCH 13/21] nf_tables: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that lists initialized in net_init hook were return to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/netfilter/nf_tables_api.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 64e1ee0..60cbf0a 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -5778,6 +5778,14 @@ static int __net_init nf_tables_init_net(struct net *net)
return 0;
 }
 
+static void __net_exit nf_tables_exit_net(struct net *net)
+{
+   WARN(!list_empty(>nft.af_info),
+"net %p exit: nf_tables af_info list is not empty\n", net);
+   WARN(!list_empty(>nft.commit_list),
+"net %p exit: nf_tables commit_list is not empty\n", net);
+}
+
 int __nft_release_basechain(struct nft_ctx *ctx)
 {
struct nft_rule *rule, *nr;
@@ -5848,6 +5856,7 @@ static void __nft_release_afinfo(struct net *net, struct 
nft_af_info *afi)
 
 static struct pernet_operations nf_tables_net_ops = {
.init   = nf_tables_init_net,
+   .exit   = nf_tables_exit_net,
 };
 
 static int __init nf_tables_module_init(void)
-- 
2.7.4



[PATCH 17/21] hashlimit: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that htables array initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/netfilter/xt_hashlimit.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index 5da8746..78485d1 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -1338,7 +1338,11 @@ static int __net_init hashlimit_net_init(struct net *net)
 
 static void __net_exit hashlimit_net_exit(struct net *net)
 {
+   struct hashlimit_net *hashlimit_net = hashlimit_pernet(net);
+
hashlimit_proc_net_exit(net);
+   WARN(!hlist_empty(_net->htables),
+"net %p exit: hashlimit htables hlist is not empty\n", net);
 }
 
 static struct pernet_operations hashlimit_net_ops = {
-- 
2.7.4



[PATCH 16/21] x_tables: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that xt.tables array initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/netfilter/x_tables.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index d8571f4..7e74b37 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1714,8 +1714,18 @@ static int __net_init xt_net_init(struct net *net)
return 0;
 }
 
+static void __net_exit xt_net_exit(struct net *net)
+{
+   int i;
+
+   for (i = 0; i < NFPROTO_NUMPROTO; i++)
+   WARN(!list_empty(>xt.tables[i]),
+"net %p exit: xt tables list is not empty\n", net);
+}
+
 static struct pernet_operations xt_net_ops = {
.init = xt_net_init,
+   .exit = xt_net_exit,
 };
 
 static int __init xt_init(void)
-- 
2.7.4



[PATCH 14/21] nfnetlink_log: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that instance_table array initialized in net_init hook
was return to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/netfilter/nfnetlink_log.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index cad6498..fa97566 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -1093,10 +1093,17 @@ static int __net_init nfnl_log_net_init(struct net *net)
 
 static void __net_exit nfnl_log_net_exit(struct net *net)
 {
+   unsigned int i;
+   struct nfnl_log_net *log = nfnl_log_pernet(net);
 #ifdef CONFIG_PROC_FS
remove_proc_entry("nfnetlink_log", net->nf.proc_netfilter);
 #endif
nf_log_unset(net, _logger);
+   for (i = 0; i < INSTANCE_BUCKETS; i++)
+   if (WARN(!hlist_empty(>instance_table[i]),
+"net %p exit: nfnl_log instance_table is not empty\n",
+net))
+   break;
 }
 
 static struct pernet_operations nfnl_log_net_ops = {
-- 
2.7.4



[PATCH 15/21] nfnetlink_gueue: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that instance_table array initialized in net_init hook
was return to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/netfilter/nfnetlink_queue.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index c979662..c752eb7 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -1512,10 +1512,18 @@ static int __net_init nfnl_queue_net_init(struct net 
*net)
 
 static void __net_exit nfnl_queue_net_exit(struct net *net)
 {
+   unsigned int i;
+   struct nfnl_queue_net *q = nfnl_queue_pernet(net);
+
nf_unregister_queue_handler(net);
 #ifdef CONFIG_PROC_FS
remove_proc_entry("nfnetlink_queue", net->nf.proc_netfilter);
 #endif
+   for (i = 0; i < INSTANCE_BUCKETS; i++)
+   if (WARN(!hlist_empty(>instance_table[i]),
+"net %p exit: nfnl_queue instance_table isn't empty\n",
+net))
+   break;
 }
 
 static void nfnl_queue_net_exit_batch(struct list_head *net_exit_list)
-- 
2.7.4



[PATCH 10/21] xfrm6_tunnel: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that spi_byaddr and spi_byspi arrays initialized in net_init hook
were return to initial state

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/ipv6/xfrm6_tunnel.c | 12 
 1 file changed, 12 insertions(+)

diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index 4e438bc..3825e03 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -338,6 +338,18 @@ static int __net_init xfrm6_tunnel_net_init(struct net 
*net)
 
 static void __net_exit xfrm6_tunnel_net_exit(struct net *net)
 {
+   struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
+   unsigned int i;
+
+   for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++)
+   if (WARN(!hlist_empty(_tn->spi_byaddr[i]),
+"net %p exit: xfrm6 spi_byaddr is not empty\n", net))
+   break;
+
+   for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++)
+   if (WARN(!hlist_empty(_tn->spi_byspi[i]),
+"net %p exit: xfrm6 spi_byspi is not empty\n", net))
+   break;
 }
 
 static struct pernet_operations xfrm6_tunnel_net_ops = {
-- 
2.7.4



[PATCH 09/21] clusterip: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that configs list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/ipv4/netfilter/ipt_CLUSTERIP.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c 
b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 17b4ca5..aa6ada3 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -819,6 +819,8 @@ static void clusterip_net_exit(struct net *net)
cn->procdir = NULL;
 #endif
nf_unregister_net_hook(net, _arp_ops);
+   WARN(!list_empty(>configs),
+"net %p exit: clusterip configs list is not empty\n", net);
 }
 
 static struct pernet_operations clusterip_net_ops = {
-- 
2.7.4



[PATCH 08/21] fib_rules: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that rules_ops list initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/core/fib_rules.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 9a6d97c..bb921b0 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -1019,8 +1019,15 @@ static int __net_init fib_rules_net_init(struct net *net)
return 0;
 }
 
+static void __net_exit fib_rules_net_exit(struct net *net)
+{
+   WARN(!list_empty(>rules_ops),
+"net %p exit: fib rules_ops list is not empty\n", net);
+}
+
 static struct pernet_operations fib_rules_net_ops = {
.init = fib_rules_net_init,
+   .exit = fib_rules_net_exit,
 };
 
 static int __init fib_rules_init(void)
-- 
2.7.4



[PATCH 12/21] l2tp: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that l2tp_session_hlist array initialized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/l2tp/l2tp_core.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 02d6110..109fd36 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1888,6 +1888,7 @@ static __net_exit void l2tp_exit_net(struct net *net)
 {
struct l2tp_net *pn = l2tp_pernet(net);
struct l2tp_tunnel *tunnel = NULL;
+   int hash;
 
rcu_read_lock_bh();
list_for_each_entry_rcu(tunnel, >l2tp_tunnel_list, list) {
@@ -1897,6 +1898,11 @@ static __net_exit void l2tp_exit_net(struct net *net)
 
flush_workqueue(l2tp_wq);
rcu_barrier();
+
+   for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++)
+   if (WARN(!hlist_empty(>l2tp_session_hlist[hash]),
+"net %p exit: l2tp session_hlist is not empty\n", net))
+   break;
 }
 
 static struct pernet_operations l2tp_net_ops = {
-- 
2.7.4



[PATCH 07/21] fib_notifier: exit_net cleanup check added

2017-11-05 Thread Vasily Averin
Be sure that fib_notifier_ops list initilized in net_init hook was return
to initial state.

Signed-off-by: Vasily Averin <v...@virtuozzo.com>
---
 net/core/fib_notifier.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/net/core/fib_notifier.c b/net/core/fib_notifier.c
index 4fc202d..2de8df3 100644
--- a/net/core/fib_notifier.c
+++ b/net/core/fib_notifier.c
@@ -161,8 +161,15 @@ static int __net_init fib_notifier_net_init(struct net 
*net)
return 0;
 }
 
+static void __net_exit fib_notifier_net_exit(struct net *net)
+{
+   WARN(!list_empty(>fib_notifier_ops),
+"net %p exit: fib_notifier_ops list is not empty\n", net);
+}
+
 static struct pernet_operations fib_notifier_net_ops = {
.init = fib_notifier_net_init,
+   .exit = fib_notifier_net_exit,
 };
 
 static int __init fib_notifier_init(void)
-- 
2.7.4



  1   2   >