diff options
author | Eric Dumazet <edumazet@google.com> | 2016-05-20 19:57:53 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-20 20:58:30 -0400 |
commit | b8ca9e3a612eaf3e54c6fa136c62246a1a9aece7 (patch) | |
tree | 4738aff27fdf4f88f77deaebd30454f94ea63a44 /include/linux/pagemap.h | |
parent | 297880f4af4e492ed5084be9397d65a18ade56ee (diff) |
mm: tighten fault_in_pages_writeable()
copy_page_to_iter_iovec() is currently the only user of
fault_in_pages_writeable(), and it definitely can use fragments from
high order pages.
Make sure fault_in_pages_writeable() is only touching two adjacent pages
at most, as claimed.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include/linux/pagemap.h')
-rw-r--r-- | include/linux/pagemap.h | 24 |
1 files changed, 9 insertions, 15 deletions
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index fe1513ffb7bf..97354102794d 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h | |||
@@ -518,33 +518,27 @@ void page_endio(struct page *page, int rw, int err); | |||
518 | extern void add_page_wait_queue(struct page *page, wait_queue_t *waiter); | 518 | extern void add_page_wait_queue(struct page *page, wait_queue_t *waiter); |
519 | 519 | ||
520 | /* | 520 | /* |
521 | * Fault a userspace page into pagetables. Return non-zero on a fault. | 521 | * Fault one or two userspace pages into pagetables. |
522 | * | 522 | * Return -EINVAL if more than two pages would be needed. |
523 | * This assumes that two userspace pages are always sufficient. | 523 | * Return non-zero on a fault. |
524 | */ | 524 | */ |
525 | static inline int fault_in_pages_writeable(char __user *uaddr, int size) | 525 | static inline int fault_in_pages_writeable(char __user *uaddr, int size) |
526 | { | 526 | { |
527 | int ret; | 527 | int span, ret; |
528 | 528 | ||
529 | if (unlikely(size == 0)) | 529 | if (unlikely(size == 0)) |
530 | return 0; | 530 | return 0; |
531 | 531 | ||
532 | span = offset_in_page(uaddr) + size; | ||
533 | if (span > 2 * PAGE_SIZE) | ||
534 | return -EINVAL; | ||
532 | /* | 535 | /* |
533 | * Writing zeroes into userspace here is OK, because we know that if | 536 | * Writing zeroes into userspace here is OK, because we know that if |
534 | * the zero gets there, we'll be overwriting it. | 537 | * the zero gets there, we'll be overwriting it. |
535 | */ | 538 | */ |
536 | ret = __put_user(0, uaddr); | 539 | ret = __put_user(0, uaddr); |
537 | if (ret == 0) { | 540 | if (ret == 0 && span > PAGE_SIZE) |
538 | char __user *end = uaddr + size - 1; | 541 | ret = __put_user(0, uaddr + size - 1); |
539 | |||
540 | /* | ||
541 | * If the page was already mapped, this will get a cache miss | ||
542 | * for sure, so try to avoid doing it. | ||
543 | */ | ||
544 | if (((unsigned long)uaddr & PAGE_MASK) != | ||
545 | ((unsigned long)end & PAGE_MASK)) | ||
546 | ret = __put_user(0, end); | ||
547 | } | ||
548 | return ret; | 542 | return ret; |
549 | } | 543 | } |
550 | 544 | ||