# git rev-parse -q --verify 94bd8a05cd4de344a9a57e52ef7d99550251984f^{commit} 94bd8a05cd4de344a9a57e52ef7d99550251984f already have revision, skipping fetch # git checkout -q -f -B kisskb 94bd8a05cd4de344a9a57e52ef7d99550251984f # git clean -qxdf # < git log -1 # commit 94bd8a05cd4de344a9a57e52ef7d99550251984f # Author: Linus Torvalds # Date: Sun Jan 6 11:15:04 2019 -0800 # # Fix 'acccess_ok()' on alpha and SH # # Commit 594cc251fdd0 ("make 'user_access_begin()' do 'access_ok()'") # broke both alpha and SH booting in qemu, as noticed by Guenter Roeck. # # It turns out that the bug wasn't actually in that commit itself (which # would have been surprising: it was mostly a no-op), but in how the # addition of access_ok() to the strncpy_from_user() and strnlen_user() # functions now triggered the case where those functions would test the # access of the very last byte of the user address space. # # The string functions actually did that user range test before too, but # they did it manually by just comparing against user_addr_max(). But # with user_access_begin() doing the check (using "access_ok()"), it now # exposed problems in the architecture implementations of that function. # # For example, on alpha, the access_ok() helper macro looked like this: # # #define __access_ok(addr, size) \ # ((get_fs().seg & (addr | size | (addr+size))) == 0) # # and what it basically tests is of any of the high bits get set (the # USER_DS masking value is 0xfffffc0000000000). # # And that's completely wrong for the "addr+size" check. Because it's # off-by-one for the case where we check to the very end of the user # address space, which is exactly what the strn*_user() functions do. # # Why? Because "addr+size" will be exactly the size of the address space, # so trying to access the last byte of the user address space will fail # the __access_ok() check, even though it shouldn't. As a result, the # user string accessor functions failed consistently - because they # literally don't know how long the string is going to be, and the max # access is going to be that last byte of the user address space. # # Side note: that alpha macro is buggy for another reason too - it re-uses # the arguments twice. # # And SH has another version of almost the exact same bug: # # #define __addr_ok(addr) \ # ((unsigned long __force)(addr) < current_thread_info()->addr_limit.seg) # # so far so good: yes, a user address must be below the limit. But then: # # #define __access_ok(addr, size) \ # (__addr_ok((addr) + (size))) # # is wrong with the exact same off-by-one case: the case when "addr+size" # is exactly _equal_ to the limit is actually perfectly fine (think "one # byte access at the last address of the user address space") # # The SH version is actually seriously buggy in another way: it doesn't # actually check for overflow, even though it did copy the _comment_ that # talks about overflow. # # So it turns out that both SH and alpha actually have completely buggy # implementations of access_ok(), but they happened to work in practice # (although the SH overflow one is a serious serious security bug, not # that anybody likely cares about SH security). # # This fixes the problems by using a similar macro on both alpha and SH. # It isn't trying to be clever, the end address is based on this logic: # # unsigned long __ao_end = __ao_a + __ao_b - !!__ao_b; # # which basically says "add start and length, and then subtract one unless # the length was zero". We can't subtract one for a zero length, or we'd # just hit an underflow instead. # # For a lot of access_ok() users the length is a constant, so this isn't # actually as expensive as it initially looks. # # Reported-and-tested-by: Guenter Roeck # Cc: Matt Turner # Cc: Yoshinori Sato # Signed-off-by: Linus Torvalds # < /opt/cross/kisskb/korg/gcc-5.5.0-nolibc/powerpc64-linux/bin/powerpc64-linux-gcc --version # < /opt/cross/kisskb/korg/gcc-5.5.0-nolibc/powerpc64-linux/bin/powerpc64-linux-ld --version # < git log --format=%s --max-count=1 94bd8a05cd4de344a9a57e52ef7d99550251984f # < make -s -j 10 ARCH=powerpc O=/kisskb/build/linus-rand_randconfig+ppc64le_ppc64le-gcc5 CROSS_COMPILE=/opt/cross/kisskb/korg/gcc-5.5.0-nolibc/powerpc64-linux/bin/powerpc64-linux- randconfig KCONFIG_SEED=0x1154541E # Added to kconfig CONFIG_STANDALONE=y # Added to kconfig CONFIG_BUILD_DOCSRC=n # Added to kconfig CONFIG_MODULE_SIG=n # Added to kconfig CONFIG_CPU_BIG_ENDIAN=n # Added to kconfig CONFIG_CPU_LITTLE_ENDIAN=y # Added to kconfig CONFIG_PPC64=y # Added to kconfig CONFIG_PPC_BOOK3E_64=n # Added to kconfig CONFIG_PPC_BOOK3S_64=y # Added to kconfig CONFIG_PPC_DISABLE_WERROR=y # Added to kconfig CONFIG_SECTION_MISMATCH_WARN_ONLY=y # Added to kconfig CONFIG_PREVENT_FIRMWARE_BUILD=y # Added to kconfig CONFIG_LD_HEAD_STUB_CATCH=y # yes \n | make -s -j 10 ARCH=powerpc O=/kisskb/build/linus-rand_randconfig+ppc64le_ppc64le-gcc5 CROSS_COMPILE=/opt/cross/kisskb/korg/gcc-5.5.0-nolibc/powerpc64-linux/bin/powerpc64-linux- oldconfig yes: standard output: Broken pipe # make -s -j 10 ARCH=powerpc O=/kisskb/build/linus-rand_randconfig+ppc64le_ppc64le-gcc5 CROSS_COMPILE=/opt/cross/kisskb/korg/gcc-5.5.0-nolibc/powerpc64-linux/bin/powerpc64-linux- In file included from /kisskb/src/arch/powerpc/xmon/xmon.c:67:0: /kisskb/src/arch/powerpc/xmon/dis-asm.h: In function 'print_insn_powerpc': /kisskb/src/arch/powerpc/xmon/dis-asm.h:20:9: warning: format '%x' expects argument of type 'unsigned int', but argument 2 has type 'long unsigned int' [-Wformat=] printf("%.8x", insn); ^ /kisskb/src/arch/powerpc/xmon/dis-asm.h: In function 'print_insn_spu': /kisskb/src/arch/powerpc/xmon/dis-asm.h:26:9: warning: format '%x' expects argument of type 'unsigned int', but argument 2 has type 'long unsigned int' [-Wformat=] printf("%.8x", insn); ^ WARNING: modpost: Found 2 section mismatch(es). To see full details build your kernel with: 'make CONFIG_DEBUG_SECTION_MISMATCH=y' ERROR: start_text address is c000000000008100, should be c000000000008000 ERROR: try to enable LD_HEAD_STUB_CATCH config option ERROR: see comments in arch/powerpc/tools/head_check.sh make[2]: *** [/kisskb/src/arch/powerpc/Makefile.postlink:31: vmlinux] Error 1 make[1]: *** [/kisskb/src/Makefile:1027: vmlinux] Error 2 make[1]: *** Deleting file 'vmlinux' make: *** [Makefile:152: sub-make] Error 2 Command 'make -s -j 10 ARCH=powerpc O=/kisskb/build/linus-rand_randconfig+ppc64le_ppc64le-gcc5 CROSS_COMPILE=/opt/cross/kisskb/korg/gcc-5.5.0-nolibc/powerpc64-linux/bin/powerpc64-linux- ' returned non-zero exit status 2 # rm -rf /kisskb/build/linus-rand_randconfig+ppc64le_ppc64le-gcc5 # Build took: 0:11:11.997051