| From 2a418cf3f5f1caf911af288e978d61c9844b0695 Mon Sep 17 00:00:00 2001 |
| From: Andy Lutomirski <luto@kernel.org> |
| Date: Fri, 22 Feb 2019 17:17:04 -0800 |
| Subject: x86/uaccess: Don't leak the AC flag into __put_user() value evaluation |
| |
| From: Andy Lutomirski <luto@kernel.org> |
| |
| commit 2a418cf3f5f1caf911af288e978d61c9844b0695 upstream. |
| |
| When calling __put_user(foo(), ptr), the __put_user() macro would call |
| foo() in between __uaccess_begin() and __uaccess_end(). If that code |
| were buggy, then those bugs would be run without SMAP protection. |
| |
| Fortunately, there seem to be few instances of the problem in the |
| kernel. Nevertheless, __put_user() should be fixed to avoid doing this. |
| Therefore, evaluate __put_user()'s argument before setting AC. |
| |
| This issue was noticed when an objtool hack by Peter Zijlstra complained |
| about genregs_get() and I compared the assembly output to the C source. |
| |
| [ bp: Massage commit message and fixed up whitespace. ] |
| |
| Fixes: 11f1a4b9755f ("x86: reorganize SMAP handling in user space accesses") |
| Signed-off-by: Andy Lutomirski <luto@kernel.org> |
| Signed-off-by: Borislav Petkov <bp@suse.de> |
| Acked-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Cc: Peter Zijlstra <peterz@infradead.org> |
| Cc: Brian Gerst <brgerst@gmail.com> |
| Cc: Josh Poimboeuf <jpoimboe@redhat.com> |
| Cc: Denys Vlasenko <dvlasenk@redhat.com> |
| Cc: stable@vger.kernel.org |
| Link: http://lkml.kernel.org/r/20190225125231.845656645@infradead.org |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/x86/include/asm/uaccess.h | 7 ++++--- |
| 1 file changed, 4 insertions(+), 3 deletions(-) |
| |
| --- a/arch/x86/include/asm/uaccess.h |
| +++ b/arch/x86/include/asm/uaccess.h |
| @@ -293,8 +293,7 @@ do { \ |
| __put_user_asm(x, ptr, retval, "l", "k", "ir", errret); \ |
| break; \ |
| case 8: \ |
| - __put_user_asm_u64((__typeof__(*ptr))(x), ptr, retval, \ |
| - errret); \ |
| + __put_user_asm_u64(x, ptr, retval, errret); \ |
| break; \ |
| default: \ |
| __put_user_bad(); \ |
| @@ -440,8 +439,10 @@ do { \ |
| #define __put_user_nocheck(x, ptr, size) \ |
| ({ \ |
| int __pu_err; \ |
| + __typeof__(*(ptr)) __pu_val; \ |
| + __pu_val = x; \ |
| __uaccess_begin(); \ |
| - __put_user_size((x), (ptr), (size), __pu_err, -EFAULT); \ |
| + __put_user_size(__pu_val, (ptr), (size), __pu_err, -EFAULT);\ |
| __uaccess_end(); \ |
| __builtin_expect(__pu_err, 0); \ |
| }) |