Message ID | 151703974000.26578.2874964402485950653.stgit@dwillia2-desk3.amr.corp.intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
* Dan Williams <dan.j.williams@intel.com> wrote: > Quoting Linus: > > I do think that it would be a good idea to very expressly document > the fact that it's not that the user access itself is unsafe. I do > agree that things like "get_user()" want to be protected, but not > because of any direct bugs or problems with get_user() and friends, > but simply because get_user() is an excellent source of a pointer > that is obviously controlled from a potentially attacking user > space. So it's a prime candidate for then finding _subsequent_ > accesses that can then be used to perturb the cache. > > '__uaccess_begin_nospec' covers '__get_user' and 'copy_from_iter' where > the limit check is far away from the user pointer de-reference. In those > cases an 'lfence' prevents speculation with a potential pointer to > privileged memory. (Same style comments as for the previous patches) > > Suggested-by: Linus Torvalds <torvalds@linux-foundation.org> > Suggested-by: Andi Kleen <ak@linux.intel.com> > Cc: Al Viro <viro@zeniv.linux.org.uk> > Cc: Kees Cook <keescook@chromium.org> > Cc: Thomas Gleixner <tglx@linutronix.de> > Cc: "H. Peter Anvin" <hpa@zytor.com> > Cc: Ingo Molnar <mingo@redhat.com> > Cc: x86@kernel.org > Signed-off-by: Dan Williams <dan.j.williams@intel.com> > --- > arch/x86/include/asm/uaccess.h | 6 +++--- > arch/x86/include/asm/uaccess_32.h | 6 +++--- > arch/x86/include/asm/uaccess_64.h | 12 ++++++------ > arch/x86/lib/usercopy_32.c | 8 ++++---- > 4 files changed, 16 insertions(+), 16 deletions(-) > > diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h > index 626caf58183a..a930585fa3b5 100644 > --- a/arch/x86/include/asm/uaccess.h > +++ b/arch/x86/include/asm/uaccess.h > @@ -450,7 +450,7 @@ do { \ > ({ \ > int __gu_err; \ > __inttype(*(ptr)) __gu_val; \ > - __uaccess_begin(); \ > + __uaccess_begin_nospec(); \ > __get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \ > __uaccess_end(); \ > (x) = (__force __typeof__(*(ptr)))__gu_val; \ > @@ -557,7 +557,7 @@ struct __large_struct { unsigned long buf[100]; }; > * get_user_ex(...); > * } get_user_catch(err) > */ > -#define get_user_try uaccess_try > +#define get_user_try uaccess_try_nospec > #define get_user_catch(err) uaccess_catch(err) > > #define get_user_ex(x, ptr) do { \ > @@ -591,7 +591,7 @@ extern void __cmpxchg_wrong_size(void) > __typeof__(ptr) __uval = (uval); \ > __typeof__(*(ptr)) __old = (old); \ > __typeof__(*(ptr)) __new = (new); \ > - __uaccess_begin(); \ > + __uaccess_begin_nospec(); \ > else > n = __copy_user_intel(to, from, n); > - clac(); > + __uaccess_end(); > return n; > } > EXPORT_SYMBOL(__copy_user_ll); > @@ -344,7 +344,7 @@ EXPORT_SYMBOL(__copy_user_ll); > unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *from, > unsigned long n) > { > - stac(); > + __uaccess_begin_nospec(); > #ifdef CONFIG_X86_INTEL_USERCOPY > if (n > 64 && static_cpu_has(X86_FEATURE_XMM2)) > n = __copy_user_intel_nocache(to, from, n); > @@ -353,7 +353,7 @@ unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *fr > #else > __copy_user(to, from, n); > #endif > - clac(); > + __uaccess_end(); > return n; > } > EXPORT_SYMBOL(__copy_from_user_ll_nocache_nozero); > These three chunks appears to be unrelated changes changing open-coded clac()s to __uaccess_end() calls correctly: please split these out into a separate patch. Thanks, Ingo
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index 626caf58183a..a930585fa3b5 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h @@ -450,7 +450,7 @@ do { \ ({ \ int __gu_err; \ __inttype(*(ptr)) __gu_val; \ - __uaccess_begin(); \ + __uaccess_begin_nospec(); \ __get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \ __uaccess_end(); \ (x) = (__force __typeof__(*(ptr)))__gu_val; \ @@ -557,7 +557,7 @@ struct __large_struct { unsigned long buf[100]; }; * get_user_ex(...); * } get_user_catch(err) */ -#define get_user_try uaccess_try +#define get_user_try uaccess_try_nospec #define get_user_catch(err) uaccess_catch(err) #define get_user_ex(x, ptr) do { \ @@ -591,7 +591,7 @@ extern void __cmpxchg_wrong_size(void) __typeof__(ptr) __uval = (uval); \ __typeof__(*(ptr)) __old = (old); \ __typeof__(*(ptr)) __new = (new); \ - __uaccess_begin(); \ + __uaccess_begin_nospec(); \ switch (size) { \ case 1: \ { \ diff --git a/arch/x86/include/asm/uaccess_32.h b/arch/x86/include/asm/uaccess_32.h index 72950401b223..ba2dc1930630 100644 --- a/arch/x86/include/asm/uaccess_32.h +++ b/arch/x86/include/asm/uaccess_32.h @@ -29,21 +29,21 @@ raw_copy_from_user(void *to, const void __user *from, unsigned long n) switch (n) { case 1: ret = 0; - __uaccess_begin(); + __uaccess_begin_nospec(); __get_user_asm_nozero(*(u8 *)to, from, ret, "b", "b", "=q", 1); __uaccess_end(); return ret; case 2: ret = 0; - __uaccess_begin(); + __uaccess_begin_nospec(); __get_user_asm_nozero(*(u16 *)to, from, ret, "w", "w", "=r", 2); __uaccess_end(); return ret; case 4: ret = 0; - __uaccess_begin(); + __uaccess_begin_nospec(); __get_user_asm_nozero(*(u32 *)to, from, ret, "l", "k", "=r", 4); __uaccess_end(); diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h index f07ef3c575db..62546b3a398e 100644 --- a/arch/x86/include/asm/uaccess_64.h +++ b/arch/x86/include/asm/uaccess_64.h @@ -55,31 +55,31 @@ raw_copy_from_user(void *dst, const void __user *src, unsigned long size) return copy_user_generic(dst, (__force void *)src, size); switch (size) { case 1: - __uaccess_begin(); + __uaccess_begin_nospec(); __get_user_asm_nozero(*(u8 *)dst, (u8 __user *)src, ret, "b", "b", "=q", 1); __uaccess_end(); return ret; case 2: - __uaccess_begin(); + __uaccess_begin_nospec(); __get_user_asm_nozero(*(u16 *)dst, (u16 __user *)src, ret, "w", "w", "=r", 2); __uaccess_end(); return ret; case 4: - __uaccess_begin(); + __uaccess_begin_nospec(); __get_user_asm_nozero(*(u32 *)dst, (u32 __user *)src, ret, "l", "k", "=r", 4); __uaccess_end(); return ret; case 8: - __uaccess_begin(); + __uaccess_begin_nospec(); __get_user_asm_nozero(*(u64 *)dst, (u64 __user *)src, ret, "q", "", "=r", 8); __uaccess_end(); return ret; case 10: - __uaccess_begin(); + __uaccess_begin_nospec(); __get_user_asm_nozero(*(u64 *)dst, (u64 __user *)src, ret, "q", "", "=r", 10); if (likely(!ret)) @@ -89,7 +89,7 @@ raw_copy_from_user(void *dst, const void __user *src, unsigned long size) __uaccess_end(); return ret; case 16: - __uaccess_begin(); + __uaccess_begin_nospec(); __get_user_asm_nozero(*(u64 *)dst, (u64 __user *)src, ret, "q", "", "=r", 16); if (likely(!ret)) diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c index 1b377f734e64..7add8ba06887 100644 --- a/arch/x86/lib/usercopy_32.c +++ b/arch/x86/lib/usercopy_32.c @@ -331,12 +331,12 @@ do { \ unsigned long __copy_user_ll(void *to, const void *from, unsigned long n) { - stac(); + __uaccess_begin_nospec(); if (movsl_is_ok(to, from, n)) __copy_user(to, from, n); else n = __copy_user_intel(to, from, n); - clac(); + __uaccess_end(); return n; } EXPORT_SYMBOL(__copy_user_ll); @@ -344,7 +344,7 @@ EXPORT_SYMBOL(__copy_user_ll); unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *from, unsigned long n) { - stac(); + __uaccess_begin_nospec(); #ifdef CONFIG_X86_INTEL_USERCOPY if (n > 64 && static_cpu_has(X86_FEATURE_XMM2)) n = __copy_user_intel_nocache(to, from, n); @@ -353,7 +353,7 @@ unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *fr #else __copy_user(to, from, n); #endif - clac(); + __uaccess_end(); return n; } EXPORT_SYMBOL(__copy_from_user_ll_nocache_nozero);
Quoting Linus: I do think that it would be a good idea to very expressly document the fact that it's not that the user access itself is unsafe. I do agree that things like "get_user()" want to be protected, but not because of any direct bugs or problems with get_user() and friends, but simply because get_user() is an excellent source of a pointer that is obviously controlled from a potentially attacking user space. So it's a prime candidate for then finding _subsequent_ accesses that can then be used to perturb the cache. '__uaccess_begin_nospec' covers '__get_user' and 'copy_from_iter' where the limit check is far away from the user pointer de-reference. In those cases an 'lfence' prevents speculation with a potential pointer to privileged memory. Suggested-by: Linus Torvalds <torvalds@linux-foundation.org> Suggested-by: Andi Kleen <ak@linux.intel.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Kees Cook <keescook@chromium.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: x86@kernel.org Signed-off-by: Dan Williams <dan.j.williams@intel.com> --- arch/x86/include/asm/uaccess.h | 6 +++--- arch/x86/include/asm/uaccess_32.h | 6 +++--- arch/x86/include/asm/uaccess_64.h | 12 ++++++------ arch/x86/lib/usercopy_32.c | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-)