Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+26 −29
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@
}

#define iterate_all_kinds(i, n, v, I, B, K) {			\
	if (likely(n)) {					\
		size_t skip = i->iov_offset;			\
		if (unlikely(i->type & ITER_BVEC)) {		\
			struct bio_vec v;			\
@@ -87,6 +88,7 @@
			struct iovec v;				\
			iterate_iovec(i, n, v, iov, skip, (I))	\
		}						\
	}							\
}

#define iterate_and_advance(i, n, v, I, B, K) {			\
@@ -576,7 +578,7 @@ bool copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i)
		WARN_ON(1);
		return false;
	}
	if (unlikely(i->count < bytes))				\
	if (unlikely(i->count < bytes))
		return false;

	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)
		WARN_ON(1);
		return false;
	}
	if (unlikely(i->count < bytes))				\
	if (unlikely(i->count < bytes))
		return false;
	iterate_all_kinds(i, bytes, v, ({
		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)
	unsigned long res = 0;
	size_t size = i->count;

	if (!size)
		return 0;

	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;
	}
@@ -858,8 +857,6 @@ unsigned long iov_iter_gap_alignment(const struct iov_iter *i)
{
	unsigned long res = 0;
	size_t size = i->count;
	if (!size)
		return 0;

	if (unlikely(i->type & ITER_PIPE)) {
		WARN_ON(1);
@@ -908,6 +905,9 @@ static ssize_t pipe_get_pages(struct iov_iter *i,
	size_t capacity;
	int idx;

	if (!maxsize)
		return 0;

	if (!sanity(i))
		return -EFAULT;

@@ -926,9 +926,6 @@ ssize_t iov_iter_get_pages(struct iov_iter *i,
	if (maxsize > i->count)
		maxsize = i->count;

	if (!maxsize)
		return 0;

	if (unlikely(i->type & ITER_PIPE))
		return pipe_get_pages(i, pages, maxsize, maxpages, start);
	iterate_all_kinds(i, maxsize, v, ({
@@ -975,6 +972,9 @@ static ssize_t pipe_get_pages_alloc(struct iov_iter *i,
	int idx;
	int npages;

	if (!maxsize)
		return 0;

	if (!sanity(i))
		return -EFAULT;

@@ -1006,9 +1006,6 @@ ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
	if (maxsize > i->count)
		maxsize = i->count;

	if (!maxsize)
		return 0;

	if (unlikely(i->type & ITER_PIPE))
		return pipe_get_pages_alloc(i, pages, maxsize, start);
	iterate_all_kinds(i, maxsize, v, ({