All of lore.kernel.org
 help / color / mirror / Atom feed
From: Al Viro <viro@ZenIV.linux.org.uk>
To: Jan Stancek <jstancek@redhat.com>
Cc: linux-kernel@vger.kernel.org
Subject: Re: [bug] pwritev02 hang on s390x with 4.8.0-rc7
Date: Tue, 20 Sep 2016 16:06:57 +0100	[thread overview]
Message-ID: <20160920150657.GN2356@ZenIV.linux.org.uk> (raw)
In-Reply-To: <57E131E6.1090507@redhat.com>

On Tue, Sep 20, 2016 at 02:56:06PM +0200, Jan Stancek wrote:
> Hi,
> 
> I'm hitting a regression with LTP's pwritev02 [1] on s390x with 4.8.0-rc7.
> Specifically the EFAULT case, which is passing an iovec with invalid base address:
>   #define CHUNK 64
>   static struct iovec wr_iovec3[] = {
>   	{(char *)-1, CHUNK},
>   };
> hangs with 100% cpu usage and not very helpful stack trace:
>   # cat /proc/28544/stack
>   [<0000000000001000>] 0x1000
>   [<ffffffffffffffff>] 0xffffffffffffffff
> 
> The problem starts with d4690f1e1cda "fix iov_iter_fault_in_readable()".
> 
> Before this commit fault_in_pages_readable() called __get_user() on start
> address which presumably failed with -EFAULT immediately.
> 
> With this commit applied fault_in_multipages_readable() appears to return 0
> for the case when "start" is invalid but "end" overflows. Then according to
> my traces we keep spinning inside while loop in iomap_write_actor().

Cute.  Let me see if I understand what's going on there: we have a wraparound
that would've been caught by most of access_ok(), but not on an architectures
where access_ok() is a no-op; in that case the loop is skipped and we
just check the last address, which passes and we get a false positive.
Bug is real and it's definitely -stable fodder.

I'm not sure that the fix you propose is right, though.  Note that ERR_PTR()
is not a valid address on any architecture, so any wraparound automatically
means -EFAULT and we can simply check unlikely(uaddr > end) and bugger off
if it holds.  while() turns into do-while(), of course, and the same is
needed for the read side.

Could you check if the following works for you?

diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 66a1260..7e3d537 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -571,56 +571,56 @@ static inline int fault_in_pages_readable(const char __user *uaddr, int size)
  */
 static inline int fault_in_multipages_writeable(char __user *uaddr, int size)
 {
-	int ret = 0;
 	char __user *end = uaddr + size - 1;
 
 	if (unlikely(size == 0))
-		return ret;
+		return 0;
 
+	if (unlikely(uaddr > end))
+		return -EFAULT;
 	/*
 	 * Writing zeroes into userspace here is OK, because we know that if
 	 * the zero gets there, we'll be overwriting it.
 	 */
-	while (uaddr <= end) {
-		ret = __put_user(0, uaddr);
-		if (ret != 0)
-			return ret;
+	do {
+		if (unlikely(__put_user(0, uaddr) != 0))
+			return -EFAULT;
 		uaddr += PAGE_SIZE;
-	}
+	} while (uaddr <= end);
 
 	/* Check whether the range spilled into the next page. */
 	if (((unsigned long)uaddr & PAGE_MASK) ==
 			((unsigned long)end & PAGE_MASK))
-		ret = __put_user(0, end);
+		return __put_user(0, end);
 
-	return ret;
+	return 0;
 }
 
 static inline int fault_in_multipages_readable(const char __user *uaddr,
 					       int size)
 {
 	volatile char c;
-	int ret = 0;
 	const char __user *end = uaddr + size - 1;
 
 	if (unlikely(size == 0))
-		return ret;
+		return 0;
 
-	while (uaddr <= end) {
-		ret = __get_user(c, uaddr);
-		if (ret != 0)
-			return ret;
+	if (unlikely(uaddr > end))
+		return -EFAULT;
+
+	do {
+		if (unlikely(__get_user(c, uaddr) != 0))
+			return -EFAULT;
 		uaddr += PAGE_SIZE;
-	}
+	} while (uaddr <= end);
 
 	/* Check whether the range spilled into the next page. */
 	if (((unsigned long)uaddr & PAGE_MASK) ==
 			((unsigned long)end & PAGE_MASK)) {
-		ret = __get_user(c, end);
-		(void)c;
+		return __get_user(c, end);
 	}
 
-	return ret;
+	return 0;
 }
 
 int add_to_page_cache_locked(struct page *page, struct address_space *mapping,

  reply	other threads:[~2016-09-20 15:07 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-09-20 12:56 [bug] pwritev02 hang on s390x with 4.8.0-rc7 Jan Stancek
2016-09-20 15:06 ` Al Viro [this message]
2016-09-20 17:11   ` Jan Stancek
2016-09-20 17:30     ` Al Viro
2016-09-21  6:49       ` [LTP] Fwd: writev01/03/04 failures with 4.8-rc7 / was: " Jan Stancek
2016-09-20 19:07     ` [PATCH] fix fault_in_multipages_...() on architectures with no-op access_ok() Al Viro
2016-09-20 20:24       ` Linus Torvalds
2016-09-20 20:38         ` Al Viro
2016-09-20 20:48           ` Linus Torvalds
2016-09-20 21:03             ` Al Viro
2016-09-20 21:37               ` Al Viro
2016-09-20 23:43               ` Linus Torvalds
2016-09-21  0:38                 ` Al Viro

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160920150657.GN2356@ZenIV.linux.org.uk \
    --to=viro@zeniv.linux.org.uk \
    --cc=jstancek@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.