From patchwork Thu Apr 25 13:47:18 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benjamin Poirier X-Patchwork-Id: 239510 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 93C462C00D1 for ; Thu, 25 Apr 2013 23:48:02 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932455Ab3DYNrj (ORCPT ); Thu, 25 Apr 2013 09:47:39 -0400 Received: from mail-qa0-f46.google.com ([209.85.216.46]:37857 "EHLO mail-qa0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932381Ab3DYNrc (ORCPT ); Thu, 25 Apr 2013 09:47:32 -0400 Received: by mail-qa0-f46.google.com with SMTP id p6so1300020qad.12 for ; Thu, 25 Apr 2013 06:47:31 -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=wCqCMQA/atN5NxqLPLFMVoqnDUOxHTyVHqT1CTtraRPkTULqLKhHRqrRewKg7lwrbp kwEF1yvrO6Qhylic8GZr7rHloJ2sXyXz9bKSdYoM20MmPtgZePRHWsislPVX5RywX4Xb ZnmSQjCQEkFWYlN/KfVNK7oTAB92EZYdGFGZJ2zMWcCDjPYQUk9x1s5jSQd6WoPO9gFW KPDbjQytuIGsJprQv0oNXAa+lNiclQVF9Z7uvrfdmJTuHcc1RtyHX34qP0mZ6Nhd6VDY xliITLjymSvxe0/BCLTQm9pbDldrKzhLr6SHIC2E5tbqtsnc6zqrnTCvnri7bUGgso0u HmCg== X-Received: by 10.224.192.196 with SMTP id dr4mr35069582qab.80.1366897651383; Thu, 25 Apr 2013 06:47:31 -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 kf2sm9973066qeb.4.2013.04.25.06.47.30 for (version=TLSv1.2 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 25 Apr 2013 06:47:31 -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 3/3] unix/stream: fix peeking with an offset larger than data in queue Date: Thu, 25 Apr 2013 09:47:18 -0400 Message-Id: <1366897638-21882-3-git-send-email-bpoirier@suse.de> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1366897638-21882-1-git-send-email-bpoirier@suse.de> References: <1366897638-21882-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);