diff options
author | Julian Anastasov <ja@ssi.bg> | 2012-04-16 00:43:15 -0400 |
---|---|---|
committer | Luis Henriques <luis.henriques@canonical.com> | 2012-05-01 06:00:23 -0400 |
commit | 7a44ec092d399db125c10c2f18b0f90157840819 (patch) | |
tree | 197bf5d2c00b14c990bcc12197096866e000ecce /net | |
parent | 81a5e5595a996d6e304e342411f34adb95213d2e (diff) |
netns: do not leak net_generic data on failed init
BugLink: http://bugs.launchpad.net/bugs/990544
[ 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>
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
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: | |||
82 | 82 | ||
83 | static int ops_init(const struct pernet_operations *ops, struct net *net) | 83 | static int ops_init(const struct pernet_operations *ops, struct net *net) |
84 | { | 84 | { |
85 | int err; | 85 | int err = -ENOMEM; |
86 | void *data = NULL; | ||
87 | |||
86 | if (ops->id && ops->size) { | 88 | if (ops->id && ops->size) { |
87 | void *data = kzalloc(ops->size, GFP_KERNEL); | 89 | data = kzalloc(ops->size, GFP_KERNEL); |
88 | if (!data) | 90 | if (!data) |
89 | return -ENOMEM; | 91 | goto out; |
90 | 92 | ||
91 | err = net_assign_generic(net, *ops->id, data); | 93 | err = net_assign_generic(net, *ops->id, data); |
92 | if (err) { | 94 | if (err) |
93 | kfree(data); | 95 | goto cleanup; |
94 | return err; | ||
95 | } | ||
96 | } | 96 | } |
97 | err = 0; | ||
97 | if (ops->init) | 98 | if (ops->init) |
98 | return ops->init(net); | 99 | err = ops->init(net); |
99 | return 0; | 100 | if (!err) |
101 | return 0; | ||
102 | |||
103 | cleanup: | ||
104 | kfree(data); | ||
105 | |||
106 | out: | ||
107 | return err; | ||
100 | } | 108 | } |
101 | 109 | ||
102 | static void ops_free(const struct pernet_operations *ops, struct net *net) | 110 | 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) | |||
446 | static int __register_pernet_operations(struct list_head *list, | 454 | static int __register_pernet_operations(struct list_head *list, |
447 | struct pernet_operations *ops) | 455 | struct pernet_operations *ops) |
448 | { | 456 | { |
449 | int err = 0; | 457 | return ops_init(ops, &init_net); |
450 | err = ops_init(ops, &init_net); | ||
451 | if (err) | ||
452 | ops_free(ops, &init_net); | ||
453 | return err; | ||
454 | |||
455 | } | 458 | } |
456 | 459 | ||
457 | static void __unregister_pernet_operations(struct pernet_operations *ops) | 460 | static void __unregister_pernet_operations(struct pernet_operations *ops) |