From dd981ab091cde09bb9eb23c8d81305ba615ee30c Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Wed, 3 Apr 2013 10:14:20 +0200 Subject: batman-adv: use the proper header len when checking the TTVN Unicast packet might be of type either UNICAST or UNICAST4ADDR. In the two cases the header size is different, but the mechanism checking the TTVN field was assuming it to be always of the same type (UNICAST), so failing to access the inner Ethernet header in case of UNICAST4ADDR. Fix this by passing the real header length as argument. Signed-off-by: Antonio Quartulli Signed-off-by: Marek Lindner --- net/batman-adv/routing.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 319f2906c71a..7de033667ebc 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -924,7 +924,7 @@ out: } static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, - struct sk_buff *skb) { + struct sk_buff *skb, int hdr_len) { uint8_t curr_ttvn, old_ttvn; struct batadv_orig_node *orig_node; struct ethhdr *ethhdr; @@ -933,7 +933,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, int is_old_ttvn; /* check if there is enough data before accessing it */ - if (pskb_may_pull(skb, sizeof(*unicast_packet) + ETH_HLEN) < 0) + if (pskb_may_pull(skb, hdr_len + ETH_HLEN) < 0) return 0; /* create a copy of the skb (in case of for re-routing) to modify it. */ @@ -941,7 +941,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, return 0; unicast_packet = (struct batadv_unicast_packet *)skb->data; - ethhdr = (struct ethhdr *)(skb->data + sizeof(*unicast_packet)); + ethhdr = (struct ethhdr *)(skb->data + hdr_len); /* check if the destination client was served by this node and it is now * roaming. In this case, it means that the node has got a ROAM_ADV @@ -1048,8 +1048,7 @@ int batadv_recv_unicast_packet(struct sk_buff *skb, if (batadv_check_unicast_packet(bat_priv, skb, hdr_size) < 0) return NET_RX_DROP; - - if (!batadv_check_unicast_ttvn(bat_priv, skb)) + if (!batadv_check_unicast_ttvn(bat_priv, skb, hdr_size)) return NET_RX_DROP; /* packet for me */ @@ -1093,7 +1092,7 @@ int batadv_recv_ucast_frag_packet(struct sk_buff *skb, if (batadv_check_unicast_packet(bat_priv, skb, hdr_size) < 0) return NET_RX_DROP; - if (!batadv_check_unicast_ttvn(bat_priv, skb)) + if (!batadv_check_unicast_ttvn(bat_priv, skb, hdr_size)) return NET_RX_DROP; unicast_packet = (struct batadv_unicast_frag_packet *)skb->data; -- cgit v1.2.3 From fccc9f1fa878d9599aa583f0fec3bca95639667d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 22 Apr 2013 20:22:15 +0000 Subject: appletalk: info leak in ->getname() There is a one byte hole between ->sat_port and ->sat_addr. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- net/appletalk/ddp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 4a141e3cf076..ef12839a7cfe 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1253,7 +1253,7 @@ static int atalk_getname(struct socket *sock, struct sockaddr *uaddr, goto out; *uaddr_len = sizeof(struct sockaddr_at); - memset(&sat.sat_zero, 0, sizeof(sat.sat_zero)); + memset(&sat, 0, sizeof(sat)); if (peer) { err = -ENOTCONN; -- cgit v1.2.3 From 7a3b68434b1b5fb7b9a6184efb26822cd1a54cc8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 22 Apr 2013 20:22:51 +0000 Subject: netrom: info leak in ->getname() The sockaddr_ax25 struct has a 3 byte hole between ->sax25_call and ->sax25_ndigis. I've added a memset to avoid leaking uninitialized stack data to userspace. Signed-off-by: Dan Carpenter Acked-by: Ralf Baechle Signed-off-by: David S. Miller --- net/netrom/af_netrom.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 103bd704b5fc..ec0c80fde69f 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -834,6 +834,8 @@ static int nr_getname(struct socket *sock, struct sockaddr *uaddr, struct sock *sk = sock->sk; struct nr_sock *nr = nr_sk(sk); + memset(&sax->fsa_ax25, 0, sizeof(struct sockaddr_ax25)); + lock_sock(sk); if (peer != 0) { if (sk->sk_state != TCP_ESTABLISHED) { -- cgit v1.2.3 From 5ffedc6ed3d066f5c0d2c2106f9081170b3d24fa Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 22 Apr 2013 20:24:52 +0000 Subject: NFC: llcp: two bugs in ->getname() The sockaddr_nfc_llcp struct has as hole between ->sa_family and ->dev_idx so I've added a memset() to clear it and prevent an information leak. Also the ->nfc_protocol element wasn't set so I've added that. "uaddr->sa_family" and "llcp_addr->sa_family" are the same thing but it's less confusing to use llcp_addr consistently throughout. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- net/nfc/llcp/sock.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index 6c94447ec414..e16315719eaf 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -358,12 +358,13 @@ static int llcp_sock_getname(struct socket *sock, struct sockaddr *uaddr, pr_debug("%p %d %d %d\n", sk, llcp_sock->target_idx, llcp_sock->dsap, llcp_sock->ssap); - uaddr->sa_family = AF_NFC; - + memset(llcp_addr, 0, sizeof(*llcp_addr)); *len = sizeof(struct sockaddr_nfc_llcp); + llcp_addr->sa_family = AF_NFC; llcp_addr->dev_idx = llcp_sock->dev->idx; llcp_addr->target_idx = llcp_sock->target_idx; + llcp_addr->nfc_protocol = llcp_sock->nfc_protocol; llcp_addr->dsap = llcp_sock->dsap; llcp_addr->ssap = llcp_sock->ssap; llcp_addr->service_name_len = llcp_sock->service_name_len; -- cgit v1.2.3 From 6ad0b2f7fdfd95fe3107367f8aed252e94c3f654 Mon Sep 17 00:00:00 2001 From: Asias He Date: Tue, 23 Apr 2013 20:33:52 +0000 Subject: VSOCK: Fix misc device registration When we call vsock_core_init to init VSOCK the second time, vsock_device.minor still points to the old dynamically allocated minor number. misc_register will allocate it for us successfully as if we were asking for a static one. However, when other user call misc_register to allocate a dynamic minor number, it will give the one used by vsock_core_init(), causing this: [ 405.470687] WARNING: at fs/sysfs/dir.c:536 sysfs_add_one+0xcc/0xf0() [ 405.470689] Hardware name: OptiPlex 790 [ 405.470690] sysfs: cannot create duplicate filename '/dev/char/10:54' Always set vsock_device.minor to MISC_DYNAMIC_MINOR before we register. Cc: "David S. Miller" Cc: Andy King Cc: Dmitry Torokhov Cc: Reilly Grant Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Asias He Acked-by: Dmitry Torokhov Signed-off-by: David S. Miller --- net/vmw_vsock/af_vsock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index 7f93e2a42d7a..4b4db18ba92c 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -1932,7 +1932,6 @@ static const struct file_operations vsock_device_ops = { static struct miscdevice vsock_device = { .name = "vsock", - .minor = MISC_DYNAMIC_MINOR, .fops = &vsock_device_ops, }; @@ -1942,6 +1941,7 @@ static int __vsock_core_init(void) vsock_init_tables(); + vsock_device.minor = MISC_DYNAMIC_MINOR; err = misc_register(&vsock_device); if (err) { pr_err("Failed to register misc device\n"); -- cgit v1.2.3 From 22ee3b57c3ff71772b0c4178404b04f5df78d501 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 23 Apr 2013 23:40:55 +0000 Subject: VSOCK: Drop bogus __init annotation from vsock_init_tables() If gcc (e.g. 4.1.2) decides not to inline vsock_init_tables(), this will cause a section mismatch: WARNING: net/vmw_vsock/vsock.o(.text+0x1bc): Section mismatch in reference from the function __vsock_core_init() to the function .init.text:vsock_init_tables() The function __vsock_core_init() references the function __init vsock_init_tables(). This is often because __vsock_core_init lacks a __init annotation or the annotation of vsock_init_tables is wrong. This may cause crashes if VSOCKETS=y and VMWARE_VMCI_VSOCKETS=m. Signed-off-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- net/vmw_vsock/af_vsock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index 4b4db18ba92c..3f77f42a3b58 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -165,7 +165,7 @@ static struct list_head vsock_bind_table[VSOCK_HASH_SIZE + 1]; static struct list_head vsock_connected_table[VSOCK_HASH_SIZE]; static DEFINE_SPINLOCK(vsock_table_lock); -static __init void vsock_init_tables(void) +static void vsock_init_tables(void) { int i; -- cgit v1.2.3 From f7a1dd6e3ad59f0cfd51da29dfdbfd54122c5916 Mon Sep 17 00:00:00 2001 From: Hans Schillstrom Date: Sat, 27 Apr 2013 20:06:14 +0200 Subject: ipvs: ip_vs_sip_fill_param() BUG: bad check of return value The reason for this patch is crash in kmemdup caused by returning from get_callid with uniialized matchoff and matchlen. Removing Zero check of matchlen since it's done by ct_sip_get_header() BUG: unable to handle kernel paging request at ffff880457b5763f IP: [] kmemdup+0x2e/0x35 PGD 27f6067 PUD 0 Oops: 0000 [#1] PREEMPT SMP Modules linked in: xt_state xt_helper nf_conntrack_ipv6 nf_defrag_ipv6 ip6table_mangle xt_connmark xt_conntrack ip6_tables nf_conntrack_ftp ip_vs_ftp nf_nat xt_tcpudp iptable_mangle xt_mark ip_tables x_tables ip_vs_rr ip_vs_lblcr ip_vs_pe_sip ip_vs nf_conntrack_sip nf_conntrack bonding igb i2c_algo_bit i2c_core CPU 5 Pid: 0, comm: swapper/5 Not tainted 3.9.0-rc5+ #5 /S1200KP RIP: 0010:[] [] kmemdup+0x2e/0x35 RSP: 0018:ffff8803fea03648 EFLAGS: 00010282 RAX: ffff8803d61063e0 RBX: 0000000000000003 RCX: 0000000000000003 RDX: 0000000000000003 RSI: ffff880457b5763f RDI: ffff8803d61063e0 RBP: ffff8803fea03658 R08: 0000000000000008 R09: 0000000000000011 R10: 0000000000000011 R11: 00ffffffff81a8a3 R12: ffff880457b5763f R13: ffff8803d67f786a R14: ffff8803fea03730 R15: ffffffffa0098e90 FS: 0000000000000000(0000) GS:ffff8803fea00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffff880457b5763f CR3: 0000000001a0c000 CR4: 00000000001407e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process swapper/5 (pid: 0, threadinfo ffff8803ee18c000, task ffff8803ee18a480) Stack: ffff8803d822a080 000000000000001c ffff8803fea036c8 ffffffffa000937a ffffffff81f0d8a0 000000038135fdd5 ffff880300000014 ffff880300110000 ffffffff150118ac ffff8803d7e8a000 ffff88031e0118ac 0000000000000000 Call Trace: [] ip_vs_sip_fill_param+0x13a/0x187 [ip_vs_pe_sip] [] ip_vs_sched_persist+0x2c6/0x9c3 [ip_vs] [] ? __lock_acquire+0x677/0x1697 [] ? native_sched_clock+0x3c/0x7d [] ? native_sched_clock+0x3c/0x7d [] ? sched_clock_cpu+0x43/0xcf [] ip_vs_schedule+0x181/0x4ba [ip_vs] ... Signed-off-by: Hans Schillstrom Acked-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: David S. Miller --- net/netfilter/ipvs/ip_vs_pe_sip.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'net') diff --git a/net/netfilter/ipvs/ip_vs_pe_sip.c b/net/netfilter/ipvs/ip_vs_pe_sip.c index 12475ef88daf..e5920fb7ad01 100644 --- a/net/netfilter/ipvs/ip_vs_pe_sip.c +++ b/net/netfilter/ipvs/ip_vs_pe_sip.c @@ -37,14 +37,10 @@ static int get_callid(const char *dptr, unsigned int dataoff, if (ret > 0) break; if (!ret) - return 0; + return -EINVAL; dataoff += *matchoff; } - /* Empty callid is useless */ - if (!*matchlen) - return -EINVAL; - /* Too large is useless */ if (*matchlen > IP_VS_PEDATA_MAXLEN) return -EINVAL; -- cgit v1.2.3 From 2c1bbbffa0b644fab4f91878cde0c2e8f52e2dcc Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Thu, 25 Apr 2013 00:49:55 +0000 Subject: net: mac802154: comparision issue of type cast, finding by EXTRA_CFLAGS=-W Change MAC802154_CHAN_NONE from ~(u8)0 to 0xff, or the comparison in mac802154_wpan_xmit() for ``chan == MAC802154_CHAN_NONE'' will not succeed. This bug can be boiled down to ``u8 foo = 0xff; if (foo == ~(u8)0) [...] else [...]'' where the condition will always take the else branch. Signed-off-by: Chen Gang Signed-off-by: David S. Miller --- net/mac802154/mac802154.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac802154/mac802154.h b/net/mac802154/mac802154.h index a4dcaf1dd4b6..703c1210d223 100644 --- a/net/mac802154/mac802154.h +++ b/net/mac802154/mac802154.h @@ -90,7 +90,7 @@ struct mac802154_sub_if_data { #define MAC802154_MAX_XMIT_ATTEMPTS 3 -#define MAC802154_CHAN_NONE (~(u8)0) /* No channel is assigned */ +#define MAC802154_CHAN_NONE 0xff /* No channel is assigned */ extern struct ieee802154_reduced_mlme_ops mac802154_mlme_reduced; extern struct ieee802154_mlme_ops mac802154_mlme_wpan; -- cgit v1.2.3 From add05ad4e9f5c4efee9b98535db5efa32b0d0492 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Mon, 29 Apr 2013 11:42:12 +0000 Subject: unix/dgram: peek beyond 0-sized skbs "77c1090 net: fix infinite loop in __skb_recv_datagram()" (v3.8) introduced a regression: After that commit, recv can no longer peek beyond a 0-sized skb in the queue. __skb_recv_datagram() instead stops at the first skb with len == 0 and results in the system call failing with -EFAULT via skb_copy_datagram_iovec(). When peeking at an offset with 0-sized skb(s), each one of those is received only once, in sequence. The offset starts moving forward again after receiving datagrams with len > 0. Signed-off-by: Benjamin Poirier Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/datagram.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/core/datagram.c b/net/core/datagram.c index 368f9c3f9dc6..99c4f525b1d9 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -187,7 +187,8 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags, skb_queue_walk(queue, skb) { *peeked = skb->peeked; if (flags & MSG_PEEK) { - if (*off >= skb->len && skb->len) { + if (*off >= skb->len && (skb->len || *off || + skb->peeked)) { *off -= skb->len; continue; } -- cgit v1.2.3 From 39cc86130bc045d87f525ce7742da308ff757cec Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Mon, 29 Apr 2013 11:42:13 +0000 Subject: unix/dgram: fix peeking with an offset larger than data in queue Currently, peeking on a unix datagram socket with an offset larger than len of the data in the sk receive queue returns immediately with bogus data. That's because *off is not reset between each skb_queue_walk(). 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 Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/datagram.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/core/datagram.c b/net/core/datagram.c index 99c4f525b1d9..b5d48ac2a9c1 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -78,9 +78,10 @@ static int receiver_wake_function(wait_queue_t *wait, unsigned int mode, int syn return autoremove_wake_function(wait, mode, sync, key); } /* - * Wait for a packet.. + * Wait for the last received packet to be different from skb */ -static int wait_for_packet(struct sock *sk, int *err, long *timeo_p) +static int wait_for_more_packets(struct sock *sk, int *err, long *timeo_p, + const struct sk_buff *skb) { int error; DEFINE_WAIT_FUNC(wait, receiver_wake_function); @@ -92,7 +93,7 @@ static int wait_for_packet(struct sock *sk, int *err, long *timeo_p) if (error) goto out_err; - if (!skb_queue_empty(&sk->sk_receive_queue)) + if (sk->sk_receive_queue.prev != skb) goto out; /* Socket shut down? */ @@ -131,9 +132,9 @@ out_noerr: * __skb_recv_datagram - Receive a datagram skbuff * @sk: socket * @flags: MSG_ flags + * @peeked: returns non-zero if this packet has been seen before * @off: an offset in bytes to peek skb from. Returns an offset * within an skb where data actually starts - * @peeked: returns non-zero if this packet has been seen before * @err: error code returned * * Get a datagram skbuff, understands the peeking, nonblocking wakeups @@ -161,7 +162,7 @@ out_noerr: struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags, int *peeked, int *off, int *err) { - struct sk_buff *skb; + struct sk_buff *skb, *last; long timeo; /* * Caller is allowed not to check sk->sk_err before skb_recv_datagram() @@ -182,14 +183,17 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags, */ unsigned long cpu_flags; struct sk_buff_head *queue = &sk->sk_receive_queue; + int _off = *off; + last = (struct sk_buff *)queue; spin_lock_irqsave(&queue->lock, cpu_flags); skb_queue_walk(queue, skb) { + last = skb; *peeked = skb->peeked; if (flags & MSG_PEEK) { - if (*off >= skb->len && (skb->len || *off || + if (_off >= skb->len && (skb->len || _off || skb->peeked)) { - *off -= skb->len; + _off -= skb->len; continue; } skb->peeked = 1; @@ -198,6 +202,7 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags, __skb_unlink(skb, queue); spin_unlock_irqrestore(&queue->lock, cpu_flags); + *off = _off; return skb; } spin_unlock_irqrestore(&queue->lock, cpu_flags); @@ -207,7 +212,7 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags, if (!timeo) goto no_packet; - } while (!wait_for_packet(sk, err, &timeo)); + } while (!wait_for_more_packets(sk, err, &timeo, last)); return NULL; -- cgit v1.2.3 From 79f632c71bea0d0864d84d6a4ce78da5a9430f5b Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Mon, 29 Apr 2013 11:42:14 +0000 Subject: 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 Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/unix/af_unix.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'net') 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: } /* - * Sleep until data has arrive. But check for races.. + * Sleep until more data has arrived. But check for races.. */ - -static long unix_stream_data_wait(struct sock *sk, long timeo) +static long unix_stream_data_wait(struct sock *sk, long timeo, + struct sk_buff *last) { DEFINE_WAIT(wait); @@ -1871,7 +1871,7 @@ static long unix_stream_data_wait(struct sock *sk, long timeo) for (;;) { prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - if (!skb_queue_empty(&sk->sk_receive_queue) || + if (skb_peek_tail(&sk->sk_receive_queue) != last || sk->sk_err || (sk->sk_shutdown & RCV_SHUTDOWN) || signal_pending(current) || @@ -1890,8 +1890,6 @@ static long unix_stream_data_wait(struct sock *sk, long timeo) return timeo; } - - static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size, int flags) @@ -1936,14 +1934,12 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, goto out; } - skip = sk_peek_offset(sk, flags); - do { int chunk; - struct sk_buff *skb; + struct sk_buff *skb, *last; unix_state_lock(sk); - skb = skb_peek(&sk->sk_receive_queue); + last = skb = skb_peek(&sk->sk_receive_queue); again: if (skb == NULL) { unix_sk(sk)->recursion_level = 0; @@ -1966,7 +1962,7 @@ again: break; mutex_unlock(&u->readlock); - timeo = unix_stream_data_wait(sk, timeo); + timeo = unix_stream_data_wait(sk, timeo, last); if (signal_pending(current) || mutex_lock_interruptible(&u->readlock)) { @@ -1980,10 +1976,13 @@ again: break; } - if (skip >= skb->len) { + skip = sk_peek_offset(sk, flags); + while (skip >= skb->len) { skip -= skb->len; + last = skb; skb = skb_peek_next(skb, &sk->sk_receive_queue); - goto again; + if (!skb) + goto again; } unix_state_unlock(sk); -- cgit v1.2.3