Re: [PATCH RESEND x3 v9 1/9] iov_iter: add copy_struct_from_iter()
From: Omar Sandoval <osandov@osandov.com>
Date: 2021-06-18 22:10:16
Also in:
linux-btrfs, linux-fsdevel
On Fri, Jun 18, 2021 at 02:40:51PM -0700, Linus Torvalds wrote:
On Fri, Jun 18, 2021 at 2:32 PM Al Viro [off-list ref] wrote:quoted
Huh? All corner cases are already taken care of by copy_from_iter{,_full}(). What I'm proposing is to have the size as a field in 'encoded' and do thisHmm. Making it part of the structure does make it easier (also for the sending userspace side, that doesn't now have to create yet another iov or copy the structure or whatever). Except your code doesn't actually handle the "smaller than expected" case correctly, since by the time it even checks for that, it will possibly already have failed. So you actually had a bug there - you can't use the "xyz_full()" version and get it right. That's fixable.
Right, we either need to read the size first and then the rest:
size_t copy_size;
if (!copy_from_iter_full(&encoded.size, sizeof(encoded.size),
&i))
return -EFAULT;
if (encoded.size > PAGE_SIZE)
return -E2BIG;
if (encoded.size < ENCODED_IOV_SIZE_VER0)
return -EINVAL;
if (!copy_from_iter_full(&encoded.size + 1,
min(sizeof(encoded), encoded.size) - sizeof(encoded.size),
&i))
return -EFAULT;
if (encoded.size > sizeof(encoded)) {
// newer than what we expect
if (!iov_iter_check_zeroes(&i, encoded.size - sizeof(encoded))
return -EINVAL;
} else if (encoded.size < sizeof(encoded)) {
// older than what we expect
memset((void *)&encoded + encoded.size, 0, sizeof(encoded) - encoded.size);
}
Or do the same reverting thing that Al did, but with copy_from_iter()
instead of copy_from_iter_full() and being careful with the copied count
(which I'm not 100% sure I got correct here):
size_t copied = copy_from_iter(&encoded, sizeof(encoded), &i);
if (copied < offsetofend(struct encoded_iov, size))
return -EFAULT;
if (encoded.size > PAGE_SIZE)
return -E2BIG;
if (encoded.size < ENCODED_IOV_SIZE_VER0)
return -EINVAL;
if (encoded.size > sizeof(encoded)) {
if (copied < sizeof(encoded)
return -EFAULT;
if (!iov_iter_check_zeroes(&i, encoded.size - sizeof(encoded))
return -EINVAL;
} else if (encoded.size < sizeof(encoded)) {
// older than what we expect
if (copied < encoded.size)
return -EFAULT;
iov_iter_revert(&i, copied - encoded.size);
memset((void *)&encoded + encoded.size, 0, sizeof(encoded) - encoded.size);
}