| From stable-bounces@linux.kernel.org Mon Dec 10 20:32:35 2007 |
| From: Florian Zumbiehl <florz@florz.de> |
| Date: Tue, 11 Dec 2007 09:39:39 +0800 |
| Subject: UNIX: EOF on non-blocking SOCK_SEQPACKET |
| To: stable@kernel.org, bunk@kernel.org, <davem@davemloft.net> |
| Message-ID: <E1J1u5z-0002LQ-00@gondolin.me.apana.org.au> |
| |
| |
| From: Florian Zumbiehl <florz@florz.de> |
| |
| [UNIX]: EOF on non-blocking SOCK_SEQPACKET |
| |
| [ Upstream commit: 0a11225887fe6cbccd882404dc36ddc50f47daf9 ] |
| |
| I am not absolutely sure whether this actually is a bug (as in: I've got |
| no clue what the standards say or what other implementations do), but at |
| least I was pretty surprised when I noticed that a recv() on a |
| non-blocking unix domain socket of type SOCK_SEQPACKET (which is connection |
| oriented, after all) where the remote end has closed the connection |
| returned -1 (EAGAIN) rather than 0 to indicate end of file. |
| |
| This is a test case: |
| |
| | #include <sys/types.h> |
| | #include <unistd.h> |
| | #include <sys/socket.h> |
| | #include <sys/un.h> |
| | #include <fcntl.h> |
| | #include <string.h> |
| | #include <stdlib.h> |
| | |
| | int main(){ |
| | int sock; |
| | struct sockaddr_un addr; |
| | char buf[4096]; |
| | int pfds[2]; |
| | |
| | pipe(pfds); |
| | sock=socket(PF_UNIX,SOCK_SEQPACKET,0); |
| | addr.sun_family=AF_UNIX; |
| | strcpy(addr.sun_path,"/tmp/foobar_testsock"); |
| | bind(sock,(struct sockaddr *)&addr,sizeof(addr)); |
| | listen(sock,1); |
| | if(fork()){ |
| | close(sock); |
| | sock=socket(PF_UNIX,SOCK_SEQPACKET,0); |
| | connect(sock,(struct sockaddr *)&addr,sizeof(addr)); |
| | fcntl(sock,F_SETFL,fcntl(sock,F_GETFL)|O_NONBLOCK); |
| | close(pfds[1]); |
| | read(pfds[0],buf,sizeof(buf)); |
| | recv(sock,buf,sizeof(buf),0); // <-- this one |
| | }else accept(sock,NULL,NULL); |
| | exit(0); |
| | } |
| |
| If you try it, make sure /tmp/foobar_testsock doesn't exist. |
| |
| The marked recv() returns -1 (EAGAIN) on 2.6.23.9. Below you find a |
| patch that fixes that. |
| |
| Signed-off-by: Florian Zumbiehl <florz@florz.de> |
| Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| net/unix/af_unix.c | 9 ++++++++- |
| 1 file changed, 8 insertions(+), 1 deletion(-) |
| |
| --- a/net/unix/af_unix.c |
| +++ b/net/unix/af_unix.c |
| @@ -1632,8 +1632,15 @@ static int unix_dgram_recvmsg(struct kio |
| mutex_lock(&u->readlock); |
| |
| skb = skb_recv_datagram(sk, flags, noblock, &err); |
| - if (!skb) |
| + if (!skb) { |
| + unix_state_lock(sk); |
| + /* Signal EOF on disconnected non-blocking SEQPACKET socket. */ |
| + if (sk->sk_type == SOCK_SEQPACKET && err == -EAGAIN && |
| + (sk->sk_shutdown & RCV_SHUTDOWN)) |
| + err = 0; |
| + unix_state_unlock(sk); |
| goto out_unlock; |
| + } |
| |
| wake_up_interruptible(&u->peer_wait); |
| |