diff options
| author | Eric Dumazet <edumazet@google.com> | 2014-03-26 05:42:27 +0400 | 
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2014-03-27 01:05:40 +0400 | 
| commit | de1443916791d75fdd26becb116898277bb0273f (patch) | |
| tree | 26fa8bd2f7ea36df46746a2b57e48f3247733d13 /net/unix/af_unix.c | |
| parent | dc0fe58f356b109c662c6c85562460b0e8be9f5f (diff) | |
| download | linux-de1443916791d75fdd26becb116898277bb0273f.tar.xz | |
net: unix: non blocking recvmsg() should not return -EINTR
Some applications didn't expect recvmsg() on a non blocking socket
could return -EINTR. This possibility was added as a side effect
of commit b3ca9b02b00704 ("net: fix multithreaded signal handling in
unix recv routines").
To hit this bug, you need to be a bit unlucky, as the u->readlock
mutex is usually held for very small periods.
Fixes: b3ca9b02b00704 ("net: fix multithreaded signal handling in unix recv routines")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Rainer Weikusat <rweikusat@mobileactivedefense.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/unix/af_unix.c')
| -rw-r--r-- | net/unix/af_unix.c | 17 | 
1 files changed, 12 insertions, 5 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index ce6ec6c2f4de..94404f19f9de 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1787,8 +1787,11 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,  		goto out;  	err = mutex_lock_interruptible(&u->readlock); -	if (err) { -		err = sock_intr_errno(sock_rcvtimeo(sk, noblock)); +	if (unlikely(err)) { +		/* recvmsg() in non blocking mode is supposed to return -EAGAIN +		 * sk_rcvtimeo is not honored by mutex_lock_interruptible() +		 */ +		err = noblock ? -EAGAIN : -ERESTARTSYS;  		goto out;  	} @@ -1913,6 +1916,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,  	struct unix_sock *u = unix_sk(sk);  	DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, msg->msg_name);  	int copied = 0; +	int noblock = flags & MSG_DONTWAIT;  	int check_creds = 0;  	int target;  	int err = 0; @@ -1928,7 +1932,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,  		goto out;  	target = sock_rcvlowat(sk, flags&MSG_WAITALL, size); -	timeo = sock_rcvtimeo(sk, flags&MSG_DONTWAIT); +	timeo = sock_rcvtimeo(sk, noblock);  	/* Lock the socket to prevent queue disordering  	 * while sleeps in memcpy_tomsg @@ -1940,8 +1944,11 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,  	}  	err = mutex_lock_interruptible(&u->readlock); -	if (err) { -		err = sock_intr_errno(timeo); +	if (unlikely(err)) { +		/* recvmsg() in non blocking mode is supposed to return -EAGAIN +		 * sk_rcvtimeo is not honored by mutex_lock_interruptible() +		 */ +		err = noblock ? -EAGAIN : -ERESTARTSYS;  		goto out;  	}  | 
