|
|
e293be |
From 0a2d7d9b1e63dd28baf6c8e1416b64a33f89c900 Mon Sep 17 00:00:00 2001
|
|
|
e293be |
From: Linus Torvalds <torvalds@linux-foundation.org>
|
|
|
e293be |
Date: Tue, 23 Feb 2016 14:58:52 -0800
|
|
|
e293be |
Subject: x86: fix SMAP in 32-bit environments
|
|
|
e293be |
|
|
|
e293be |
commit de9e478b9d49f3a0214310d921450cf5bb4a21e6 upstream.
|
|
|
e293be |
|
|
|
e293be |
In commit 11f1a4b9755f ("x86: reorganize SMAP handling in user space
|
|
|
e293be |
accesses") I changed how the stac/clac instructions were generated
|
|
|
e293be |
around the user space accesses, which then made it possible to do
|
|
|
e293be |
batched accesses efficiently for user string copies etc.
|
|
|
e293be |
|
|
|
e293be |
However, in doing so, I completely spaced out, and didn't even think
|
|
|
e293be |
about the 32-bit case. And nobody really even seemed to notice, because
|
|
|
e293be |
SMAP doesn't even exist until modern Skylake processors, and you'd have
|
|
|
e293be |
to be crazy to run 32-bit kernels on a modern CPU.
|
|
|
e293be |
|
|
|
e293be |
Which brings us to Andy Lutomirski.
|
|
|
e293be |
|
|
|
e293be |
He actually tested the 32-bit kernel on new hardware, and noticed that
|
|
|
e293be |
it doesn't work. My bad. The trivial fix is to add the required
|
|
|
e293be |
uaccess begin/end markers around the raw accesses in <asm/uaccess_32.h>.
|
|
|
e293be |
|
|
|
e293be |
I feel a bit bad about this patch, just because that header file really
|
|
|
e293be |
should be cleaned up to avoid all the duplicated code in it, and this
|
|
|
e293be |
commit just expands on the problem. But this just fixes the bug without
|
|
|
e293be |
any bigger cleanup surgery.
|
|
|
e293be |
|
|
|
e293be |
Reported-and-tested-by: Andy Lutomirski <luto@kernel.org>
|
|
|
e293be |
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
|
|
|
e293be |
[bwh: Backported to 3.16: There's no 'case 8' in __copy_to_user_inatomic()]
|
|
|
e293be |
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
|
|
|
e293be |
---
|
|
|
e293be |
arch/x86/include/asm/uaccess_32.h | 24 ++++++++++++++++++++++++
|
|
|
e293be |
1 file changed, 24 insertions(+)
|
|
|
e293be |
|
|
|
e293be |
diff --git a/arch/x86/include/asm/uaccess_32.h b/arch/x86/include/asm/uaccess_32.h
|
|
|
e293be |
index 3c03a5de64d3..b25d109fb95a 100644
|
|
|
e293be |
--- a/arch/x86/include/asm/uaccess_32.h
|
|
|
e293be |
+++ b/arch/x86/include/asm/uaccess_32.h
|
|
|
e293be |
@@ -48,16 +48,22 @@ __copy_to_user_inatomic(void __user *to, const void *from, unsigned long n)
|
|
|
e293be |
|
|
|
e293be |
switch (n) {
|
|
|
e293be |
case 1:
|
|
|
e293be |
+ __uaccess_begin();
|
|
|
e293be |
__put_user_size(*(u8 *)from, (u8 __user *)to,
|
|
|
e293be |
1, ret, 1);
|
|
|
e293be |
+ __uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
case 2:
|
|
|
e293be |
+ __uaccess_begin();
|
|
|
e293be |
__put_user_size(*(u16 *)from, (u16 __user *)to,
|
|
|
e293be |
2, ret, 2);
|
|
|
e293be |
+ __uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
case 4:
|
|
|
e293be |
+ __uaccess_begin();
|
|
|
e293be |
__put_user_size(*(u32 *)from, (u32 __user *)to,
|
|
|
e293be |
4, ret, 4);
|
|
|
e293be |
+ __uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
}
|
|
|
e293be |
}
|
|
|
e293be |
@@ -98,13 +104,19 @@ __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
|
|
|
e293be |
|
|
|
e293be |
switch (n) {
|
|
|
e293be |
case 1:
|
|
|
e293be |
+ __uaccess_begin();
|
|
|
e293be |
__get_user_size(*(u8 *)to, from, 1, ret, 1);
|
|
|
e293be |
+ __uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
case 2:
|
|
|
e293be |
+ __uaccess_begin();
|
|
|
e293be |
__get_user_size(*(u16 *)to, from, 2, ret, 2);
|
|
|
e293be |
+ __uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
case 4:
|
|
|
e293be |
+ __uaccess_begin();
|
|
|
e293be |
__get_user_size(*(u32 *)to, from, 4, ret, 4);
|
|
|
e293be |
+ __uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
}
|
|
|
e293be |
}
|
|
|
e293be |
@@ -142,13 +154,19 @@ __copy_from_user(void *to, const void __user *from, unsigned long n)
|
|
|
e293be |
|
|
|
e293be |
switch (n) {
|
|
|
e293be |
case 1:
|
|
|
e293be |
+ __uaccess_begin();
|
|
|
e293be |
__get_user_size(*(u8 *)to, from, 1, ret, 1);
|
|
|
e293be |
+ __uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
case 2:
|
|
|
e293be |
+ __uaccess_begin();
|
|
|
e293be |
__get_user_size(*(u16 *)to, from, 2, ret, 2);
|
|
|
e293be |
+ __uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
case 4:
|
|
|
e293be |
+ __uaccess_begin();
|
|
|
e293be |
__get_user_size(*(u32 *)to, from, 4, ret, 4);
|
|
|
e293be |
+ __uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
}
|
|
|
e293be |
}
|
|
|
e293be |
@@ -164,13 +182,19 @@ static __always_inline unsigned long __copy_from_user_nocache(void *to,
|
|
|
e293be |
|
|
|
e293be |
switch (n) {
|
|
|
e293be |
case 1:
|
|
|
e293be |
+ __uaccess_begin();
|
|
|
e293be |
__get_user_size(*(u8 *)to, from, 1, ret, 1);
|
|
|
e293be |
+ __uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
case 2:
|
|
|
e293be |
+ __uaccess_begin();
|
|
|
e293be |
__get_user_size(*(u16 *)to, from, 2, ret, 2);
|
|
|
e293be |
+ __uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
case 4:
|
|
|
e293be |
+ __uaccess_begin();
|
|
|
e293be |
__get_user_size(*(u32 *)to, from, 4, ret, 4);
|
|
|
e293be |
+ __uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
}
|
|
|
e293be |
}
|
|
|
e293be |
--
|
|
|
e293be |
cgit 1.2-0.3.lf.el7
|
|
|
e293be |
|
|
|
e293be |
From 98ce99aa23b43c3dc736cd0354537fca029d69cb Mon Sep 17 00:00:00 2001
|
|
|
e293be |
From: Dan Williams <dan.j.williams@intel.com>
|
|
|
e293be |
Date: Mon, 29 Jan 2018 17:02:49 -0800
|
|
|
e293be |
Subject: x86/uaccess: Use __uaccess_begin_nospec() and uaccess_try_nospec
|
|
|
e293be |
|
|
|
e293be |
commit 304ec1b050310548db33063e567123fae8fd0301 upstream.
|
|
|
e293be |
|
|
|
e293be |
Quoting Linus:
|
|
|
e293be |
|
|
|
e293be |
I do think that it would be a good idea to very expressly document
|
|
|
e293be |
the fact that it's not that the user access itself is unsafe. I do
|
|
|
e293be |
agree that things like "get_user()" want to be protected, but not
|
|
|
e293be |
because of any direct bugs or problems with get_user() and friends,
|
|
|
e293be |
but simply because get_user() is an excellent source of a pointer
|
|
|
e293be |
that is obviously controlled from a potentially attacking user
|
|
|
e293be |
space. So it's a prime candidate for then finding _subsequent_
|
|
|
e293be |
accesses that can then be used to perturb the cache.
|
|
|
e293be |
|
|
|
e293be |
__uaccess_begin_nospec() covers __get_user() and copy_from_iter() where the
|
|
|
e293be |
limit check is far away from the user pointer de-reference. In those cases
|
|
|
e293be |
a barrier_nospec() prevents speculation with a potential pointer to
|
|
|
e293be |
privileged memory. uaccess_try_nospec covers get_user_try.
|
|
|
e293be |
|
|
|
e293be |
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
|
|
|
e293be |
Suggested-by: Andi Kleen <ak@linux.intel.com>
|
|
|
e293be |
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
|
|
|
e293be |
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
|
|
|
e293be |
Cc: linux-arch@vger.kernel.org
|
|
|
e293be |
Cc: Kees Cook <keescook@chromium.org>
|
|
|
e293be |
Cc: kernel-hardening@lists.openwall.com
|
|
|
e293be |
Cc: gregkh@linuxfoundation.org
|
|
|
e293be |
Cc: Al Viro <viro@zeniv.linux.org.uk>
|
|
|
e293be |
Cc: alan@linux.intel.com
|
|
|
e293be |
Link: https://lkml.kernel.org/r/151727416953.33451.10508284228526170604.stgit@dwillia2-desk3.amr.corp.intel.com
|
|
|
e293be |
[bwh: Backported to 3.16:
|
|
|
e293be |
- Convert several more functions to use __uaccess_begin_nospec(), that
|
|
|
e293be |
are just wrappers in mainline
|
|
|
e293be |
- There's no 'case 8' in __copy_to_user_inatomic()
|
|
|
e293be |
- Adjust context]
|
|
|
e293be |
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
|
|
|
e293be |
---
|
|
|
e293be |
arch/x86/include/asm/uaccess.h | 6 +++---
|
|
|
e293be |
arch/x86/include/asm/uaccess_32.h | 24 ++++++++++++------------
|
|
|
e293be |
arch/x86/include/asm/uaccess_64.h | 20 ++++++++++----------
|
|
|
e293be |
arch/x86/lib/usercopy_32.c | 10 +++++-----
|
|
|
e293be |
4 files changed, 30 insertions(+), 30 deletions(-)
|
|
|
e293be |
|
|
|
e293be |
diff --git a/arch/x86/include/asm/uaccess_32.h b/arch/x86/include/asm/uaccess_32.h
|
|
|
e293be |
index b25d109fb95a..c803818cedfb 100644
|
|
|
e293be |
--- a/arch/x86/include/asm/uaccess_32.h
|
|
|
e293be |
+++ b/arch/x86/include/asm/uaccess_32.h
|
|
|
e293be |
@@ -48,19 +48,19 @@ __copy_to_user_inatomic(void __user *to, const void *from, unsigned long n)
|
|
|
e293be |
|
|
|
e293be |
switch (n) {
|
|
|
e293be |
case 1:
|
|
|
e293be |
- __uaccess_begin();
|
|
|
e293be |
+ __uaccess_begin_nospec();
|
|
|
e293be |
__put_user_size(*(u8 *)from, (u8 __user *)to,
|
|
|
e293be |
1, ret, 1);
|
|
|
e293be |
__uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
case 2:
|
|
|
e293be |
- __uaccess_begin();
|
|
|
e293be |
+ __uaccess_begin_nospec();
|
|
|
e293be |
__put_user_size(*(u16 *)from, (u16 __user *)to,
|
|
|
e293be |
2, ret, 2);
|
|
|
e293be |
__uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
case 4:
|
|
|
e293be |
- __uaccess_begin();
|
|
|
e293be |
+ __uaccess_begin_nospec();
|
|
|
e293be |
__put_user_size(*(u32 *)from, (u32 __user *)to,
|
|
|
e293be |
4, ret, 4);
|
|
|
e293be |
__uaccess_end();
|
|
|
e293be |
@@ -104,17 +104,17 @@ __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
|
|
|
e293be |
|
|
|
e293be |
switch (n) {
|
|
|
e293be |
case 1:
|
|
|
e293be |
- __uaccess_begin();
|
|
|
e293be |
+ __uaccess_begin_nospec();
|
|
|
e293be |
__get_user_size(*(u8 *)to, from, 1, ret, 1);
|
|
|
e293be |
__uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
case 2:
|
|
|
e293be |
- __uaccess_begin();
|
|
|
e293be |
+ __uaccess_begin_nospec();
|
|
|
e293be |
__get_user_size(*(u16 *)to, from, 2, ret, 2);
|
|
|
e293be |
__uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
case 4:
|
|
|
e293be |
- __uaccess_begin();
|
|
|
e293be |
+ __uaccess_begin_nospec();
|
|
|
e293be |
__get_user_size(*(u32 *)to, from, 4, ret, 4);
|
|
|
e293be |
__uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
@@ -154,17 +154,17 @@ __copy_from_user(void *to, const void __user *from, unsigned long n)
|
|
|
e293be |
|
|
|
e293be |
switch (n) {
|
|
|
e293be |
case 1:
|
|
|
e293be |
- __uaccess_begin();
|
|
|
e293be |
+ __uaccess_begin_nospec();
|
|
|
e293be |
__get_user_size(*(u8 *)to, from, 1, ret, 1);
|
|
|
e293be |
__uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
case 2:
|
|
|
e293be |
- __uaccess_begin();
|
|
|
e293be |
+ __uaccess_begin_nospec();
|
|
|
e293be |
__get_user_size(*(u16 *)to, from, 2, ret, 2);
|
|
|
e293be |
__uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
case 4:
|
|
|
e293be |
- __uaccess_begin();
|
|
|
e293be |
+ __uaccess_begin_nospec();
|
|
|
e293be |
__get_user_size(*(u32 *)to, from, 4, ret, 4);
|
|
|
e293be |
__uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
@@ -182,17 +182,17 @@ static __always_inline unsigned long __copy_from_user_nocache(void *to,
|
|
|
e293be |
|
|
|
e293be |
switch (n) {
|
|
|
e293be |
case 1:
|
|
|
e293be |
- __uaccess_begin();
|
|
|
e293be |
+ __uaccess_begin_nospec();
|
|
|
e293be |
__get_user_size(*(u8 *)to, from, 1, ret, 1);
|
|
|
e293be |
__uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
case 2:
|
|
|
e293be |
- __uaccess_begin();
|
|
|
e293be |
+ __uaccess_begin_nospec();
|
|
|
e293be |
__get_user_size(*(u16 *)to, from, 2, ret, 2);
|
|
|
e293be |
__uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
case 4:
|
|
|
e293be |
- __uaccess_begin();
|
|
|
e293be |
+ __uaccess_begin_nospec();
|
|
|
e293be |
__get_user_size(*(u32 *)to, from, 4, ret, 4);
|
|
|
e293be |
__uaccess_end();
|
|
|
e293be |
return ret;
|
|
|
e293be |
diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c
|
|
|
e293be |
index 7f6e7dd46215..de848bc95a9f 100644
|
|
|
e293be |
--- a/arch/x86/lib/usercopy_32.c
|
|
|
e293be |
+++ b/arch/x86/lib/usercopy_32.c
|
|
|
e293be |
@@ -570,7 +570,7 @@ do { \
|
|
|
e293be |
unsigned long __copy_to_user_ll(void __user *to, const void *from,
|
|
|
e293be |
unsigned long n)
|
|
|
e293be |
{
|
|
|
e293be |
- __uaccess_begin();
|
|
|
e293be |
+ __uaccess_begin_nospec();
|
|
|
e293be |
if (movsl_is_ok(to, from, n))
|
|
|
e293be |
__copy_user(to, from, n);
|
|
|
e293be |
else
|
|
|
e293be |
--
|
|
|
e293be |
cgit 1.2-0.3.lf.el7
|
|
|
e293be |
|