[Devel] [PATCH RHEL7 COMMIT] net: net_assign_generic NULL lead to memory leaks
Vasily Averin
vvs at virtuozzo.com
Mon Apr 5 13:05:25 MSK 2021
The commit is pushed to "branch-rh7-3.10.0-1160.21.1.vz7.174.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-1160.21.1.vz7.174.5
------>
commit ee83cbb202626f6902eb0d728ef92ce7620f713f
Author: Vasily Averin <vvs at virtuozzo.com>
Date: Mon Apr 5 13:05:24 2021 +0300
net: net_assign_generic NULL lead to memory leaks
net_assign_generic(NULL) called during net_init or net_exit hooks
cleans up net_generic() pointer allocated by ops_init()
and does not allow to free it during ops_free()
Let's drop calls from net_exit hooks
and use net_generic_free() call instead in net_init_hooks.
https://jira.sw.ru/browse/PSBM-92950
Signed-off-by: Vasily Averin <vvs at virtuozzo.com>
---
drivers/net/ppp/ppp_generic.c | 7 ++++---
drivers/net/ppp/pppoe.c | 7 ++++---
include/net/netns/generic.h | 13 ++++++++++++-
net/ipv4/ip_gre.c | 12 ++++++++----
net/ipv4/ip_vti.c | 6 ++++--
net/ipv4/ipip.c | 8 ++++----
net/ipv6/ip6_gre.c | 6 ++++--
net/ipv6/ip6_tunnel.c | 6 ++++--
net/ipv6/sit.c | 7 ++++---
9 files changed, 48 insertions(+), 24 deletions(-)
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index a9480c1..5c7e0d5 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -884,9 +884,10 @@ static __net_init int ppp_init_net(struct net *net)
{
struct ppp_net *pn = net_generic(net, ppp_net_id);
- if (!(net->owner_ve->features & VE_FEATURE_PPP))
- return net_assign_generic(net, ppp_net_id, NULL);
-
+ if (!(net->owner_ve->features & VE_FEATURE_PPP)) {
+ net_generic_free(net, ppp_net_id);
+ return 0;
+ }
idr_init(&pn->units_idr);
mutex_init(&pn->all_ppp_mutex);
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index 3101720..81618dc 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -1169,9 +1169,10 @@ static __net_init int pppoe_init_net(struct net *net)
struct pppoe_net *pn = pppoe_pernet(net);
struct proc_dir_entry *pde;
- if (!(net->owner_ve->features & VE_FEATURE_PPP))
- return net_assign_generic(net, pppoe_net_id, NULL);
-
+ if (!(net->owner_ve->features & VE_FEATURE_PPP)) {
+ net_generic_free(net, pppoe_net_id);
+ return 0;
+ }
rwlock_init(&pn->hash_lock);
pde = proc_net_create("pppoe", S_IRUGO, net->proc_net, &pppoe_seq_fops);
diff --git a/include/net/netns/generic.h b/include/net/netns/generic.h
index a07ef65..eb07bda 100644
--- a/include/net/netns/generic.h
+++ b/include/net/netns/generic.h
@@ -49,6 +49,17 @@ static inline void *net_generic(const struct net *net, int id)
return ptr;
}
-extern int net_assign_generic(struct net *net, int id, void *data);
+static inline void net_generic_free(const struct net *net, unsigned int id)
+{
+ struct net_generic *ng;
+ void *ptr;
+
+ rcu_read_lock();
+ ng = rcu_dereference(net->gen);
+ ptr = ng->ptr[id];
+ ng->ptr[id] = NULL;
+ rcu_read_unlock();
+ kfree(ptr);
+}
#endif
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index aecb1a8..52234a5 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -788,8 +788,10 @@ static const struct gre_protocol ipgre_protocol = {
static int __net_init ipgre_init_net(struct net *net)
{
#ifdef CONFIG_VE
- if (!(net->owner_ve->features & VE_FEATURE_IPGRE))
- return net_assign_generic(net, ipgre_net_id, NULL);
+ if (!(net->owner_ve->features & VE_FEATURE_IPGRE)) {
+ net_generic_free(net, ipgre_net_id);
+ return 0;
+ }
#endif
return ip_tunnel_init_net(net, ipgre_net_id, &ipgre_link_ops, NULL);
}
@@ -1222,8 +1224,10 @@ EXPORT_SYMBOL_GPL(gretap_fb_dev_create);
static int __net_init ipgre_tap_init_net(struct net *net)
{
#ifdef CONFIG_VE
- if (!(net->owner_ve->features & VE_FEATURE_IPGRE))
- return net_assign_generic(net, gre_tap_net_id, NULL);
+ if (!(net->owner_ve->features & VE_FEATURE_IPGRE)) {
+ net_generic_free(net, gre_tap_net_id);
+ return 0;
+ }
#endif
return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, "gretap0");
}
diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c
index 3ab6f1a..3608f4e 100644
--- a/net/ipv4/ip_vti.c
+++ b/net/ipv4/ip_vti.c
@@ -436,8 +436,10 @@ static int __net_init vti_init_net(struct net *net)
int err;
struct ip_tunnel_net *itn;
- if (!ve_is_super(net->owner_ve))
- return net_assign_generic(net, vti_net_id, NULL);
+ if (!ve_is_super(net->owner_ve)) {
+ net_generic_free(net, vti_net_id);
+ return 0;
+ }
err = ip_tunnel_init_net(net, vti_net_id, &vti_link_ops, "ip_vti0");
if (err)
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index ea55274..a4c1c20 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -471,9 +471,10 @@ static struct xfrm_tunnel ipip_handler __read_mostly = {
static int __net_init ipip_init_net(struct net *net)
{
- if (!(net->owner_ve->features & VE_FEATURE_IPIP))
- return net_assign_generic(net, ipip_net_id, NULL);
-
+ if (!(net->owner_ve->features & VE_FEATURE_IPIP)) {
+ net_assign_generic(net, ipip_net_id);
+ return 0;
+ }
return ip_tunnel_init_net(net, ipip_net_id, &ipip_link_ops, "tunl0");
}
@@ -485,7 +486,6 @@ static void __net_exit ipip_exit_net(struct net *net)
return;
ip_tunnel_delete_net(itn, &ipip_link_ops);
- net_assign_generic(net, ipip_net_id, NULL);
}
static struct pernet_operations ipip_net_ops = {
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 818d76e..5743692 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -1234,8 +1234,10 @@ static int __net_init ip6gre_init_net(struct net *net)
int err;
#ifdef CONFIG_VE
- if (!(net->owner_ve->features & VE_FEATURE_IPGRE))
- return net_assign_generic(net, ip6gre_net_id, NULL);
+ if (!(net->owner_ve->features & VE_FEATURE_IPGRE)) {
+ net_generic_free(net, ip6gre_net_id);
+ return 0;
+ }
#endif
ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6gre0",
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 465b0e2..87f8b4f 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -2045,8 +2045,10 @@ static int __net_init ip6_tnl_init_net(struct net *net)
int err;
#ifdef CONFIG_VE
- if (!(net->owner_ve->features & VE_FEATURE_IPIP))
- return net_assign_generic(net, ip6_tnl_net_id, NULL);
+ if (!(net->owner_ve->features & VE_FEATURE_IPIP)) {
+ net_generic_free(net, ip6_tnl_net_id);
+ return 0;
+ }
#endif
ip6n->tnls[0] = ip6n->tnls_wc;
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 52b9e6a..e54f773 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -1740,8 +1740,10 @@ static int __net_init sit_init_net(struct net *net)
struct ip_tunnel *t;
int err;
- if (!(net->owner_ve->features & VE_FEATURE_SIT))
- return net_assign_generic(net, sit_net_id, NULL);
+ if (!(net->owner_ve->features & VE_FEATURE_SIT)) {
+ net_generic_free(net, sit_net_id);
+ return 0;
+ }
sitn->tunnels[0] = sitn->tunnels_wc;
sitn->tunnels[1] = sitn->tunnels_l;
@@ -1791,7 +1793,6 @@ static void __net_exit sit_exit_net(struct net *net)
sit_destroy_tunnels(net, &list);
unregister_netdevice_many(&list);
rtnl_unlock();
- net_assign_generic(net, sit_net_id, NULL);
}
static struct pernet_operations sit_net_ops = {
More information about the Devel
mailing list