On Fri, Jun 18, 2021 at 02:40:51PM -0700, Linus Torvalds wrote: > On Fri, Jun 18, 2021 at 2:32 PM Al Viro <viro@xxxxxxxxxxxxxxxxxx> wrote: > > > > 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 this > > Hmm. 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); }