diff mbox series

x86/uaccess: Fix missed zeroing of ia32 u64 get_user() range checking

Message ID 20240610210213.work.143-kees@kernel.org (mailing list archive)
State Mainlined
Commit 8c860ed825cb85f6672cd7b10a8f33e3498a7c81
Headers show
Series x86/uaccess: Fix missed zeroing of ia32 u64 get_user() range checking | expand

Commit Message

Kees Cook June 10, 2024, 9:02 p.m. UTC
When reworking the range checking for get_user(), the get_user_8() case
on 32-bit wasn't zeroing the high register. (The jump to bad_get_user_8
was accidentally dropped.) Restore the correct error handling
destination (and rename the jump to using the expected ".L" prefix).

While here, switch to using a named argument ("size") for the call
template ("%c4" to "%c[size]") as already used in the other call
templates in this file.

Found after moving the usercopy selftests to KUnit:

      # usercopy_test_invalid: EXPECTATION FAILED at
      lib/usercopy_kunit.c:278
      Expected val_u64 == 0, but
          val_u64 == -60129542144 (0xfffffff200000000)

Reported-by: David Gow <davidgow@google.com>
Closes: https://lore.kernel.org/all/CABVgOSn=tb=Lj9SxHuT4_9MTjjKVxsq-ikdXC4kGHO4CfKVmGQ@mail.gmail.com
Fixes: b19b74bc99b1 ("x86/mm: Rework address range check in get_user() and put_user()")
Signed-off-by: Kees Cook <kees@kernel.org>
---
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: x86@kernel.org
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Sean Christopherson <seanjc@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
Cc: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
Cc: Nadav Amit <nadav.amit@gmail.com>
Cc: Masahiro Yamada <masahiroy@kernel.org>
---
 arch/x86/include/asm/uaccess.h | 4 ++--
 arch/x86/lib/getuser.S         | 6 +++++-
 2 files changed, 7 insertions(+), 3 deletions(-)

Comments

David Gow June 11, 2024, 6:14 a.m. UTC | #1
On Tue, 11 Jun 2024 at 05:02, Kees Cook <kees@kernel.org> wrote:
>
> When reworking the range checking for get_user(), the get_user_8() case
> on 32-bit wasn't zeroing the high register. (The jump to bad_get_user_8
> was accidentally dropped.) Restore the correct error handling
> destination (and rename the jump to using the expected ".L" prefix).
>
> While here, switch to using a named argument ("size") for the call
> template ("%c4" to "%c[size]") as already used in the other call
> templates in this file.
>
> Found after moving the usercopy selftests to KUnit:
>
>       # usercopy_test_invalid: EXPECTATION FAILED at
>       lib/usercopy_kunit.c:278
>       Expected val_u64 == 0, but
>           val_u64 == -60129542144 (0xfffffff200000000)
>
> Reported-by: David Gow <davidgow@google.com>
> Closes: https://lore.kernel.org/all/CABVgOSn=tb=Lj9SxHuT4_9MTjjKVxsq-ikdXC4kGHO4CfKVmGQ@mail.gmail.com
> Fixes: b19b74bc99b1 ("x86/mm: Rework address range check in get_user() and put_user()")
> Signed-off-by: Kees Cook <kees@kernel.org>
> ---
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: Borislav Petkov <bp@alien8.de>
> Cc: Dave Hansen <dave.hansen@linux.intel.com>
> Cc: x86@kernel.org
> Cc: "H. Peter Anvin" <hpa@zytor.com>
> Cc: Sean Christopherson <seanjc@google.com>
> Cc: Peter Zijlstra <peterz@infradead.org>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
> Cc: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
> Cc: Nadav Amit <nadav.amit@gmail.com>
> Cc: Masahiro Yamada <masahiroy@kernel.org>
> ---

Thanks: this fixes it here, both under qemu and on real hardware.

Tested-by: David Gow <davidgow@google.com>

-- David
Greg KH June 11, 2024, 6:21 a.m. UTC | #2
On Mon, Jun 10, 2024 at 02:02:27PM -0700, Kees Cook wrote:
> When reworking the range checking for get_user(), the get_user_8() case
> on 32-bit wasn't zeroing the high register. (The jump to bad_get_user_8
> was accidentally dropped.) Restore the correct error handling
> destination (and rename the jump to using the expected ".L" prefix).
> 
> While here, switch to using a named argument ("size") for the call
> template ("%c4" to "%c[size]") as already used in the other call
> templates in this file.
> 
> Found after moving the usercopy selftests to KUnit:
> 
>       # usercopy_test_invalid: EXPECTATION FAILED at
>       lib/usercopy_kunit.c:278
>       Expected val_u64 == 0, but
>           val_u64 == -60129542144 (0xfffffff200000000)
> 
> Reported-by: David Gow <davidgow@google.com>
> Closes: https://lore.kernel.org/all/CABVgOSn=tb=Lj9SxHuT4_9MTjjKVxsq-ikdXC4kGHO4CfKVmGQ@mail.gmail.com
> Fixes: b19b74bc99b1 ("x86/mm: Rework address range check in get_user() and put_user()")
> Signed-off-by: Kees Cook <kees@kernel.org>
> ---
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: Borislav Petkov <bp@alien8.de>
> Cc: Dave Hansen <dave.hansen@linux.intel.com>
> Cc: x86@kernel.org
> Cc: "H. Peter Anvin" <hpa@zytor.com>
> Cc: Sean Christopherson <seanjc@google.com>
> Cc: Peter Zijlstra <peterz@infradead.org>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
> Cc: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
> Cc: Nadav Amit <nadav.amit@gmail.com>
> Cc: Masahiro Yamada <masahiroy@kernel.org>
> ---
>  arch/x86/include/asm/uaccess.h | 4 ++--
>  arch/x86/lib/getuser.S         | 6 +++++-
>  2 files changed, 7 insertions(+), 3 deletions(-)
> 

Hi,

This is the friendly patch-bot of Greg Kroah-Hartman.  You have sent him
a patch that has triggered this response.  He used to manually respond
to these common problems, but in order to save his sanity (he kept
writing the same thing over and over, yet to different people), I was
created.  Hopefully you will not take offence and will fix the problem
in your patch and resubmit it so that it can be accepted into the Linux
kernel tree.

You are receiving this message because of the following common error(s)
as indicated below:

- You have marked a patch with a "Fixes:" tag for a commit that is in an
  older released kernel, yet you do not have a cc: stable line in the
  signed-off-by area at all, which means that the patch will not be
  applied to any older kernel releases.  To properly fix this, please
  follow the documented rules in the
  Documentation/process/stable-kernel-rules.rst file for how to resolve
  this.

If you wish to discuss this problem further, or you have questions about
how to resolve this issue, please feel free to respond to this email and
Greg will reply once he has dug out from the pending patches received
from other developers.

thanks,

greg k-h's patch email bot
Zhuo, Qiuxu June 11, 2024, 6:57 a.m. UTC | #3
> From: Kees Cook <kees@kernel.org>
> [...]
> Subject: [PATCH] x86/uaccess: Fix missed zeroing of ia32 u64 get_user() range
> checking
> 
> When reworking the range checking for get_user(), the get_user_8() case on
> 32-bit wasn't zeroing the high register. (The jump to bad_get_user_8 was
> accidentally dropped.) Restore the correct error handling destination (and
> rename the jump to using the expected ".L" prefix).
> 
> While here, switch to using a named argument ("size") for the call template
> ("%c4" to "%c[size]") as already used in the other call templates in this file.
> 
> Found after moving the usercopy selftests to KUnit:
> 
>       # usercopy_test_invalid: EXPECTATION FAILED at
>       lib/usercopy_kunit.c:278
>       Expected val_u64 == 0, but
>           val_u64 == -60129542144 (0xfffffff200000000)
> 
> Reported-by: David Gow <davidgow@google.com>
> Closes: https://lore.kernel.org/all/CABVgOSn=tb=Lj9SxHuT4_9MTjjKVxsq-
> ikdXC4kGHO4CfKVmGQ@mail.gmail.com
> Fixes: b19b74bc99b1 ("x86/mm: Rework address range check in get_user()
> and put_user()")
> Signed-off-by: Kees Cook <kees@kernel.org>
> [...]
>  arch/x86/include/asm/uaccess.h | 4 ++--
>  arch/x86/lib/getuser.S         | 6 +++++-
>  2 files changed, 7 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/x86/include/asm/uaccess.h
> b/arch/x86/include/asm/uaccess.h index 0f9bab92a43d..3a7755c1a441
> 100644
> --- a/arch/x86/include/asm/uaccess.h
> +++ b/arch/x86/include/asm/uaccess.h
> @@ -78,10 +78,10 @@ extern int __get_user_bad(void);
>  	int __ret_gu;							\
>  	register __inttype(*(ptr)) __val_gu asm("%"_ASM_DX);		\
>  	__chk_user_ptr(ptr);						\
> -	asm volatile("call __" #fn "_%c4"				\
> +	asm volatile("call __" #fn "_%c[size]"				\
>  		     : "=a" (__ret_gu), "=r" (__val_gu),		\
>  			ASM_CALL_CONSTRAINT
> 	\
> -		     : "0" (ptr), "i" (sizeof(*(ptr))));		\
> +		     : "0" (ptr), [size] "i" (sizeof(*(ptr))));		\
>  	instrument_get_user(__val_gu);
> 	\
>  	(x) = (__force __typeof__(*(ptr))) __val_gu;			\
>  	__builtin_expect(__ret_gu, 0);					\
> diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S index
> 10d5ed8b5990..a1cb3a4e6742 100644
> --- a/arch/x86/lib/getuser.S
> +++ b/arch/x86/lib/getuser.S
> @@ -44,7 +44,11 @@
>  	or %rdx, %rax
>  .else
>  	cmp $TASK_SIZE_MAX-\size+1, %eax
> +.if \size != 8
>  	jae .Lbad_get_user
> +.else
> +	jae .Lbad_get_user_8
> +.endif
>  	sbb %edx, %edx		/* array_index_mask_nospec() */
>  	and %edx, %eax
>  .endif
> @@ -154,7 +158,7 @@ SYM_CODE_END(__get_user_handle_exception)
>  #ifdef CONFIG_X86_32
>  SYM_CODE_START_LOCAL(__get_user_8_handle_exception)
>  	ASM_CLAC
> -bad_get_user_8:
> +.Lbad_get_user_8:
>  	xor %edx,%edx
>  	xor %ecx,%ecx
>  	mov $(-EFAULT),%_ASM_AX
> --
> 2.34.1

LGTM. Thanks!

Reviewed-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
Kirill A . Shutemov June 11, 2024, 10:29 a.m. UTC | #4
On Mon, Jun 10, 2024 at 02:02:27PM -0700, Kees Cook wrote:
> When reworking the range checking for get_user(), the get_user_8() case
> on 32-bit wasn't zeroing the high register. (The jump to bad_get_user_8
> was accidentally dropped.) Restore the correct error handling
> destination (and rename the jump to using the expected ".L" prefix).

Oh. My bad.

Reviewed-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
diff mbox series

Patch

diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index 0f9bab92a43d..3a7755c1a441 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -78,10 +78,10 @@  extern int __get_user_bad(void);
 	int __ret_gu;							\
 	register __inttype(*(ptr)) __val_gu asm("%"_ASM_DX);		\
 	__chk_user_ptr(ptr);						\
-	asm volatile("call __" #fn "_%c4"				\
+	asm volatile("call __" #fn "_%c[size]"				\
 		     : "=a" (__ret_gu), "=r" (__val_gu),		\
 			ASM_CALL_CONSTRAINT				\
-		     : "0" (ptr), "i" (sizeof(*(ptr))));		\
+		     : "0" (ptr), [size] "i" (sizeof(*(ptr))));		\
 	instrument_get_user(__val_gu);					\
 	(x) = (__force __typeof__(*(ptr))) __val_gu;			\
 	__builtin_expect(__ret_gu, 0);					\
diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S
index 10d5ed8b5990..a1cb3a4e6742 100644
--- a/arch/x86/lib/getuser.S
+++ b/arch/x86/lib/getuser.S
@@ -44,7 +44,11 @@ 
 	or %rdx, %rax
 .else
 	cmp $TASK_SIZE_MAX-\size+1, %eax
+.if \size != 8
 	jae .Lbad_get_user
+.else
+	jae .Lbad_get_user_8
+.endif
 	sbb %edx, %edx		/* array_index_mask_nospec() */
 	and %edx, %eax
 .endif
@@ -154,7 +158,7 @@  SYM_CODE_END(__get_user_handle_exception)
 #ifdef CONFIG_X86_32
 SYM_CODE_START_LOCAL(__get_user_8_handle_exception)
 	ASM_CLAC
-bad_get_user_8:
+.Lbad_get_user_8:
 	xor %edx,%edx
 	xor %ecx,%ecx
 	mov $(-EFAULT),%_ASM_AX