diff options
author | Julian Anastasov <ja@ssi.bg> | 2012-04-16 04:43:15 +0000 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-04-27 09:51:21 -0700 |
commit | 0958c122f47f4ef2a1ae552fed56a8bf8502c32b (patch) | |
tree | fe2b05ff1c175836b1c407a948b0bdea4d3e9628 /net | |
parent | 6a0e69cea2ec1499224067989470d3c929dbd67e (diff) |
netns: do not leak net_generic data on failed init
[ Upstream commit b922934d017f1cc831b017913ed7d1a56c558b43 ]
ops_init should free the net_generic data on
init failure and __register_pernet_operations should not
call ops_free when NET_NS is not enabled.
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Reviewed-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/net_namespace.c | 33 |
1 files changed, 18 insertions, 15 deletions
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 0b0211d7fc3..2772ed11bec 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -82,21 +82,29 @@ assign: static int ops_init(const struct pernet_operations *ops, struct net *net) { - int err; + int err = -ENOMEM; + void *data = NULL; + if (ops->id && ops->size) { - void *data = kzalloc(ops->size, GFP_KERNEL); + data = kzalloc(ops->size, GFP_KERNEL); if (!data) - return -ENOMEM; + goto out; err = net_assign_generic(net, *ops->id, data); - if (err) { - kfree(data); - return err; - } + if (err) + goto cleanup; } + err = 0; if (ops->init) - return ops->init(net); - return 0; + err = ops->init(net); + if (!err) + return 0; + +cleanup: + kfree(data); + +out: + return err; } static void ops_free(const struct pernet_operations *ops, struct net *net) @@ -446,12 +454,7 @@ static void __unregister_pernet_operations(struct pernet_operations *ops) static int __register_pernet_operations(struct list_head *list, struct pernet_operations *ops) { - int err = 0; - err = ops_init(ops, &init_net); - if (err) - ops_free(ops, &init_net); - return err; - + return ops_init(ops, &init_net); } static void __unregister_pernet_operations(struct pernet_operations *ops) |