diff options
| author | Andrew Morton <akpm@digeo.com> | 2002-09-19 08:36:47 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2002-09-19 08:36:47 -0700 |
| commit | d4872de38e4c74dd5c56facbd986da46ca551b65 (patch) | |
| tree | 9eed86e6eb11d9fe885e91d528666cec306e656b /include | |
| parent | bd90a275f400dc3b46dd72cec221f1db13bffc0f (diff) | |
[PATCH] readv/writev bounds checking fixes
- writev currently returns -EFAULT if _any_ of the segments has an
invalid address. We should only return -EFAULT if the first segment
has a bad address.
If some of the first segments have valid addresses we need to write
them and return a partial result.
- The current code only checks if the sum-of-lengths is negative. If
individual segments have a negative length but the result is positive
we miss that.
So rework the code to detect this, and to be immune to odd wrapping
situations.
As a bonus, we save one pass across the iovec.
- ditto for readv.
The check for "does any segment have a negative length" has already
been performed in do_readv_writev(), but it's basically free here, and
we need to do it for generic_file_read/write anyway.
This all means that the iov_length() function is unsafe because of
wrap/overflow isues. It should only be used after the
generic_file_read/write or do_readv_writev() checking has been
performed. Its callers have been reviewed and they are OK.
The code now passes LTP testing and has been QA'd by Janet's team.
Diffstat (limited to 'include')
| -rw-r--r-- | include/linux/uio.h | 6 |
1 files changed, 5 insertions, 1 deletions
diff --git a/include/linux/uio.h b/include/linux/uio.h index ec098c8e6793..85b2f0ec9d3f 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h @@ -35,7 +35,11 @@ struct iovec #endif /* - * Total number of bytes covered by an iovec + * Total number of bytes covered by an iovec. + * + * NOTE that it is not safe to use this function until all the iovec's + * segment lengths have been validated. Because the individual lengths can + * overflow a size_t when added together. */ static inline size_t iov_length(const struct iovec *iov, unsigned long nr_segs) { |
