From: Ingo Molnar <mingo@kernel.org>
To: Mateusz Guzik <mjguzik@gmail.com>
Cc: mingo@redhat.com, x86@kernel.org, linux-kernel@vger.kernel.org,
Linus Torvalds <torvalds@linux-foundation.org>,
Peter Zijlstra <peterz@infradead.org>,
Uros Bizjak <ubizjak@gmail.com>, "H. Peter Anvin" <hpa@zytor.com>
Subject: Re: [PATCH] x86: predict __access_ok() returning true
Date: Tue, 1 Apr 2025 22:35:34 +0200 [thread overview]
Message-ID: <Z-xOFuT9Sl6VuFYi@gmail.com> (raw)
In-Reply-To: <20250401203029.1132135-1-mjguzik@gmail.com>
* Mateusz Guzik <mjguzik@gmail.com> wrote:
> This works around what seems to be an optimization bug in gcc (at least
> 13.3.0), where it predicts access_ok() to fail despite the hint to the
> contrary.
>
> _copy_to_user contains:
> if (access_ok(to, n)) {
> instrument_copy_to_user(to, from, n);
> n = raw_copy_to_user(to, from, n);
> }
>
> Where access_ok is likely(__access_ok(addr, size)), yet the compiler
> emits conditional jumps forward for the case where it succeeds:
>
> <+0>: endbr64
> <+4>: mov %rdx,%rcx
> <+7>: mov %rdx,%rax
> <+10>: xor %edx,%edx
> <+12>: add %rdi,%rcx
> <+15>: setb %dl
> <+18>: movabs $0x123456789abcdef,%r8
> <+28>: test %rdx,%rdx
> <+31>: jne 0xffffffff81b3b7c6 <_copy_to_user+38>
> <+33>: cmp %rcx,%r8
> <+36>: jae 0xffffffff81b3b7cb <_copy_to_user+43>
> <+38>: jmp 0xffffffff822673e0 <__x86_return_thunk>
> <+43>: nop
> <+44>: nop
> <+45>: nop
> <+46>: mov %rax,%rcx
> <+49>: rep movsb %ds:(%rsi),%es:(%rdi)
> <+51>: nop
> <+52>: nop
> <+53>: nop
> <+54>: mov %rcx,%rax
> <+57>: nop
> <+58>: nop
> <+59>: nop
> <+60>: jmp 0xffffffff822673e0 <__x86_return_thunk>
>
> Patching _copy_to_user() to likely() around the access_ok() use does
> not change the asm.
>
> However, spelling out the prediction *within* __access_ok() does the
> trick:
> <+0>: endbr64
> <+4>: xor %eax,%eax
> <+6>: mov %rdx,%rcx
> <+9>: add %rdi,%rdx
> <+12>: setb %al
> <+15>: movabs $0x123456789abcdef,%r8
> <+25>: test %rax,%rax
> <+28>: jne 0xffffffff81b315e6 <_copy_to_user+54>
> <+30>: cmp %rdx,%r8
> <+33>: jb 0xffffffff81b315e6 <_copy_to_user+54>
> <+35>: nop
> <+36>: nop
> <+37>: nop
> <+38>: rep movsb %ds:(%rsi),%es:(%rdi)
> <+40>: nop
> <+41>: nop
> <+42>: nop
> <+43>: nop
> <+44>: nop
> <+45>: nop
> <+46>: mov %rcx,%rax
> <+49>: jmp 0xffffffff82255ba0 <__x86_return_thunk>
> <+54>: mov %rcx,%rax
> <+57>: jmp 0xffffffff82255ba0 <__x86_return_thunk>
>
> Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
> ---
>
> I did not investigate what's going on here. It may be other spots are
> also suffering.
>
> If someone commits to figuring out what went wrong I'll be happy to drop
> this patch. Otherwise this can be worked around at least for access_ok()
> consumers.
>
> arch/x86/include/asm/uaccess_64.h | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h
> index c52f0133425b..30c912375260 100644
> --- a/arch/x86/include/asm/uaccess_64.h
> +++ b/arch/x86/include/asm/uaccess_64.h
> @@ -98,11 +98,11 @@ static inline void __user *mask_user_address(const void __user *ptr)
> static inline bool __access_ok(const void __user *ptr, unsigned long size)
> {
> if (__builtin_constant_p(size <= PAGE_SIZE) && size <= PAGE_SIZE) {
> - return valid_user_address(ptr);
> + return likely(valid_user_address(ptr));
> } else {
> unsigned long sum = size + (__force unsigned long)ptr;
>
> - return valid_user_address(sum) && sum >= (__force unsigned long)ptr;
> + return likely(valid_user_address(sum) && sum >= (__force unsigned long)ptr);
Cannot we put this into valid_user_address() definition, via something
like the below patch?
It's also the right place to have the hint: that user addresses are
valid is the common case we optimize for.
Thanks,
Ingo
arch/x86/include/asm/uaccess_64.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h
index c52f0133425b..4c13883371aa 100644
--- a/arch/x86/include/asm/uaccess_64.h
+++ b/arch/x86/include/asm/uaccess_64.h
@@ -54,7 +54,7 @@ static inline unsigned long __untagged_addr_remote(struct mm_struct *mm,
#endif
#define valid_user_address(x) \
- ((__force unsigned long)(x) <= runtime_const_ptr(USER_PTR_MAX))
+ likely((__force unsigned long)(x) <= runtime_const_ptr(USER_PTR_MAX))
/*
* Masking the user address is an alternative to a conditional
next prev parent reply other threads:[~2025-04-01 20:35 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-01 20:30 [PATCH] x86: predict __access_ok() returning true Mateusz Guzik
2025-04-01 20:35 ` Ingo Molnar [this message]
2025-04-01 20:43 ` Ingo Molnar
2025-04-01 20:49 ` Mateusz Guzik
2025-04-01 21:00 ` Ingo Molnar
2025-04-01 21:11 ` Mateusz Guzik
2025-04-02 7:15 ` Uros Bizjak
2025-04-09 21:32 ` [tip: x86/asm] x86/uaccess: Predict valid_user_address() " tip-bot2 for Mateusz Guzik
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=Z-xOFuT9Sl6VuFYi@gmail.com \
--to=mingo@kernel.org \
--cc=hpa@zytor.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=mjguzik@gmail.com \
--cc=peterz@infradead.org \
--cc=torvalds@linux-foundation.org \
--cc=ubizjak@gmail.com \
--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.