diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2016-12-21 21:55:02 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2016-12-22 23:00:22 -0500 |
commit | 33844e665104b169a3a7732bdcddb40e4f82b335 (patch) | |
tree | 5432d8aeecc31c96696a19c56c0577d4499abdaa /lib/iov_iter.c | |
parent | c00d2c7e89880036f288a764599b2b8b87c0a364 (diff) |
[iov_iter] fix iterate_all_kinds() on empty iterators
Problem similar to ones dealt with in "fold checks into iterate_and_advance()"
and followups, except that in this case we really want to do nothing when
asked for zero-length operation - unlike zero-length iterate_and_advance(),
zero-length iterate_all_kinds() has no side effects, and callers are simpler
that way.
That got exposed when copy_from_iter_full() had been used by tipc, which
builds an msghdr with zero payload and (now) feeds it to a primitive
based on iterate_all_kinds() instead of iterate_and_advance().
Reported-by: Jon Maloy <jon.maloy@ericsson.com>
Tested-by: Jon Maloy <jon.maloy@ericsson.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'lib/iov_iter.c')
-rw-r--r-- | lib/iov_iter.c | 55 |
1 files changed, 26 insertions, 29 deletions
diff --git a/lib/iov_iter.c b/lib/iov_iter.c index 228892dabba6..25f572303801 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c | |||
@@ -73,19 +73,21 @@ | |||
73 | } | 73 | } |
74 | 74 | ||
75 | #define iterate_all_kinds(i, n, v, I, B, K) { \ | 75 | #define iterate_all_kinds(i, n, v, I, B, K) { \ |
76 | size_t skip = i->iov_offset; \ | 76 | if (likely(n)) { \ |
77 | if (unlikely(i->type & ITER_BVEC)) { \ | 77 | size_t skip = i->iov_offset; \ |
78 | struct bio_vec v; \ | 78 | if (unlikely(i->type & ITER_BVEC)) { \ |
79 | struct bvec_iter __bi; \ | 79 | struct bio_vec v; \ |
80 | iterate_bvec(i, n, v, __bi, skip, (B)) \ | 80 | struct bvec_iter __bi; \ |
81 | } else if (unlikely(i->type & ITER_KVEC)) { \ | 81 | iterate_bvec(i, n, v, __bi, skip, (B)) \ |
82 | const struct kvec *kvec; \ | 82 | } else if (unlikely(i->type & ITER_KVEC)) { \ |
83 | struct kvec v; \ | 83 | const struct kvec *kvec; \ |
84 | iterate_kvec(i, n, v, kvec, skip, (K)) \ | 84 | struct kvec v; \ |
85 | } else { \ | 85 | iterate_kvec(i, n, v, kvec, skip, (K)) \ |
86 | const struct iovec *iov; \ | 86 | } else { \ |
87 | struct iovec v; \ | 87 | const struct iovec *iov; \ |
88 | iterate_iovec(i, n, v, iov, skip, (I)) \ | 88 | struct iovec v; \ |
89 | iterate_iovec(i, n, v, iov, skip, (I)) \ | ||
90 | } \ | ||
89 | } \ | 91 | } \ |
90 | } | 92 | } |
91 | 93 | ||
@@ -576,7 +578,7 @@ bool copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i) | |||
576 | WARN_ON(1); | 578 | WARN_ON(1); |
577 | return false; | 579 | return false; |
578 | } | 580 | } |
579 | if (unlikely(i->count < bytes)) \ | 581 | if (unlikely(i->count < bytes)) |
580 | return false; | 582 | return false; |
581 | 583 | ||
582 | iterate_all_kinds(i, bytes, v, ({ | 584 | iterate_all_kinds(i, bytes, v, ({ |
@@ -620,7 +622,7 @@ bool copy_from_iter_full_nocache(void *addr, size_t bytes, struct iov_iter *i) | |||
620 | WARN_ON(1); | 622 | WARN_ON(1); |
621 | return false; | 623 | return false; |
622 | } | 624 | } |
623 | if (unlikely(i->count < bytes)) \ | 625 | if (unlikely(i->count < bytes)) |
624 | return false; | 626 | return false; |
625 | iterate_all_kinds(i, bytes, v, ({ | 627 | iterate_all_kinds(i, bytes, v, ({ |
626 | if (__copy_from_user_nocache((to += v.iov_len) - v.iov_len, | 628 | if (__copy_from_user_nocache((to += v.iov_len) - v.iov_len, |
@@ -837,11 +839,8 @@ unsigned long iov_iter_alignment(const struct iov_iter *i) | |||
837 | unsigned long res = 0; | 839 | unsigned long res = 0; |
838 | size_t size = i->count; | 840 | size_t size = i->count; |
839 | 841 | ||
840 | if (!size) | ||
841 | return 0; | ||
842 | |||
843 | if (unlikely(i->type & ITER_PIPE)) { | 842 | if (unlikely(i->type & ITER_PIPE)) { |
844 | if (i->iov_offset && allocated(&i->pipe->bufs[i->idx])) | 843 | if (size && i->iov_offset && allocated(&i->pipe->bufs[i->idx])) |
845 | return size | i->iov_offset; | 844 | return size | i->iov_offset; |
846 | return size; | 845 | return size; |
847 | } | 846 | } |
@@ -856,10 +855,8 @@ EXPORT_SYMBOL(iov_iter_alignment); | |||
856 | 855 | ||
857 | unsigned long iov_iter_gap_alignment(const struct iov_iter *i) | 856 | unsigned long iov_iter_gap_alignment(const struct iov_iter *i) |
858 | { | 857 | { |
859 | unsigned long res = 0; | 858 | unsigned long res = 0; |
860 | size_t size = i->count; | 859 | size_t size = i->count; |
861 | if (!size) | ||
862 | return 0; | ||
863 | 860 | ||
864 | if (unlikely(i->type & ITER_PIPE)) { | 861 | if (unlikely(i->type & ITER_PIPE)) { |
865 | WARN_ON(1); | 862 | WARN_ON(1); |
@@ -874,7 +871,7 @@ unsigned long iov_iter_gap_alignment(const struct iov_iter *i) | |||
874 | (res |= (!res ? 0 : (unsigned long)v.iov_base) | | 871 | (res |= (!res ? 0 : (unsigned long)v.iov_base) | |
875 | (size != v.iov_len ? size : 0)) | 872 | (size != v.iov_len ? size : 0)) |
876 | ); | 873 | ); |
877 | return res; | 874 | return res; |
878 | } | 875 | } |
879 | EXPORT_SYMBOL(iov_iter_gap_alignment); | 876 | EXPORT_SYMBOL(iov_iter_gap_alignment); |
880 | 877 | ||
@@ -908,6 +905,9 @@ static ssize_t pipe_get_pages(struct iov_iter *i, | |||
908 | size_t capacity; | 905 | size_t capacity; |
909 | int idx; | 906 | int idx; |
910 | 907 | ||
908 | if (!maxsize) | ||
909 | return 0; | ||
910 | |||
911 | if (!sanity(i)) | 911 | if (!sanity(i)) |
912 | return -EFAULT; | 912 | return -EFAULT; |
913 | 913 | ||
@@ -926,9 +926,6 @@ ssize_t iov_iter_get_pages(struct iov_iter *i, | |||
926 | if (maxsize > i->count) | 926 | if (maxsize > i->count) |
927 | maxsize = i->count; | 927 | maxsize = i->count; |
928 | 928 | ||
929 | if (!maxsize) | ||
930 | return 0; | ||
931 | |||
932 | if (unlikely(i->type & ITER_PIPE)) | 929 | if (unlikely(i->type & ITER_PIPE)) |
933 | return pipe_get_pages(i, pages, maxsize, maxpages, start); | 930 | return pipe_get_pages(i, pages, maxsize, maxpages, start); |
934 | iterate_all_kinds(i, maxsize, v, ({ | 931 | iterate_all_kinds(i, maxsize, v, ({ |
@@ -975,6 +972,9 @@ static ssize_t pipe_get_pages_alloc(struct iov_iter *i, | |||
975 | int idx; | 972 | int idx; |
976 | int npages; | 973 | int npages; |
977 | 974 | ||
975 | if (!maxsize) | ||
976 | return 0; | ||
977 | |||
978 | if (!sanity(i)) | 978 | if (!sanity(i)) |
979 | return -EFAULT; | 979 | return -EFAULT; |
980 | 980 | ||
@@ -1006,9 +1006,6 @@ ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, | |||
1006 | if (maxsize > i->count) | 1006 | if (maxsize > i->count) |
1007 | maxsize = i->count; | 1007 | maxsize = i->count; |
1008 | 1008 | ||
1009 | if (!maxsize) | ||
1010 | return 0; | ||
1011 | |||
1012 | if (unlikely(i->type & ITER_PIPE)) | 1009 | if (unlikely(i->type & ITER_PIPE)) |
1013 | return pipe_get_pages_alloc(i, pages, maxsize, start); | 1010 | return pipe_get_pages_alloc(i, pages, maxsize, start); |
1014 | iterate_all_kinds(i, maxsize, v, ({ | 1011 | iterate_all_kinds(i, maxsize, v, ({ |