netns: fix double free at netns creation

This patch fix a double free when a network namespace fails.
The previous code does a kfree of the net_generic structure when
one of the init subsystem initialization fails.
The 'setup_net' function does kfree(ng) and returns an error.
The caller, 'copy_net_ns', call net_free on error, and this one
calls kfree(net->gen), making this pointer freed twice.

This patch make the code symetric, the net_alloc does the net_generic
allocation and the net_free frees the net_generic.

Signed-off-by: Daniel Lezcano <daniel.lezcano@free.fr>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by Daniel Lezcano and committed by David S. Miller 486a87f1 ee923623

+55 -31
+55 -31
net/core/net_namespace.c
··· 32 32 { 33 33 /* Must be called with net_mutex held */ 34 34 struct pernet_operations *ops; 35 - int error; 36 - struct net_generic *ng; 35 + int error = 0; 37 36 38 37 atomic_set(&net->count, 1); 38 + 39 39 #ifdef NETNS_REFCNT_DEBUG 40 40 atomic_set(&net->use_count, 0); 41 41 #endif 42 42 43 - error = -ENOMEM; 44 - ng = kzalloc(sizeof(struct net_generic) + 45 - INITIAL_NET_GEN_PTRS * sizeof(void *), GFP_KERNEL); 46 - if (ng == NULL) 47 - goto out; 48 - 49 - ng->len = INITIAL_NET_GEN_PTRS; 50 - rcu_assign_pointer(net->gen, ng); 51 - 52 - error = 0; 53 43 list_for_each_entry(ops, &pernet_list, list) { 54 44 if (ops->init) { 55 45 error = ops->init(net); ··· 60 70 } 61 71 62 72 rcu_barrier(); 63 - kfree(ng); 64 73 goto out; 65 74 } 66 75 ··· 67 78 static struct kmem_cache *net_cachep; 68 79 static struct workqueue_struct *netns_wq; 69 80 81 + static struct net_generic *net_alloc_generic(void) 82 + { 83 + struct net_generic *ng; 84 + size_t generic_size = sizeof(struct net_generic) + 85 + INITIAL_NET_GEN_PTRS * sizeof(void *); 86 + 87 + ng = kzalloc(generic_size, GFP_KERNEL); 88 + if (ng) 89 + ng->len = INITIAL_NET_GEN_PTRS; 90 + 91 + return ng; 92 + } 93 + 70 94 static struct net *net_alloc(void) 71 95 { 72 - return kmem_cache_zalloc(net_cachep, GFP_KERNEL); 96 + struct net *net = NULL; 97 + struct net_generic *ng; 98 + 99 + ng = net_alloc_generic(); 100 + if (!ng) 101 + goto out; 102 + 103 + net = kmem_cache_zalloc(net_cachep, GFP_KERNEL); 104 + if (!net) 105 + goto out_free; 106 + 107 + rcu_assign_pointer(net->gen, ng); 108 + out: 109 + return net; 110 + 111 + out_free: 112 + kfree(ng); 113 + goto out; 73 114 } 74 115 75 116 static void net_free(struct net *net) 76 117 { 77 - if (!net) 78 - return; 79 - 80 118 #ifdef NETNS_REFCNT_DEBUG 81 119 if (unlikely(atomic_read(&net->use_count) != 0)) { 82 120 printk(KERN_EMERG "network namespace not free! Usage: %d\n", ··· 128 112 err = -ENOMEM; 129 113 new_net = net_alloc(); 130 114 if (!new_net) 131 - goto out; 115 + goto out_err; 132 116 133 117 mutex_lock(&net_mutex); 134 118 err = setup_net(new_net); 135 - if (err) 136 - goto out_unlock; 137 - 138 - rtnl_lock(); 139 - list_add_tail(&new_net->list, &net_namespace_list); 140 - rtnl_unlock(); 141 - 142 - 143 - out_unlock: 119 + if (!err) { 120 + rtnl_lock(); 121 + list_add_tail(&new_net->list, &net_namespace_list); 122 + rtnl_unlock(); 123 + } 144 124 mutex_unlock(&net_mutex); 125 + 126 + if (err) 127 + goto out_free; 145 128 out: 146 129 put_net(old_net); 147 - if (err) { 148 - net_free(new_net); 149 - new_net = ERR_PTR(err); 150 - } 151 130 return new_net; 131 + 132 + out_free: 133 + net_free(new_net); 134 + out_err: 135 + new_net = ERR_PTR(err); 136 + goto out; 152 137 } 153 138 154 139 static void cleanup_net(struct work_struct *work) ··· 205 188 206 189 static int __init net_ns_init(void) 207 190 { 191 + struct net_generic *ng; 208 192 int err; 209 193 210 194 printk(KERN_INFO "net_namespace: %zd bytes\n", sizeof(struct net)); ··· 219 201 if (!netns_wq) 220 202 panic("Could not create netns workq"); 221 203 #endif 204 + 205 + ng = net_alloc_generic(); 206 + if (!ng) 207 + panic("Could not allocate generic netns"); 208 + 209 + rcu_assign_pointer(init_net.gen, ng); 222 210 223 211 mutex_lock(&net_mutex); 224 212 err = setup_net(&init_net);