The function uip_tcp_socket_free() is called with the sk lock held, but then goes on to call uip_tcp_socket_close() which attempts to aquire the lock a second time, triggering a deadlock if there are outstanding TCP connections. Rename the existing uip_tcp_socket_close() to a _locked variety and removing the locking from it. Add a new uip_tcp_socket_close() which takes the lock and calls the _locked variety. Fixes: d87b503f4d6e ("net/uip: Add exit function") Signed-off-by: Steven Price --- v2: Rather than duplicate the cleanup in uip_tcp_socket_free() rejig the code to have two functions with one _locked. --- net/uip/tcp.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/net/uip/tcp.c b/net/uip/tcp.c index 8e0ad5235240..42e6e992cd6a 100644 --- a/net/uip/tcp.c +++ b/net/uip/tcp.c @@ -6,7 +6,7 @@ #include #include -static int uip_tcp_socket_close(struct uip_tcp_socket *sk, int how) +static int uip_tcp_socket_close_locked(struct uip_tcp_socket *sk, int how) { shutdown(sk->fd, how); @@ -14,9 +14,7 @@ static int uip_tcp_socket_close(struct uip_tcp_socket *sk, int how) shutdown(sk->fd, SHUT_RDWR); close(sk->fd); - mutex_lock(sk->lock); list_del(&sk->list); - mutex_unlock(sk->lock); free(sk->buf); free(sk); @@ -25,6 +23,17 @@ static int uip_tcp_socket_close(struct uip_tcp_socket *sk, int how) return 0; } +static int uip_tcp_socket_close(struct uip_tcp_socket *sk, int how) +{ + int ret; + + mutex_lock(sk->lock); + ret = uip_tcp_socket_close_locked(sk, how); + mutex_unlock(sk->lock); + + return ret; +} + static struct uip_tcp_socket *uip_tcp_socket_find(struct uip_tx_arg *arg, u32 sip, u32 dip, u16 sport, u16 dport) { struct list_head *sk_head; @@ -110,7 +119,7 @@ static void uip_tcp_socket_free(struct uip_tcp_socket *sk) } sk->write_done = sk->read_done = 1; - uip_tcp_socket_close(sk, SHUT_RDWR); + uip_tcp_socket_close_locked(sk, SHUT_RDWR); } static int uip_tcp_payload_send(struct uip_tcp_socket *sk, u8 flag, u16 payload_len) -- 2.43.0