Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1487565
| From | Al Viro <viro@ZenIV.linux.org.uk> |
|---|---|
| Newsgroups | linux.kernel |
| Subject | [PATCH] fix fault_in_multipages_...() on architectures with no-op access_ok() |
| Date | 2016-09-20 21:10 +0200 |
| Message-ID | <sjyAx-74A-11@gated-at.bofh.it> (permalink) |
| References | <sjsOu-34H-23@gated-at.bofh.it> <sjuQh-4Gm-1@gated-at.bofh.it> <sjwS5-5V7-11@gated-at.bofh.it> |
| Organization | linux.* mail to news gateway |
Switching iov_iter fault-in to multipages variants has exposed an old
bug in underlying fault_in_multipages_...(); they break if the range
passed to them wraps around. Normally access_ok() done by callers
will prevent such (and it's a guaranteed EFAULT - ERR_PTR() values
fall into such a range and they should not point to any valid objects).
However, on architectures where userland and kernel live in different
MMU contexts (e.g. s390) access_ok() is a no-op and on those a range
with a wraparound can reach fault_in_multipages_...().
Since any wraparound means EFAULT there, the fix is trivial - turn
those
while (uaddr <= end)
...
into
if (unlikely(uaddr > end))
return -EFAULT;
do
...
while (uaddr <= end);
Reported-by: Jan Stancek <jstancek@redhat.com>
Tested-by: Jan Stancek <jstancek@redhat.com>
Cc: stable@vger.kernel.org # v3.5+
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
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,
Back to linux.kernel | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread
[bug] pwritev02 hang on s390x with 4.8.0-rc7 Jan Stancek <jstancek@redhat.com> - 2016-09-20 15:00 +0200
Re: [bug] pwritev02 hang on s390x with 4.8.0-rc7 Al Viro <viro@ZenIV.linux.org.uk> - 2016-09-20 17:10 +0200
Re: [bug] pwritev02 hang on s390x with 4.8.0-rc7 Jan Stancek <jstancek@redhat.com> - 2016-09-20 19:20 +0200
Re: [bug] pwritev02 hang on s390x with 4.8.0-rc7 Al Viro <viro@ZenIV.linux.org.uk> - 2016-09-20 19:40 +0200
[PATCH] fix fault_in_multipages_...() on architectures with no-op access_ok() Al Viro <viro@ZenIV.linux.org.uk> - 2016-09-20 21:10 +0200
Re: [PATCH] fix fault_in_multipages_...() on architectures with no-op access_ok() Linus Torvalds <torvalds@linux-foundation.org> - 2016-09-20 22:30 +0200
Re: [PATCH] fix fault_in_multipages_...() on architectures with no-op access_ok() Al Viro <viro@ZenIV.linux.org.uk> - 2016-09-20 22:40 +0200
Re: [PATCH] fix fault_in_multipages_...() on architectures with no-op access_ok() Linus Torvalds <torvalds@linux-foundation.org> - 2016-09-20 22:50 +0200
Re: [PATCH] fix fault_in_multipages_...() on architectures with no-op access_ok() Al Viro <viro@ZenIV.linux.org.uk> - 2016-09-20 23:10 +0200
Re: [PATCH] fix fault_in_multipages_...() on architectures with no-op access_ok() Al Viro <viro@ZenIV.linux.org.uk> - 2016-09-20 23:40 +0200
Re: [PATCH] fix fault_in_multipages_...() on architectures with no-op access_ok() Linus Torvalds <torvalds@linux-foundation.org> - 2016-09-21 01:50 +0200
Re: [PATCH] fix fault_in_multipages_...() on architectures with no-op access_ok() Al Viro <viro@ZenIV.linux.org.uk> - 2016-09-21 02:40 +0200
csiph-web