From patchwork Fri Apr 26 18:35:12 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benjamin Poirier X-Patchwork-Id: 239984 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id A8CE42C011B for ; Sat, 27 Apr 2013 04:36:20 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932285Ab3DZSfr (ORCPT ); Fri, 26 Apr 2013 14:35:47 -0400 Received: from mail-qe0-f54.google.com ([209.85.128.54]:35564 "EHLO mail-qe0-f54.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757451Ab3DZSfp (ORCPT ); Fri, 26 Apr 2013 14:35:45 -0400 Received: by mail-qe0-f54.google.com with SMTP id s14so2960056qeb.13 for ; Fri, 26 Apr 2013 11:35:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:sender:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references; bh=N6Ghj3f3LghyKEgDIE/yAC/fnxUEV9kl6eevTlxKX9M=; b=hh0zd1E0Vn7ret1GFjqdhN7uhOKok22bMJjEKKLTh+I8lu13ikqMZ1V+MPGO8CpSHx Adb7O65/tHXP5CZLdL5BBVIPEkkhROZZYR+9Ypt86kvYFlnyFiuHlr8o3qf2LBxqN8/1 t+m+AazOqvp54hap6RtNwKrfGB/MPz8ylLgphBT2Yyi/t7qPtOqVqJnkN8fUXTwtrQVX vKXpbCT3tuRaq+ED0hTQ60XoGK11AB1vwQy0uMEPv6B+ngKHhKq5LJpIdWCp6Q56EITE S+fweAZ5NAbkjOZ0VIHUOZZ8qNTRdrf/nQnz85iXHbTkEF4cC1hjIY/VDXZbBwDPOuww j0Ig== X-Received: by 10.224.147.83 with SMTP id k19mr23493593qav.72.1367001344595; Fri, 26 Apr 2013 11:35:44 -0700 (PDT) Received: from d2.synalogic.ca (modemcable062.27-82-70.mc.videotron.ca. [70.82.27.62]) by mx.google.com with ESMTPSA id n5sm12022130qav.2.2013.04.26.11.35.43 for (version=TLSv1.2 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 26 Apr 2013 11:35:44 -0700 (PDT) From: Benjamin Poirier To: "David S. Miller" , Eric Dumazet , Pavel Emelyanov Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH net v2 3/3] unix/stream: fix peeking with an offset larger than data in queue Date: Fri, 26 Apr 2013 14:35:12 -0400 Message-Id: <1367001312-6719-3-git-send-email-bpoirier@suse.de> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1367001312-6719-1-git-send-email-bpoirier@suse.de> References: <1366915736.8964.171.camel@edumazet-glaptop> <1367001312-6719-1-git-send-email-bpoirier@suse.de> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org 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 --- net/unix/af_unix.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 2db702d..1a02af0 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);