On Mon, Feb 14, 2022 at 12:01 PM Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> wrote: > > x86-64 has always(*) used TASK_SIZE_MAX for access_ok(), and the > get_user() assembler implementation does the same. Side note: we could just check the sign bit instead, and avoid big constants that way. Right now we actually have this complexity in the x86-64 user access code: #ifdef CONFIG_X86_5LEVEL #define LOAD_TASK_SIZE_MINUS_N(n) \ ALTERNATIVE __stringify(mov $((1 << 47) - 4096 - (n)),%rdx), \ __stringify(mov $((1 << 56) - 4096 - (n)),%rdx), X86_FEATURE_LA57 #else #define LOAD_TASK_SIZE_MINUS_N(n) \ mov $(TASK_SIZE_MAX - (n)),%_ASM_DX #endif just because the code tries to get that TASK_SIZE_MAX boundary just right. And getting that boundary just right is important on 32-bit x86, but it's *much* less important on x86-64. There's still a (weak) reason to do it even for 64-bit code: page faults outside the valid user space range don't actually cause a #PF fault - they cause #GP - and then we have the #GP handler warn about "this address hasn't been checked". Which is nice and useful for doing syzbot kind of randomization loads (ie user accesses that didn't go through access_ok() will stand out nicely), but maybe it's not worth this. syzbot would be fine with only the "sign bit set" case warning for the same thing. So on x86-64, we could just check the sign of the address instead, and simplify and shrink those get/put_user() code sequences (but array_index_mask_nospec() currently uses the carry flag computation too, so we'd have to change that part as well, maybe not worth it). Linus