diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2017-06-29 21:45:10 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2017-06-29 22:21:22 -0400 |
commit | aa28de275a248879f9828cb9f7ee7e119c72ff96 (patch) | |
tree | ea50dff24c17d06ed9a799b38e8089996c3ccff2 | |
parent | b0377fedb6528087ed319b0d054d6ed82240372c (diff) |
iov_iter/hardening: move object size checks to inlined part
There we actually have useful information about object sizes.
Note: this patch has them done for all iov_iter flavours.
Right now we do them twice in iovec case, but that'll change
very shortly.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | include/linux/uio.h | 58 | ||||
-rw-r--r-- | lib/iov_iter.c | 22 |
2 files changed, 64 insertions, 16 deletions
diff --git a/include/linux/uio.h b/include/linux/uio.h index f2d36a3d3005..243e2362fe1a 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h | |||
@@ -10,6 +10,7 @@ | |||
10 | #define __LINUX_UIO_H | 10 | #define __LINUX_UIO_H |
11 | 11 | ||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/thread_info.h> | ||
13 | #include <uapi/linux/uio.h> | 14 | #include <uapi/linux/uio.h> |
14 | 15 | ||
15 | struct page; | 16 | struct page; |
@@ -91,11 +92,58 @@ size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes, | |||
91 | struct iov_iter *i); | 92 | struct iov_iter *i); |
92 | size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes, | 93 | size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes, |
93 | struct iov_iter *i); | 94 | struct iov_iter *i); |
94 | size_t copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i); | 95 | |
95 | size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i); | 96 | size_t _copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i); |
96 | bool copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i); | 97 | size_t _copy_from_iter(void *addr, size_t bytes, struct iov_iter *i); |
97 | size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i); | 98 | bool _copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i); |
98 | bool copy_from_iter_full_nocache(void *addr, size_t bytes, struct iov_iter *i); | 99 | size_t _copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i); |
100 | bool _copy_from_iter_full_nocache(void *addr, size_t bytes, struct iov_iter *i); | ||
101 | |||
102 | static __always_inline __must_check | ||
103 | size_t copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i) | ||
104 | { | ||
105 | if (unlikely(!check_copy_size(addr, bytes, true))) | ||
106 | return bytes; | ||
107 | else | ||
108 | return _copy_to_iter(addr, bytes, i); | ||
109 | } | ||
110 | |||
111 | static __always_inline __must_check | ||
112 | size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i) | ||
113 | { | ||
114 | if (unlikely(!check_copy_size(addr, bytes, false))) | ||
115 | return bytes; | ||
116 | else | ||
117 | return _copy_from_iter(addr, bytes, i); | ||
118 | } | ||
119 | |||
120 | static __always_inline __must_check | ||
121 | bool copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i) | ||
122 | { | ||
123 | if (unlikely(!check_copy_size(addr, bytes, false))) | ||
124 | return false; | ||
125 | else | ||
126 | return _copy_from_iter_full(addr, bytes, i); | ||
127 | } | ||
128 | |||
129 | static __always_inline __must_check | ||
130 | size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i) | ||
131 | { | ||
132 | if (unlikely(!check_copy_size(addr, bytes, false))) | ||
133 | return bytes; | ||
134 | else | ||
135 | return _copy_from_iter_nocache(addr, bytes, i); | ||
136 | } | ||
137 | |||
138 | static __always_inline __must_check | ||
139 | bool copy_from_iter_full_nocache(void *addr, size_t bytes, struct iov_iter *i) | ||
140 | { | ||
141 | if (unlikely(!check_copy_size(addr, bytes, false))) | ||
142 | return false; | ||
143 | else | ||
144 | return _copy_from_iter_full_nocache(addr, bytes, i); | ||
145 | } | ||
146 | |||
99 | size_t iov_iter_zero(size_t bytes, struct iov_iter *); | 147 | size_t iov_iter_zero(size_t bytes, struct iov_iter *); |
100 | unsigned long iov_iter_alignment(const struct iov_iter *i); | 148 | unsigned long iov_iter_alignment(const struct iov_iter *i); |
101 | unsigned long iov_iter_gap_alignment(const struct iov_iter *i); | 149 | unsigned long iov_iter_gap_alignment(const struct iov_iter *i); |
diff --git a/lib/iov_iter.c b/lib/iov_iter.c index f835964c9485..bc4a63ebe91a 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c | |||
@@ -535,7 +535,7 @@ static size_t copy_pipe_to_iter(const void *addr, size_t bytes, | |||
535 | return bytes; | 535 | return bytes; |
536 | } | 536 | } |
537 | 537 | ||
538 | size_t copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i) | 538 | size_t _copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i) |
539 | { | 539 | { |
540 | const char *from = addr; | 540 | const char *from = addr; |
541 | if (unlikely(i->type & ITER_PIPE)) | 541 | if (unlikely(i->type & ITER_PIPE)) |
@@ -550,9 +550,9 @@ size_t copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i) | |||
550 | 550 | ||
551 | return bytes; | 551 | return bytes; |
552 | } | 552 | } |
553 | EXPORT_SYMBOL(copy_to_iter); | 553 | EXPORT_SYMBOL(_copy_to_iter); |
554 | 554 | ||
555 | size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i) | 555 | size_t _copy_from_iter(void *addr, size_t bytes, struct iov_iter *i) |
556 | { | 556 | { |
557 | char *to = addr; | 557 | char *to = addr; |
558 | if (unlikely(i->type & ITER_PIPE)) { | 558 | if (unlikely(i->type & ITER_PIPE)) { |
@@ -569,9 +569,9 @@ size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i) | |||
569 | 569 | ||
570 | return bytes; | 570 | return bytes; |
571 | } | 571 | } |
572 | EXPORT_SYMBOL(copy_from_iter); | 572 | EXPORT_SYMBOL(_copy_from_iter); |
573 | 573 | ||
574 | bool copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i) | 574 | bool _copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i) |
575 | { | 575 | { |
576 | char *to = addr; | 576 | char *to = addr; |
577 | if (unlikely(i->type & ITER_PIPE)) { | 577 | if (unlikely(i->type & ITER_PIPE)) { |
@@ -594,9 +594,9 @@ bool copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i) | |||
594 | iov_iter_advance(i, bytes); | 594 | iov_iter_advance(i, bytes); |
595 | return true; | 595 | return true; |
596 | } | 596 | } |
597 | EXPORT_SYMBOL(copy_from_iter_full); | 597 | EXPORT_SYMBOL(_copy_from_iter_full); |
598 | 598 | ||
599 | size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i) | 599 | size_t _copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i) |
600 | { | 600 | { |
601 | char *to = addr; | 601 | char *to = addr; |
602 | if (unlikely(i->type & ITER_PIPE)) { | 602 | if (unlikely(i->type & ITER_PIPE)) { |
@@ -613,9 +613,9 @@ size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i) | |||
613 | 613 | ||
614 | return bytes; | 614 | return bytes; |
615 | } | 615 | } |
616 | EXPORT_SYMBOL(copy_from_iter_nocache); | 616 | EXPORT_SYMBOL(_copy_from_iter_nocache); |
617 | 617 | ||
618 | bool copy_from_iter_full_nocache(void *addr, size_t bytes, struct iov_iter *i) | 618 | bool _copy_from_iter_full_nocache(void *addr, size_t bytes, struct iov_iter *i) |
619 | { | 619 | { |
620 | char *to = addr; | 620 | char *to = addr; |
621 | if (unlikely(i->type & ITER_PIPE)) { | 621 | if (unlikely(i->type & ITER_PIPE)) { |
@@ -637,7 +637,7 @@ bool copy_from_iter_full_nocache(void *addr, size_t bytes, struct iov_iter *i) | |||
637 | iov_iter_advance(i, bytes); | 637 | iov_iter_advance(i, bytes); |
638 | return true; | 638 | return true; |
639 | } | 639 | } |
640 | EXPORT_SYMBOL(copy_from_iter_full_nocache); | 640 | EXPORT_SYMBOL(_copy_from_iter_full_nocache); |
641 | 641 | ||
642 | size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes, | 642 | size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes, |
643 | struct iov_iter *i) | 643 | struct iov_iter *i) |
@@ -663,7 +663,7 @@ size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes, | |||
663 | } | 663 | } |
664 | if (i->type & (ITER_BVEC|ITER_KVEC)) { | 664 | if (i->type & (ITER_BVEC|ITER_KVEC)) { |
665 | void *kaddr = kmap_atomic(page); | 665 | void *kaddr = kmap_atomic(page); |
666 | size_t wanted = copy_from_iter(kaddr + offset, bytes, i); | 666 | size_t wanted = _copy_from_iter(kaddr + offset, bytes, i); |
667 | kunmap_atomic(kaddr); | 667 | kunmap_atomic(kaddr); |
668 | return wanted; | 668 | return wanted; |
669 | } else | 669 | } else |