aboutsummaryrefslogtreecommitdiffstats
path: root/net/unix/af_unix.c
diff options
context:
space:
mode:
authorBenjamin Poirier <bpoirier@suse.de>2013-04-29 07:42:14 -0400
committerDavid S. Miller <davem@davemloft.net>2013-04-30 00:43:54 -0400
commit79f632c71bea0d0864d84d6a4ce78da5a9430f5b (patch)
tree4a2aecd119c9c54944182ba665ad8279232e40ab /net/unix/af_unix.c
parent39cc86130bc045d87f525ce7742da308ff757cec (diff)
unix/stream: fix peeking with an offset larger than data in queue
Currently, peeking on a unix stream socket with an offset larger than len of the data in the sk receive queue returns immediately with bogus data. This patch fixes this so that the behavior is the same as peeking with no offset on an empty queue: the caller blocks. Signed-off-by: Benjamin Poirier <bpoirier@suse.de> Acked-by: Eric Dumazet <edumazet@google.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.c25
1 files changed, 12 insertions, 13 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 2db702d82e7d..1a02af0e3049 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1859,10 +1859,10 @@ out:
1859} 1859}
1860 1860
1861/* 1861/*
1862 * Sleep until data has arrive. But check for races.. 1862 * Sleep until more data has arrived. But check for races..
1863 */ 1863 */
1864 1864static long unix_stream_data_wait(struct sock *sk, long timeo,
1865static long unix_stream_data_wait(struct sock *sk, long timeo) 1865 struct sk_buff *last)
1866{ 1866{
1867 DEFINE_WAIT(wait); 1867 DEFINE_WAIT(wait);
1868 1868
@@ -1871,7 +1871,7 @@ static long unix_stream_data_wait(struct sock *sk, long timeo)
1871 for (;;) { 1871 for (;;) {
1872 prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 1872 prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
1873 1873
1874 if (!skb_queue_empty(&sk->sk_receive_queue) || 1874 if (skb_peek_tail(&sk->sk_receive_queue) != last ||
1875 sk->sk_err || 1875 sk->sk_err ||
1876 (sk->sk_shutdown & RCV_SHUTDOWN) || 1876 (sk->sk_shutdown & RCV_SHUTDOWN) ||
1877 signal_pending(current) || 1877 signal_pending(current) ||
@@ -1890,8 +1890,6 @@ static long unix_stream_data_wait(struct sock *sk, long timeo)
1890 return timeo; 1890 return timeo;
1891} 1891}
1892 1892
1893
1894
1895static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, 1893static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
1896 struct msghdr *msg, size_t size, 1894 struct msghdr *msg, size_t size,
1897 int flags) 1895 int flags)
@@ -1936,14 +1934,12 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
1936 goto out; 1934 goto out;
1937 } 1935 }
1938 1936
1939 skip = sk_peek_offset(sk, flags);
1940
1941 do { 1937 do {
1942 int chunk; 1938 int chunk;
1943 struct sk_buff *skb; 1939 struct sk_buff *skb, *last;
1944 1940
1945 unix_state_lock(sk); 1941 unix_state_lock(sk);
1946 skb = skb_peek(&sk->sk_receive_queue); 1942 last = skb = skb_peek(&sk->sk_receive_queue);
1947again: 1943again:
1948 if (skb == NULL) { 1944 if (skb == NULL) {
1949 unix_sk(sk)->recursion_level = 0; 1945 unix_sk(sk)->recursion_level = 0;
@@ -1966,7 +1962,7 @@ again:
1966 break; 1962 break;
1967 mutex_unlock(&u->readlock); 1963 mutex_unlock(&u->readlock);
1968 1964
1969 timeo = unix_stream_data_wait(sk, timeo); 1965 timeo = unix_stream_data_wait(sk, timeo, last);
1970 1966
1971 if (signal_pending(current) 1967 if (signal_pending(current)
1972 || mutex_lock_interruptible(&u->readlock)) { 1968 || mutex_lock_interruptible(&u->readlock)) {
@@ -1980,10 +1976,13 @@ again:
1980 break; 1976 break;
1981 } 1977 }
1982 1978
1983 if (skip >= skb->len) { 1979 skip = sk_peek_offset(sk, flags);
1980 while (skip >= skb->len) {
1984 skip -= skb->len; 1981 skip -= skb->len;
1982 last = skb;
1985 skb = skb_peek_next(skb, &sk->sk_receive_queue); 1983 skb = skb_peek_next(skb, &sk->sk_receive_queue);
1986 goto again; 1984 if (!skb)
1985 goto again;
1987 } 1986 }
1988 1987
1989 unix_state_unlock(sk); 1988 unix_state_unlock(sk);