Commit 33844e66 authored by Al Viro's avatar Al Viro

[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: default avatarJon Maloy <jon.maloy@ericsson.com>
Tested-by: default avatarJon Maloy <jon.maloy@ericsson.com>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent c00d2c7e
...@@ -73,19 +73,21 @@ ...@@ -73,19 +73,21 @@
} }
#define iterate_all_kinds(i, n, v, I, B, K) { \ #define iterate_all_kinds(i, n, v, I, B, K) { \
size_t skip = i->iov_offset; \ if (likely(n)) { \
if (unlikely(i->type & ITER_BVEC)) { \ size_t skip = i->iov_offset; \
struct bio_vec v; \ if (unlikely(i->type & ITER_BVEC)) { \
struct bvec_iter __bi; \ struct bio_vec v; \
iterate_bvec(i, n, v, __bi, skip, (B)) \ struct bvec_iter __bi; \
} else if (unlikely(i->type & ITER_KVEC)) { \ iterate_bvec(i, n, v, __bi, skip, (B)) \
const struct kvec *kvec; \ } else if (unlikely(i->type & ITER_KVEC)) { \
struct kvec v; \ const struct kvec *kvec; \
iterate_kvec(i, n, v, kvec, skip, (K)) \ struct kvec v; \
} else { \ iterate_kvec(i, n, v, kvec, skip, (K)) \
const struct iovec *iov; \ } else { \
struct iovec v; \ const struct iovec *iov; \
iterate_iovec(i, n, v, iov, skip, (I)) \ struct iovec v; \
iterate_iovec(i, n, v, iov, skip, (I)) \
} \
} \ } \
} }
...@@ -576,7 +578,7 @@ bool copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i) ...@@ -576,7 +578,7 @@ bool copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i)
WARN_ON(1); WARN_ON(1);
return false; return false;
} }
if (unlikely(i->count < bytes)) \ if (unlikely(i->count < bytes))
return false; return false;
iterate_all_kinds(i, bytes, v, ({ 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,7 +622,7 @@ bool copy_from_iter_full_nocache(void *addr, size_t bytes, struct iov_iter *i)
WARN_ON(1); WARN_ON(1);
return false; return false;
} }
if (unlikely(i->count < bytes)) \ if (unlikely(i->count < bytes))
return false; return false;
iterate_all_kinds(i, bytes, v, ({ iterate_all_kinds(i, bytes, v, ({
if (__copy_from_user_nocache((to += v.iov_len) - v.iov_len, 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,11 +839,8 @@ unsigned long iov_iter_alignment(const struct iov_iter *i)
unsigned long res = 0; unsigned long res = 0;
size_t size = i->count; size_t size = i->count;
if (!size)
return 0;
if (unlikely(i->type & ITER_PIPE)) { if (unlikely(i->type & ITER_PIPE)) {
if (i->iov_offset && allocated(&i->pipe->bufs[i->idx])) if (size && i->iov_offset && allocated(&i->pipe->bufs[i->idx]))
return size | i->iov_offset; return size | i->iov_offset;
return size; return size;
} }
...@@ -856,10 +855,8 @@ EXPORT_SYMBOL(iov_iter_alignment); ...@@ -856,10 +855,8 @@ EXPORT_SYMBOL(iov_iter_alignment);
unsigned long iov_iter_gap_alignment(const struct iov_iter *i) unsigned long iov_iter_gap_alignment(const struct iov_iter *i)
{ {
unsigned long res = 0; unsigned long res = 0;
size_t size = i->count; size_t size = i->count;
if (!size)
return 0;
if (unlikely(i->type & ITER_PIPE)) { if (unlikely(i->type & ITER_PIPE)) {
WARN_ON(1); WARN_ON(1);
...@@ -874,7 +871,7 @@ unsigned long iov_iter_gap_alignment(const struct iov_iter *i) ...@@ -874,7 +871,7 @@ unsigned long iov_iter_gap_alignment(const struct iov_iter *i)
(res |= (!res ? 0 : (unsigned long)v.iov_base) | (res |= (!res ? 0 : (unsigned long)v.iov_base) |
(size != v.iov_len ? size : 0)) (size != v.iov_len ? size : 0))
); );
return res; return res;
} }
EXPORT_SYMBOL(iov_iter_gap_alignment); EXPORT_SYMBOL(iov_iter_gap_alignment);
...@@ -908,6 +905,9 @@ static ssize_t pipe_get_pages(struct iov_iter *i, ...@@ -908,6 +905,9 @@ static ssize_t pipe_get_pages(struct iov_iter *i,
size_t capacity; size_t capacity;
int idx; int idx;
if (!maxsize)
return 0;
if (!sanity(i)) if (!sanity(i))
return -EFAULT; return -EFAULT;
...@@ -926,9 +926,6 @@ ssize_t iov_iter_get_pages(struct iov_iter *i, ...@@ -926,9 +926,6 @@ ssize_t iov_iter_get_pages(struct iov_iter *i,
if (maxsize > i->count) if (maxsize > i->count)
maxsize = i->count; maxsize = i->count;
if (!maxsize)
return 0;
if (unlikely(i->type & ITER_PIPE)) if (unlikely(i->type & ITER_PIPE))
return pipe_get_pages(i, pages, maxsize, maxpages, start); return pipe_get_pages(i, pages, maxsize, maxpages, start);
iterate_all_kinds(i, maxsize, v, ({ iterate_all_kinds(i, maxsize, v, ({
...@@ -975,6 +972,9 @@ static ssize_t pipe_get_pages_alloc(struct iov_iter *i, ...@@ -975,6 +972,9 @@ static ssize_t pipe_get_pages_alloc(struct iov_iter *i,
int idx; int idx;
int npages; int npages;
if (!maxsize)
return 0;
if (!sanity(i)) if (!sanity(i))
return -EFAULT; return -EFAULT;
...@@ -1006,9 +1006,6 @@ ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, ...@@ -1006,9 +1006,6 @@ ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
if (maxsize > i->count) if (maxsize > i->count)
maxsize = i->count; maxsize = i->count;
if (!maxsize)
return 0;
if (unlikely(i->type & ITER_PIPE)) if (unlikely(i->type & ITER_PIPE))
return pipe_get_pages_alloc(i, pages, maxsize, start); return pipe_get_pages_alloc(i, pages, maxsize, start);
iterate_all_kinds(i, maxsize, v, ({ iterate_all_kinds(i, maxsize, v, ({
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment