Skip to content

Commit 0fc810a

Browse files
committed
x86/uaccess: Avoid barrier_nospec() in 64-bit copy_from_user()
The barrier_nospec() in 64-bit copy_from_user() is slow. Instead use pointer masking to force the user pointer to all 1's for an invalid address. The kernel test robot reports a 2.6% improvement in the per_thread_ops benchmark [1]. This is a variation on a patch originally by Josh Poimboeuf [2]. Link: https://lore.kernel.org/[email protected] [1] Link: https://lore.kernel.org/5b887fe4c580214900e21f6c61095adf9a142735.1730166635.git.jpoimboe@kernel.org [2] Tested-and-reviewed-by: Josh Poimboeuf <[email protected]> Cc: Kirill A. Shutemov <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 14b7d43 commit 0fc810a

File tree

1 file changed

+15
-6
lines changed

1 file changed

+15
-6
lines changed

include/linux/uaccess.h

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#else
3939
#define can_do_masked_user_access() 0
4040
#define masked_user_access_begin(src) NULL
41+
#define mask_user_address(src) (src)
4142
#endif
4243

4344
/*
@@ -159,19 +160,27 @@ _inline_copy_from_user(void *to, const void __user *from, unsigned long n)
159160
{
160161
unsigned long res = n;
161162
might_fault();
162-
if (!should_fail_usercopy() && likely(access_ok(from, n))) {
163+
if (should_fail_usercopy())
164+
goto fail;
165+
if (can_do_masked_user_access())
166+
from = mask_user_address(from);
167+
else {
168+
if (!access_ok(from, n))
169+
goto fail;
163170
/*
164171
* Ensure that bad access_ok() speculation will not
165172
* lead to nasty side effects *after* the copy is
166173
* finished:
167174
*/
168175
barrier_nospec();
169-
instrument_copy_from_user_before(to, from, n);
170-
res = raw_copy_from_user(to, from, n);
171-
instrument_copy_from_user_after(to, from, n, res);
172176
}
173-
if (unlikely(res))
174-
memset(to + (n - res), 0, res);
177+
instrument_copy_from_user_before(to, from, n);
178+
res = raw_copy_from_user(to, from, n);
179+
instrument_copy_from_user_after(to, from, n, res);
180+
if (likely(!res))
181+
return 0;
182+
fail:
183+
memset(to + (n - res), 0, res);
175184
return res;
176185
}
177186
extern __must_check unsigned long

0 commit comments

Comments
 (0)