dccp: Unlock sock before calling sk_free()
Subsystems (3)
PATCH 1/2 dccp: Unlock sock before calling sk_free()
From: Arnaldo Carvalho de Melo <[email protected]>
The code where sk_clone() came from created a new socket and locked it, but then, on the error path didn't unlock it.
This problem stayed there for a long while, till b0691c8ee7c2 ("net:
Unlock sock before calling sk_free()") fixed it, but unfortunately the callers of sk_clone() (now sk_clone_locked()) were not audited and the one in dccp_create_openreq_child() remained.
Now in the age of the syskaller fuzzer, this was finally uncovered, as reported by Dmitry:
---- 8< ----
I've got the following report while running syzkaller fuzzer on 86292b33d4b7 ("Merge branch 'akpm' (patches from Andrew)")
[ BUG: held lock freed! ]
4.10.0+ #234 Not tainted
-------------------------
syz-executor6/6898 is freeing memory ffff88006286cac0-ffff88006286d3b7, with a lock still held there!
(slock-AF_INET6){+.-...}, at: [<ffffffff8362c2c9>] spin_lock
include/linux/spinlock.h:299 [inline]
(slock-AF_INET6){+.-...}, at: [<ffffffff8362c2c9>]
sk_clone_lock+0x3d9/0x12c0 net/core/sock.c:1504
5 locks held by syz-executor6/6898:
#0: (sk_lock-AF_INET6){+.+.+.}, at: [<ffffffff839a34b4>] lock_sock
include/net/sock.h:1460 [inline]
#0: (sk_lock-AF_INET6){+.+.+.}, at: [<ffffffff839a34b4>]
inet_stream_connect+0x44/0xa0 net/ipv4/af_inet.c:681
#1: (rcu_read_lock){......}, at: [<ffffffff83bc1c2a>]
inet6_csk_xmit+0x12a/0x5d0 net/ipv6/inet6_connection_sock.c:126
#2: (rcu_read_lock){......}, at: [<ffffffff8369b424>] __skb_unlink
include/linux/skbuff.h:1767 [inline]
#2: (rcu_read_lock){......}, at: [<ffffffff8369b424>] __skb_dequeue
include/linux/skbuff.h:1783 [inline]
#2: (rcu_read_lock){......}, at: [<ffffffff8369b424>]
process_backlog+0x264/0x730 net/core/dev.c:4835
#3: (rcu_read_lock){......}, at: [<ffffffff83aeb5c0>]
ip6_input_finish+0x0/0x1700 net/ipv6/ip6_input.c:59
#4: (slock-AF_INET6){+.-...}, at: [<ffffffff8362c2c9>] spin_lock
include/linux/spinlock.h:299 [inline]
#4: (slock-AF_INET6){+.-...}, at: [<ffffffff8362c2c9>]
sk_clone_lock+0x3d9/0x12c0 net/core/sock.c:1504Fix it just like was done by b0691c8ee7c2 ("net: Unlock sock before calling sk_free()").
--- net/dccp/minisocks.c | 1 + 1 file changed, 1 insertion(+)
net/dccp/minisocks.c +1 -0
@@ -122,6 +122,7 @@ struct sock *dccp_create_openreq_child(const struct sock *sk,/* It is still raw copy of parent, so invalidate * destructor and make plain sk_free() */ newsk->sk_destruct =NULL ; +bh_unlock_sock (newsk);sk_free (newsk);return NULL ; }
Signature · 1 line
2.9.3
PATCH 2/2 net: Introduce sk_clone_lock() error path routine
From: Arnaldo Carvalho de Melo <[email protected]>
When handling problems in cloning a socket with the sk_clone_locked() function we need to perform several steps that were open coded in it and its callers, so introduce a routine to avoid this duplication:sk_free_unlock_clone().
--- include/net/sock.h | 1 + net/core/sock.c | 16 +++++++++++----- net/dccp/minisocks.c | 6 +----- 3 files changed, 13 insertions(+), 10 deletions(-)
include/net/sock.h +1 -0
@@ -1520,6 +1520,7 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority,void sk_free (struct sock *sk);void sk_destruct (struct sock *sk);struct sock *sk_clone_lock (const struct sock *sk,const gfp_t priority); +void sk_free_unlock_clone (struct sock *sk);struct sk_buff *sock_wmalloc (struct sock *sk,unsigned long size,int force,gfp_t priority);
net/core/sock.c +11 -5
@@ -1540,11 +1540,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) is_charged =sk_filter_charge (newsk, filter);if (unlikely (!is_charged ||xfrm_sk_clone_policy (newsk, sk))) { -/* It is still raw copy of parent, so invalidate -* destructor and make plain sk_free() */ - newsk->sk_destruct =NULL ; -bh_unlock_sock (newsk); -sk_free (newsk); +sk_free_unlock_clone (newsk); newsk =NULL ; goto out; }
@@ -1593,6 +1589,16 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) }EXPORT_SYMBOL_GPL (sk_clone_lock); +void sk_free_unlock_clone (struct sock *sk) +{ +/* It is still raw copy of parent, so invalidate +* destructor and make plain sk_free() */ + sk->sk_destruct =NULL ; +bh_unlock_sock (sk); +sk_free (sk); +} +EXPORT_SYMBOL_GPL (sk_free_unlock_clone); +void sk_setup_caps (struct sock *sk,struct dst_entry *dst) {u32 max_segs =1 ;
net/dccp/minisocks.c +1 -5
@@ -119,11 +119,7 @@ struct sock *dccp_create_openreq_child(const struct sock *sk,* Activate features: initialise CCIDs, sequence windows etc. */ if (dccp_feat_activate_values (newsk, &dreq->dreq_featneg)) { -/* It is still raw copy of parent, so invalidate -* destructor and make plain sk_free() */ - newsk->sk_destruct =NULL ; -bh_unlock_sock (newsk); -sk_free (newsk); +sk_free_unlock_clone (newsk);return NULL ; }dccp_init_xmit_timers (newsk);
Signature · 1 line
2.9.3
Re: [PATCH 2/2] net: Introduce sk_clone_lock() error path routine
From: Arnaldo Carvalho de Melo <[email protected]>
Date: Wed, 1 Mar 2017 16:35:08 -0300
Quoted 7 lines
From: Arnaldo Carvalho de Melo <[email protected]>
When handling problems in cloning a socket with the
sk_clone_locked()function we need to perform several steps that were open coded in it and its callers, so introduce a routine to avoid this duplication:sk_free_unlock_clone().
Quoted 7 lines
Cc Cong Wang <[email protected]>Cc Dmitry Vyukov <[email protected]>Cc Eric Dumazet <[email protected]>Cc Gerrit Renker <[email protected]>Cc Thomas Gleixner <[email protected]>Signed-off-by Arnaldo Carvalho de Melo <[email protected]>
Applied.
Re: [PATCH 2/2] net: Introduce sk_clone_lock() error path routine
In reply to Arnaldo Carvalho de MeloHello!
Quoted 14 lines · Arnaldo Carvalho de Melo
From: Arnaldo Carvalho de Melo <[email protected]>
When handling problems in cloning a socket with the
sk_clone_locked()function we need to perform several steps that were open coded in it and its callers, so introduce a routine to avoid this duplication:sk_free_unlock_clone().Cc Cong Wang <[email protected]>Cc Dmitry Vyukov <[email protected]>Cc Eric Dumazet <[email protected]>Cc Gerrit Renker <[email protected]>Cc Thomas Gleixner <[email protected]>Signed-off-by Arnaldo Carvalho de Melo <[email protected]>
[...]
Quoted 18 lines
net/core/sock.c +1
-5@@ -1540,11 +1540,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) is_charged =sk_filter_charge (newsk, filter);if (unlikely (!is_charged ||xfrm_sk_clone_policy (newsk, sk))) { -/* It is still raw copy of parent, so invalidate -* destructor and make plain sk_free() */ - newsk->sk_destruct =NULL ; -bh_unlock_sock (newsk); -sk_free (newsk); +sk_free_unlock_clone (newsk); newsk =NULL ; goto out; }
net/core/sock.c struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) · line 1595
Quoted 7 lines
net/core/sock.c +4
-0@@ -1593,6 +1589,16 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) }EXPORT_SYMBOL_GPL (sk_clone_lock); +void sk_free_unlock_clone (struct sock *sk) +{ +/* It is still raw copy of parent, so invalidate +* destructor and make plain sk_free() */
Could fix the comment style to the preferred one, while at it:
/* bla
* bla
*/
net/core/sock.c struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) · line 1604
Quoted 9 lines
net/core/sock.c +6
-0+ sk->sk_destruct =NULL ; +bh_unlock_sock (sk); +sk_free (sk); +} +EXPORT_SYMBOL_GPL (sk_free_unlock_clone); +void sk_setup_caps (struct sock *sk,struct dst_entry *dst) {u32 max_segs =1 ;
[...]
MBR, Sergei
David Miller
maintainerFrom: Arnaldo Carvalho de Melo <[email protected]>
Date: Wed, 1 Mar 2017 16:35:07 -0300
Quoted 12 lines
From: Arnaldo Carvalho de Melo <[email protected]>
The code where
sk_clone()came from created a new socket and locked it, but then, on the error path didn't unlock it.This problem stayed there for a long while, till
b0691c8ee7c2("net:
Unlock sock before callingsk_free()") fixed it, but unfortunately the callers ofsk_clone()(nowsk_clone_locked()) were not audited and the one indccp_create_openreq_child()remained.Now in the age of the syskaller fuzzer, this was finally uncovered, as reported by Dmitry:
...
Quoted 10 lines
Fix it just like was done by
b0691c8ee7c2("net: Unlock sock before callingsk_free()").Reported-by Dmitry Vyukov <[email protected]>Cc Cong Wang <[email protected]>Cc Eric Dumazet <[email protected]>Cc Gerrit Renker <[email protected]>Cc Thomas Gleixner <[email protected]>Signed-off-by Arnaldo Carvalho de Melo <[email protected]>
Applied and queued up for -stable.