Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix 32-bit regression in block device read(2)

blkdev_read_iter() wants to cap the iov_iter by the amount of data
remaining to the end of device. That's what iov_iter_truncate() is for
(trim iter->count if it's above the given limit). So far, so good, but
the argument of iov_iter_truncate() is size_t, so on 32bit boxen (in
case of a large device) we end up with that upper limit truncated down
to 32 bits *before* comparing it with iter->count.

Easily fixed by making iov_iter_truncate() take 64bit argument - it does
the right thing after such change (we only reach the assignment in there
when the current value of iter->count is greater than the limit, i.e.
for anything that would get truncated we don't reach the assignment at
all) and that argument is not the new value of iter->count - it's an
upper limit for such.

The overhead of passing u64 is not an issue - the thing is inlined, so
callers passing size_t won't pay any penalty.

Reported-and-tested-by: Theodore Tso <tytso@mit.edu>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Tested-by: Alan Cox <gnomes@lxorguk.ukuu.org.uk>
Tested-by: Bruno Wolff III <bruno@wolff.to>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Al Viro and committed by
Linus Torvalds
0b86dbf6 d7933ab7

+13 -1
+13 -1
include/linux/uio.h
··· 94 94 return i->count; 95 95 } 96 96 97 - static inline void iov_iter_truncate(struct iov_iter *i, size_t count) 97 + /* 98 + * Cap the iov_iter by given limit; note that the second argument is 99 + * *not* the new size - it's upper limit for such. Passing it a value 100 + * greater than the amount of data in iov_iter is fine - it'll just do 101 + * nothing in that case. 102 + */ 103 + static inline void iov_iter_truncate(struct iov_iter *i, u64 count) 98 104 { 105 + /* 106 + * count doesn't have to fit in size_t - comparison extends both 107 + * operands to u64 here and any value that would be truncated by 108 + * conversion in assignement is by definition greater than all 109 + * values of size_t, including old i->count. 110 + */ 99 111 if (i->count > count) 100 112 i->count = count; 101 113 }