From 92a0acce186cde8ead56c6915d9479773673ea1a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 17 Feb 2009 21:24:05 -0800 Subject: net: Kill skb_truesize_check(), it only catches false-positives. A long time ago we had bugs, primarily in TCP, where we would modify skb->truesize (for TSO queue collapsing) in ways which would corrupt the socket memory accounting. skb_truesize_check() was added in order to try and catch this error more systematically. However this debugging check has morphed into a Frankenstein of sorts and these days it does nothing other than catch false-positives. Signed-off-by: David S. Miller --- net/core/skbuff.c | 8 -------- net/core/sock.c | 1 - 2 files changed, 9 deletions(-) (limited to 'net/core') diff --git a/net/core/skbuff.c b/net/core/skbuff.c index da74b844f4ea..c6a6b166f8d6 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -143,14 +143,6 @@ void skb_under_panic(struct sk_buff *skb, int sz, void *here) BUG(); } -void skb_truesize_bug(struct sk_buff *skb) -{ - WARN(net_ratelimit(), KERN_ERR "SKB BUG: Invalid truesize (%u) " - "len=%u, sizeof(sk_buff)=%Zd\n", - skb->truesize, skb->len, sizeof(struct sk_buff)); -} -EXPORT_SYMBOL(skb_truesize_bug); - /* Allocate a new skbuff. We do this ourselves so we can fill in a few * 'private' fields and also do memory statistics to find all the * [BEEP] leaks. diff --git a/net/core/sock.c b/net/core/sock.c index 6f2e1337975d..6e4f14d1ef81 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1137,7 +1137,6 @@ void sock_rfree(struct sk_buff *skb) { struct sock *sk = skb->sk; - skb_truesize_check(skb); atomic_sub(skb->truesize, &sk->sk_rmem_alloc); sk_mem_uncharge(skb->sk, skb->truesize); } -- cgit v1.2.1 From 486a87f1e5624096bd1c09e9e716239597d48dca Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Sun, 22 Feb 2009 00:07:53 -0800 Subject: 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 Signed-off-by: David S. Miller --- net/core/net_namespace.c | 86 +++++++++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 31 deletions(-) (limited to 'net/core') diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 55151faaf90c..b0767abf23e5 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -32,24 +32,14 @@ static __net_init int setup_net(struct net *net) { /* Must be called with net_mutex held */ struct pernet_operations *ops; - int error; - struct net_generic *ng; + int error = 0; atomic_set(&net->count, 1); + #ifdef NETNS_REFCNT_DEBUG atomic_set(&net->use_count, 0); #endif - error = -ENOMEM; - ng = kzalloc(sizeof(struct net_generic) + - INITIAL_NET_GEN_PTRS * sizeof(void *), GFP_KERNEL); - if (ng == NULL) - goto out; - - ng->len = INITIAL_NET_GEN_PTRS; - rcu_assign_pointer(net->gen, ng); - - error = 0; list_for_each_entry(ops, &pernet_list, list) { if (ops->init) { error = ops->init(net); @@ -70,7 +60,6 @@ out_undo: } rcu_barrier(); - kfree(ng); goto out; } @@ -78,16 +67,43 @@ out_undo: static struct kmem_cache *net_cachep; static struct workqueue_struct *netns_wq; -static struct net *net_alloc(void) +static struct net_generic *net_alloc_generic(void) { - return kmem_cache_zalloc(net_cachep, GFP_KERNEL); + struct net_generic *ng; + size_t generic_size = sizeof(struct net_generic) + + INITIAL_NET_GEN_PTRS * sizeof(void *); + + ng = kzalloc(generic_size, GFP_KERNEL); + if (ng) + ng->len = INITIAL_NET_GEN_PTRS; + + return ng; } -static void net_free(struct net *net) +static struct net *net_alloc(void) { + struct net *net = NULL; + struct net_generic *ng; + + ng = net_alloc_generic(); + if (!ng) + goto out; + + net = kmem_cache_zalloc(net_cachep, GFP_KERNEL); if (!net) - return; + goto out_free; + + rcu_assign_pointer(net->gen, ng); +out: + return net; + +out_free: + kfree(ng); + goto out; +} +static void net_free(struct net *net) +{ #ifdef NETNS_REFCNT_DEBUG if (unlikely(atomic_read(&net->use_count) != 0)) { printk(KERN_EMERG "network namespace not free! Usage: %d\n", @@ -112,27 +128,28 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net) err = -ENOMEM; new_net = net_alloc(); if (!new_net) - goto out; + goto out_err; mutex_lock(&net_mutex); err = setup_net(new_net); - if (err) - goto out_unlock; - - rtnl_lock(); - list_add_tail(&new_net->list, &net_namespace_list); - rtnl_unlock(); - - -out_unlock: + if (!err) { + rtnl_lock(); + list_add_tail(&new_net->list, &net_namespace_list); + rtnl_unlock(); + } mutex_unlock(&net_mutex); + + if (err) + goto out_free; out: put_net(old_net); - if (err) { - net_free(new_net); - new_net = ERR_PTR(err); - } return new_net; + +out_free: + net_free(new_net); +out_err: + new_net = ERR_PTR(err); + goto out; } static void cleanup_net(struct work_struct *work) @@ -188,6 +205,7 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net) static int __init net_ns_init(void) { + struct net_generic *ng; int err; printk(KERN_INFO "net_namespace: %zd bytes\n", sizeof(struct net)); @@ -202,6 +220,12 @@ static int __init net_ns_init(void) panic("Could not create netns workq"); #endif + ng = net_alloc_generic(); + if (!ng) + panic("Could not allocate generic netns"); + + rcu_assign_pointer(init_net.gen, ng); + mutex_lock(&net_mutex); err = setup_net(&init_net); -- cgit v1.2.1 From ebe47d47b7b7fed72dabcce4717da727b4e2367d Mon Sep 17 00:00:00 2001 From: Clemens Noss Date: Mon, 23 Feb 2009 15:37:35 -0800 Subject: netns: build fix for net_alloc_generic net_alloc_generic was defined in #ifdef CONFIG_NET_NS, but used unconditionally. Move net_alloc_generic out of #ifdef. Signed-off-by: Clemens Noss Signed-off-by: David S. Miller --- net/core/net_namespace.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net/core') diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index b0767abf23e5..2adb1a7d361f 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -63,10 +63,6 @@ out_undo: goto out; } -#ifdef CONFIG_NET_NS -static struct kmem_cache *net_cachep; -static struct workqueue_struct *netns_wq; - static struct net_generic *net_alloc_generic(void) { struct net_generic *ng; @@ -80,6 +76,10 @@ static struct net_generic *net_alloc_generic(void) return ng; } +#ifdef CONFIG_NET_NS +static struct kmem_cache *net_cachep; +static struct workqueue_struct *netns_wq; + static struct net *net_alloc(void) { struct net *net = NULL; -- cgit v1.2.1 From 50fee1dec5d71b8a14c1b82f2f42e16adc227f8b Mon Sep 17 00:00:00 2001 From: Eugene Teo Date: Mon, 23 Feb 2009 15:38:41 -0800 Subject: net: amend the fix for SO_BSDCOMPAT gsopt infoleak The fix for CVE-2009-0676 (upstream commit df0bca04) is incomplete. Note that the same problem of leaking kernel memory will reappear if someone on some architecture uses struct timeval with some internal padding (for example tv_sec 64-bit and tv_usec 32-bit) --- then, you are going to leak the padded bytes to userspace. Signed-off-by: Eugene Teo Reported-by: Mikulas Patocka Signed-off-by: David S. Miller --- net/core/sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/core') diff --git a/net/core/sock.c b/net/core/sock.c index 6e4f14d1ef81..5f97caa158e8 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -696,7 +696,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, if (len < 0) return -EINVAL; - v.val = 0; + memset(&v, 0, sizeof(v)); switch(optname) { case SO_DEBUG: -- cgit v1.2.1