On Sun, 9 Feb 2025 at 11:48, David Laight <david.laight.linux@xxxxxxxxx> wrote: > > You almost need it to be 'void masked_user_access_begin(&uaddr)'. Maybe we just need to make it a two-stage thing, with if (!user_access_ok(uaddr, size)) return -EFAULT; user_read_access_begin(&uaddr); unsafe_get_user(val1, &uaddr->one, Efault); unsafe_get_user(val2, &uaddr->two, Efault); user_read_access_end(); ... all done .. Efault: user_read_access_end(); return -EFAULT; and that would actually simplify some things: right now we have separate versions of the user address checking (for read/write/either): user_read_access_begin() and friends. We still need those three versions, but now we'd only need them for the simpler non-conditional case that doesn't have to bother about the size. And then if you have user address masking, user_access_ok() just unconditionally returns true and is a no-op, while user_read_access_begin() does the masking and actually enables user accesses. And if you *don't* have user address masking, user_read_access_begin() still enables user accesses and has the required speculation synchronization, but doesn't do any address checking, because user_access_ok() did that (and nothing else). That seems like it might be a reasonable compromise and fairly hard to get wrong (*)? Linus (*) Obviously anybody can get anything wrong, but if you forget the user_access_ok() entirely you're being wilful about it, and if you forget the user_read_access_begin() the code won't work, so it seems about as safe as it can be.