From: David Gow <davidgow@google.com>
To: Linus Torvalds <torvalds@linux-foundation.org>
Cc: David Gow <davidgow@google.com>, Kees Cook <kees@kernel.org>,
Borislav Petkov <bp@alien8.de>,
Thomas Gleixner <tglx@linutronix.de>,
Ingo Molnar <mingo@redhat.com>,
Dave Hansen <dave.hansen@linux.intel.com>,
Peter Zijlstra <peterz@infradead.org>,
Andrew Morton <akpm@linux-foundation.org>,
"H . Peter Anvin" <hpa@zytor.com>,
x86@kernel.org, kunit-dev@googlegroups.com,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH] x86/uaccess: Zero the 8-byte get_range case on failure
Date: Thu, 1 Aug 2024 14:34:35 +0800 [thread overview]
Message-ID: <20240801063442.553090-2-davidgow@google.com> (raw)
In-Reply-To: <CAHk-=wgPD+=Wi8T0A59muq46LxquhsWQSyPV6KM5xa8V1UPK=Q@mail.gmail.com>
On Wed, 31 Jul 2024 09:38:15 -0700 Linus Torvalds <torvalds@linux-foundation.org> wrote:
> On Wed, 31 Jul 2024 at 09:24, Linus Torvalds
> <torvalds@linux-foundation.org> wrote:
> >
> > My bad. My mental model these days is the 64-bit case, where the whole
> > 'check_range' thing is about address masking tricks, not the actual
> > conditional. So I didn't think of the "access_ok fails" case at all.
>
> Actually, now that I said that out loud, it made me go "why aren't we
> doing that on 32-bit too?"
>
> IOW, an alternative would be to just unify things more. Something like this?
>
> *ENTIRELY UNTESTED*.
I tested this on everything I had on hand, and it passes the usercopy
KUnit tests on:
- QEMU, in every config I tried
- A Core i7-4770K (Haswell), under KVM on a 64-bit host kernel
- A Core 2 Duo E6600, bare metal
- A 486/DX2, bare metal
The 486 seemed to treat the wraparound a bit differently: it's triggering
a General Protection Fault, and so giving the WARN() normally reserved
for non-canonical addresses.
>
> And no, this is not a NAK of David's patch. Last time I said "let's
> unify things", it caused this bug.
>
> I'm claiming that finishing that unification will fix the bug again,
> and I *think* we leave that top address unmapped on 32-bit x86 too,
> but this whole trick does very much depend on that "access to all-one
> address is guaranteed to fail".
>
> So this is the "maybe cleaner, but somebody really needs to
> double-check me" patch.
>
> Linus
>
I think this is right (there's definitely an unmapped page at the top),
but I'd want someone who knows better to verify that this won't do
something weird with segmentation and/or speculation with the 8-byte case
(if vm.mmap_min_addr is 0 and someone's mapped page 0).
The Intel manuals are very cagey about what happens with wraparound and
segmentation, and definitely seem to suggest that it's implementation
dependent:
"When the effective limit is FFFFFFFFH (4 GBytes), these accesses may or may not
cause the indicated exceptions. Behavior is implementation-specific and may
vary from one execution to another."
So I'm a little worried that there might be more cases where this works
differently. Does anyone know for sure if it's worth risking it?
Regardless, I tried making the same changes to put_user, and those work
equally well and pass the same tests (including with the WARN() on 486).
Combined patch below.
Cheers,
-- David
---
From 3fd12432efee3bbed26abb347244c5378b7bf7e9 Mon Sep 17 00:00:00 2001
From: Linus Torvalds <torvalds@linux-foundation.org>
Date: Thu, 1 Aug 2024 09:30:39 +0800
Subject: [PATCH] x86/uaccess: Use address masking for get_size on ia32
On x86_64 get_user and put_user rely on using address masking to force
any invalid addresses to the top of kernel address space, which is
unmapped, and then will trap. The 32-bit case has thus far just used a
comparison and a jump.
Use the address masking technique on ia32 as well (as the top page is
guaranteed to be unmapped here as well), to bring it into alignment with
the x86_64 implementation.
This also fixes the previous cleanup, which didn't zero the high bits if
a 64-bit get_user() was attempted with an invalid address, as in the
usercopy.usercopy_test_invalid KUnit test.
Fixes: 8a2462df1547 ("x86/uaccess: Improve the 8-byte getuser() case")
Co-developed-by: David Gow <davidgow@google.com>
Signed-off-by: David Gow <davidgow@google.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---
arch/x86/lib/getuser.S | 5 ++---
arch/x86/lib/putuser.S | 5 +++--
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S
index a314622aa093..3ee80b9c4f78 100644
--- a/arch/x86/lib/getuser.S
+++ b/arch/x86/lib/getuser.S
@@ -44,9 +44,9 @@
or %rdx, %rax
.else
cmp $TASK_SIZE_MAX-\size+1, %eax
- jae .Lbad_get_user
sbb %edx, %edx /* array_index_mask_nospec() */
- and %edx, %eax
+ not %edx
+ or %edx, %eax
.endif
.endm
@@ -153,7 +153,6 @@ EXPORT_SYMBOL(__get_user_nocheck_8)
SYM_CODE_START_LOCAL(__get_user_handle_exception)
ASM_CLAC
-.Lbad_get_user:
xor %edx,%edx
mov $(-EFAULT),%_ASM_AX
RET
diff --git a/arch/x86/lib/putuser.S b/arch/x86/lib/putuser.S
index 975c9c18263d..8896f6bcbf9c 100644
--- a/arch/x86/lib/putuser.S
+++ b/arch/x86/lib/putuser.S
@@ -39,7 +39,9 @@
or %rbx, %rcx
.else
cmp $TASK_SIZE_MAX-\size+1, %ecx
- jae .Lbad_put_user
+ sbb %ebx, %ebx
+ not %ebx
+ or %ebx, %ecx
.endif
.endm
@@ -128,7 +130,6 @@ EXPORT_SYMBOL(__put_user_nocheck_8)
SYM_CODE_START_LOCAL(__put_user_handle_exception)
ASM_CLAC
-.Lbad_put_user:
movl $-EFAULT,%ecx
RET
SYM_CODE_END(__put_user_handle_exception)
--
2.46.0.rc1.232.g9752f9e123-goog
next prev parent reply other threads:[~2024-08-01 6:35 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-07-31 7:30 [PATCH] x86/uaccess: Zero the 8-byte get_range case on failure David Gow
2024-07-31 16:24 ` Linus Torvalds
2024-07-31 16:38 ` Linus Torvalds
2024-08-01 6:34 ` David Gow [this message]
2024-08-01 16:24 ` Linus Torvalds
2024-08-01 19:08 ` Thomas Gleixner
2024-08-01 19:28 ` [tip: x86/urgent] x86/uaccess: Zero the 8-byte get_range case on failure on 32-bit tip-bot2 for David Gow
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240801063442.553090-2-davidgow@google.com \
--to=davidgow@google.com \
--cc=akpm@linux-foundation.org \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=hpa@zytor.com \
--cc=kees@kernel.org \
--cc=kunit-dev@googlegroups.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=peterz@infradead.org \
--cc=tglx@linutronix.de \
--cc=torvalds@linux-foundation.org \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.