diff options
Diffstat (limited to 'lib/iov_iter.c')
| -rw-r--r-- | lib/iov_iter.c | 61 | 
1 files changed, 61 insertions, 0 deletions
diff --git a/lib/iov_iter.c b/lib/iov_iter.c index fdae394172fa..7e43cd54c84c 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c  | |||
| @@ -573,6 +573,67 @@ size_t _copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i) | |||
| 573 | } | 573 | } | 
| 574 | EXPORT_SYMBOL(_copy_to_iter); | 574 | EXPORT_SYMBOL(_copy_to_iter); | 
| 575 | 575 | ||
| 576 | #ifdef CONFIG_ARCH_HAS_UACCESS_MCSAFE | ||
| 577 | static int copyout_mcsafe(void __user *to, const void *from, size_t n) | ||
| 578 | { | ||
| 579 | if (access_ok(VERIFY_WRITE, to, n)) { | ||
| 580 | kasan_check_read(from, n); | ||
| 581 | n = copy_to_user_mcsafe((__force void *) to, from, n); | ||
| 582 | } | ||
| 583 | return n; | ||
| 584 | } | ||
| 585 | |||
| 586 | static unsigned long memcpy_mcsafe_to_page(struct page *page, size_t offset, | ||
| 587 | const char *from, size_t len) | ||
| 588 | { | ||
| 589 | unsigned long ret; | ||
| 590 | char *to; | ||
| 591 | |||
| 592 | to = kmap_atomic(page); | ||
| 593 | ret = memcpy_mcsafe(to + offset, from, len); | ||
| 594 | kunmap_atomic(to); | ||
| 595 | |||
| 596 | return ret; | ||
| 597 | } | ||
| 598 | |||
| 599 | size_t _copy_to_iter_mcsafe(const void *addr, size_t bytes, struct iov_iter *i) | ||
| 600 | { | ||
| 601 | const char *from = addr; | ||
| 602 | unsigned long rem, curr_addr, s_addr = (unsigned long) addr; | ||
| 603 | |||
| 604 | if (unlikely(i->type & ITER_PIPE)) { | ||
| 605 | WARN_ON(1); | ||
| 606 | return 0; | ||
| 607 | } | ||
| 608 | if (iter_is_iovec(i)) | ||
| 609 | might_fault(); | ||
| 610 | iterate_and_advance(i, bytes, v, | ||
| 611 | copyout_mcsafe(v.iov_base, (from += v.iov_len) - v.iov_len, v.iov_len), | ||
| 612 | ({ | ||
| 613 | rem = memcpy_mcsafe_to_page(v.bv_page, v.bv_offset, | ||
| 614 | (from += v.bv_len) - v.bv_len, v.bv_len); | ||
| 615 | if (rem) { | ||
| 616 | curr_addr = (unsigned long) from; | ||
| 617 | bytes = curr_addr - s_addr - rem; | ||
| 618 | return bytes; | ||
| 619 | } | ||
| 620 | }), | ||
| 621 | ({ | ||
| 622 | rem = memcpy_mcsafe(v.iov_base, (from += v.iov_len) - v.iov_len, | ||
| 623 | v.iov_len); | ||
| 624 | if (rem) { | ||
| 625 | curr_addr = (unsigned long) from; | ||
| 626 | bytes = curr_addr - s_addr - rem; | ||
| 627 | return bytes; | ||
| 628 | } | ||
| 629 | }) | ||
| 630 | ) | ||
| 631 | |||
| 632 | return bytes; | ||
| 633 | } | ||
| 634 | EXPORT_SYMBOL_GPL(_copy_to_iter_mcsafe); | ||
| 635 | #endif /* CONFIG_ARCH_HAS_UACCESS_MCSAFE */ | ||
| 636 | |||
| 576 | size_t _copy_from_iter(void *addr, size_t bytes, struct iov_iter *i) | 637 | size_t _copy_from_iter(void *addr, size_t bytes, struct iov_iter *i) | 
| 577 | { | 638 | { | 
| 578 | char *to = addr; | 639 | char *to = addr; | 
