Commit a2150327 authored by Thomas Gleixner's avatar Thomas Gleixner

Merge branch 'next.uaccess-2' of...

Merge branch 'next.uaccess-2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs into x86/cleanups

Pull uaccess cleanups from Al Viro:

  Consolidate the user access areas and get rid of uaccess_try(), user_ex()
  and other warts.
parents 5bacdc09 cf122cfb
...@@ -337,10 +337,4 @@ pointer which points to one of: ...@@ -337,10 +337,4 @@ pointer which points to one of:
entry->insn. It is used to distinguish page faults from machine entry->insn. It is used to distinguish page faults from machine
check. check.
3) ``int ex_handler_ext(const struct exception_table_entry *fixup)``
This case is used for uaccess_err ... we need to set a flag
in the task structure. Before the handler functions existed this
case was handled by adding a large offset to the fixup to tag
it as special.
More functions can easily be added. More functions can easily be added.
...@@ -2490,7 +2490,7 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry_ctx *ent ...@@ -2490,7 +2490,7 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry_ctx *ent
/* 32-bit process in 64-bit kernel. */ /* 32-bit process in 64-bit kernel. */
unsigned long ss_base, cs_base; unsigned long ss_base, cs_base;
struct stack_frame_ia32 frame; struct stack_frame_ia32 frame;
const void __user *fp; const struct stack_frame_ia32 __user *fp;
if (!test_thread_flag(TIF_IA32)) if (!test_thread_flag(TIF_IA32))
return 0; return 0;
...@@ -2501,18 +2501,12 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry_ctx *ent ...@@ -2501,18 +2501,12 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry_ctx *ent
fp = compat_ptr(ss_base + regs->bp); fp = compat_ptr(ss_base + regs->bp);
pagefault_disable(); pagefault_disable();
while (entry->nr < entry->max_stack) { while (entry->nr < entry->max_stack) {
unsigned long bytes;
frame.next_frame = 0;
frame.return_address = 0;
if (!valid_user_frame(fp, sizeof(frame))) if (!valid_user_frame(fp, sizeof(frame)))
break; break;
bytes = __copy_from_user_nmi(&frame.next_frame, fp, 4); if (__get_user(frame.next_frame, &fp->next_frame))
if (bytes != 0)
break; break;
bytes = __copy_from_user_nmi(&frame.return_address, fp+4, 4); if (__get_user(frame.return_address, &fp->return_address))
if (bytes != 0)
break; break;
perf_callchain_store(entry, cs_base + frame.return_address); perf_callchain_store(entry, cs_base + frame.return_address);
...@@ -2533,7 +2527,7 @@ void ...@@ -2533,7 +2527,7 @@ void
perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs) perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs)
{ {
struct stack_frame frame; struct stack_frame frame;
const unsigned long __user *fp; const struct stack_frame __user *fp;
if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
/* TODO: We don't support guest os callchain now */ /* TODO: We don't support guest os callchain now */
...@@ -2546,7 +2540,7 @@ perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs ...@@ -2546,7 +2540,7 @@ perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs
if (regs->flags & (X86_VM_MASK | PERF_EFLAGS_VM)) if (regs->flags & (X86_VM_MASK | PERF_EFLAGS_VM))
return; return;
fp = (unsigned long __user *)regs->bp; fp = (void __user *)regs->bp;
perf_callchain_store(entry, regs->ip); perf_callchain_store(entry, regs->ip);
...@@ -2558,19 +2552,12 @@ perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs ...@@ -2558,19 +2552,12 @@ perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs
pagefault_disable(); pagefault_disable();
while (entry->nr < entry->max_stack) { while (entry->nr < entry->max_stack) {
unsigned long bytes;
frame.next_frame = NULL;
frame.return_address = 0;
if (!valid_user_frame(fp, sizeof(frame))) if (!valid_user_frame(fp, sizeof(frame)))
break; break;
bytes = __copy_from_user_nmi(&frame.next_frame, fp, sizeof(*fp)); if (__get_user(frame.next_frame, &fp->next_frame))
if (bytes != 0)
break; break;
bytes = __copy_from_user_nmi(&frame.return_address, fp + 1, sizeof(*fp)); if (__get_user(frame.return_address, &fp->return_address))
if (bytes != 0)
break; break;
perf_callchain_store(entry, frame.return_address); perf_callchain_store(entry, frame.return_address);
......
This diff is collapsed.
...@@ -138,9 +138,6 @@ ...@@ -138,9 +138,6 @@
# define _ASM_EXTABLE_FAULT(from, to) \ # define _ASM_EXTABLE_FAULT(from, to) \
_ASM_EXTABLE_HANDLE(from, to, ex_handler_fault) _ASM_EXTABLE_HANDLE(from, to, ex_handler_fault)
# define _ASM_EXTABLE_EX(from, to) \
_ASM_EXTABLE_HANDLE(from, to, ex_handler_ext)
# define _ASM_NOKPROBE(entry) \ # define _ASM_NOKPROBE(entry) \
.pushsection "_kprobe_blacklist","aw" ; \ .pushsection "_kprobe_blacklist","aw" ; \
_ASM_ALIGN ; \ _ASM_ALIGN ; \
...@@ -166,9 +163,6 @@ ...@@ -166,9 +163,6 @@
# define _ASM_EXTABLE_FAULT(from, to) \ # define _ASM_EXTABLE_FAULT(from, to) \
_ASM_EXTABLE_HANDLE(from, to, ex_handler_fault) _ASM_EXTABLE_HANDLE(from, to, ex_handler_fault)
# define _ASM_EXTABLE_EX(from, to) \
_ASM_EXTABLE_HANDLE(from, to, ex_handler_ext)
/* For C file, we already have NOKPROBE_SYMBOL macro */ /* For C file, we already have NOKPROBE_SYMBOL macro */
#endif #endif
......
...@@ -541,7 +541,6 @@ struct thread_struct { ...@@ -541,7 +541,6 @@ struct thread_struct {
mm_segment_t addr_limit; mm_segment_t addr_limit;
unsigned int sig_on_uaccess_err:1; unsigned int sig_on_uaccess_err:1;
unsigned int uaccess_err:1; /* uaccess failed */
/* Floating point and extended processor state */ /* Floating point and extended processor state */
struct fpu fpu; struct fpu fpu;
......
...@@ -33,11 +33,7 @@ struct sigframe_ia32 { ...@@ -33,11 +33,7 @@ struct sigframe_ia32 {
* legacy application accessing/modifying it. * legacy application accessing/modifying it.
*/ */
struct _fpstate_32 fpstate_unused; struct _fpstate_32 fpstate_unused;
#ifdef CONFIG_IA32_EMULATION unsigned int extramask[1];
unsigned int extramask[_COMPAT_NSIG_WORDS-1];
#else /* !CONFIG_IA32_EMULATION */
unsigned long extramask[_NSIG_WORDS-1];
#endif /* CONFIG_IA32_EMULATION */
char retcode[8]; char retcode[8];
/* fp state follows here */ /* fp state follows here */
}; };
......
...@@ -14,9 +14,6 @@ ...@@ -14,9 +14,6 @@
X86_EFLAGS_CF | X86_EFLAGS_RF) X86_EFLAGS_CF | X86_EFLAGS_RF)
void signal_fault(struct pt_regs *regs, void __user *frame, char *where); void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
int setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
struct pt_regs *regs, unsigned long mask);
#ifdef CONFIG_X86_X32_ABI #ifdef CONFIG_X86_X32_ABI
asmlinkage long sys32_x32_rt_sigreturn(void); asmlinkage long sys32_x32_rt_sigreturn(void);
......
...@@ -193,23 +193,12 @@ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL)) ...@@ -193,23 +193,12 @@ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
: : "A" (x), "r" (addr) \ : : "A" (x), "r" (addr) \
: : label) : : label)
#define __put_user_asm_ex_u64(x, addr) \
asm volatile("\n" \
"1: movl %%eax,0(%1)\n" \
"2: movl %%edx,4(%1)\n" \
"3:" \
_ASM_EXTABLE_EX(1b, 2b) \
_ASM_EXTABLE_EX(2b, 3b) \
: : "A" (x), "r" (addr))
#define __put_user_x8(x, ptr, __ret_pu) \ #define __put_user_x8(x, ptr, __ret_pu) \
asm volatile("call __put_user_8" : "=a" (__ret_pu) \ asm volatile("call __put_user_8" : "=a" (__ret_pu) \
: "A" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx") : "A" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx")
#else #else
#define __put_user_goto_u64(x, ptr, label) \ #define __put_user_goto_u64(x, ptr, label) \
__put_user_goto(x, ptr, "q", "", "er", label) __put_user_goto(x, ptr, "q", "", "er", label)
#define __put_user_asm_ex_u64(x, addr) \
__put_user_asm_ex(x, addr, "q", "", "er")
#define __put_user_x8(x, ptr, __ret_pu) __put_user_x(8, x, ptr, __ret_pu) #define __put_user_x8(x, ptr, __ret_pu) __put_user_x(8, x, ptr, __ret_pu)
#endif #endif
...@@ -289,31 +278,6 @@ do { \ ...@@ -289,31 +278,6 @@ do { \
} \ } \
} while (0) } while (0)
/*
* This doesn't do __uaccess_begin/end - the exception handling
* around it must do that.
*/
#define __put_user_size_ex(x, ptr, size) \
do { \
__chk_user_ptr(ptr); \
switch (size) { \
case 1: \
__put_user_asm_ex(x, ptr, "b", "b", "iq"); \
break; \
case 2: \
__put_user_asm_ex(x, ptr, "w", "w", "ir"); \
break; \
case 4: \
__put_user_asm_ex(x, ptr, "l", "k", "ir"); \
break; \
case 8: \
__put_user_asm_ex_u64((__typeof__(*ptr))(x), ptr); \
break; \
default: \
__put_user_bad(); \
} \
} while (0)
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
#define __get_user_asm_u64(x, ptr, retval, errret) \ #define __get_user_asm_u64(x, ptr, retval, errret) \
({ \ ({ \
...@@ -335,12 +299,9 @@ do { \ ...@@ -335,12 +299,9 @@ do { \
"i" (errret), "0" (retval)); \ "i" (errret), "0" (retval)); \
}) })
#define __get_user_asm_ex_u64(x, ptr) (x) = __get_user_bad()
#else #else
#define __get_user_asm_u64(x, ptr, retval, errret) \ #define __get_user_asm_u64(x, ptr, retval, errret) \
__get_user_asm(x, ptr, retval, "q", "", "=r", errret) __get_user_asm(x, ptr, retval, "q", "", "=r", errret)
#define __get_user_asm_ex_u64(x, ptr) \
__get_user_asm_ex(x, ptr, "q", "", "=r")
#endif #endif
#define __get_user_size(x, ptr, size, retval, errret) \ #define __get_user_size(x, ptr, size, retval, errret) \
...@@ -378,53 +339,6 @@ do { \ ...@@ -378,53 +339,6 @@ do { \
: "=r" (err), ltype(x) \ : "=r" (err), ltype(x) \
: "m" (__m(addr)), "i" (errret), "0" (err)) : "m" (__m(addr)), "i" (errret), "0" (err))
#define __get_user_asm_nozero(x, addr, err, itype, rtype, ltype, errret) \
asm volatile("\n" \
"1: mov"itype" %2,%"rtype"1\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: mov %3,%0\n" \
" jmp 2b\n" \
".previous\n" \
_ASM_EXTABLE_UA(1b, 3b) \
: "=r" (err), ltype(x) \
: "m" (__m(addr)), "i" (errret), "0" (err))
/*
* This doesn't do __uaccess_begin/end - the exception handling
* around it must do that.
*/
#define __get_user_size_ex(x, ptr, size) \
do { \
__chk_user_ptr(ptr); \
switch (size) { \
case 1: \
__get_user_asm_ex(x, ptr, "b", "b", "=q"); \
break; \
case 2: \
__get_user_asm_ex(x, ptr, "w", "w", "=r"); \
break; \
case 4: \
__get_user_asm_ex(x, ptr, "l", "k", "=r"); \
break; \
case 8: \
__get_user_asm_ex_u64(x, ptr); \
break; \
default: \
(x) = __get_user_bad(); \
} \
} while (0)
#define __get_user_asm_ex(x, addr, itype, rtype, ltype) \
asm volatile("1: mov"itype" %1,%"rtype"0\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3:xor"itype" %"rtype"0,%"rtype"0\n" \
" jmp 2b\n" \
".previous\n" \
_ASM_EXTABLE_EX(1b, 3b) \
: ltype(x) : "m" (__m(addr)))
#define __put_user_nocheck(x, ptr, size) \ #define __put_user_nocheck(x, ptr, size) \
({ \ ({ \
__label__ __pu_label; \ __label__ __pu_label; \
...@@ -480,29 +394,6 @@ struct __large_struct { unsigned long buf[100]; }; ...@@ -480,29 +394,6 @@ struct __large_struct { unsigned long buf[100]; };
retval = __put_user_failed(x, addr, itype, rtype, ltype, errret); \ retval = __put_user_failed(x, addr, itype, rtype, ltype, errret); \
} while (0) } while (0)
#define __put_user_asm_ex(x, addr, itype, rtype, ltype) \
asm volatile("1: mov"itype" %"rtype"0,%1\n" \
"2:\n" \
_ASM_EXTABLE_EX(1b, 2b) \
: : ltype(x), "m" (__m(addr)))
/*
* uaccess_try and catch
*/
#define uaccess_try do { \
current->thread.uaccess_err = 0; \
__uaccess_begin(); \
barrier();
#define uaccess_try_nospec do { \
current->thread.uaccess_err = 0; \
__uaccess_begin_nospec(); \
#define uaccess_catch(err) \
__uaccess_end(); \
(err) |= (current->thread.uaccess_err ? -EFAULT : 0); \
} while (0)
/** /**
* __get_user - Get a simple variable from user space, with less checking. * __get_user - Get a simple variable from user space, with less checking.
* @x: Variable to store result. * @x: Variable to store result.
...@@ -552,28 +443,6 @@ struct __large_struct { unsigned long buf[100]; }; ...@@ -552,28 +443,6 @@ struct __large_struct { unsigned long buf[100]; };
#define __put_user(x, ptr) \ #define __put_user(x, ptr) \
__put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr))) __put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
/*
* {get|put}_user_try and catch
*
* get_user_try {
* get_user_ex(...);
* } get_user_catch(err)
*/
#define get_user_try uaccess_try_nospec
#define get_user_catch(err) uaccess_catch(err)
#define get_user_ex(x, ptr) do { \
unsigned long __gue_val; \
__get_user_size_ex((__gue_val), (ptr), (sizeof(*(ptr)))); \
(x) = (__force __typeof__(*(ptr)))__gue_val; \
} while (0)
#define put_user_try uaccess_try
#define put_user_catch(err) uaccess_catch(err)
#define put_user_ex(x, ptr) \
__put_user_size_ex((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
extern unsigned long extern unsigned long
copy_from_user_nmi(void *to, const void __user *from, unsigned long n); copy_from_user_nmi(void *to, const void __user *from, unsigned long n);
extern __must_check long extern __must_check long
...@@ -694,15 +563,6 @@ extern struct movsl_mask { ...@@ -694,15 +563,6 @@ extern struct movsl_mask {
# include <asm/uaccess_64.h> # include <asm/uaccess_64.h>
#endif #endif
/*
* We rely on the nested NMI work to allow atomic faults from the NMI path; the
* nested NMI paths are careful to preserve CR2.
*
* Caller must use pagefault_enable/disable, or run in interrupt context,
* and also do a uaccess_ok() check
*/
#define __copy_from_user_nmi __copy_from_user_inatomic
/* /*
* The "unsafe" user accesses aren't really "unsafe", but the naming * The "unsafe" user accesses aren't really "unsafe", but the naming
* is a big fat warning: you have to not only do the access_ok() * is a big fat warning: you have to not only do the access_ok()
......
...@@ -23,33 +23,6 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n) ...@@ -23,33 +23,6 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n)
static __always_inline unsigned long static __always_inline unsigned long
raw_copy_from_user(void *to, const void __user *from, unsigned long n) raw_copy_from_user(void *to, const void __user *from, unsigned long n)
{ {
if (__builtin_constant_p(n)) {
unsigned long ret;
switch (n) {
case 1:
ret = 0;
__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_nospec();
__get_user_asm_nozero(*(u16 *)to, from, ret,
"w", "w", "=r", 2);
__uaccess_end();
return ret;
case 4:
ret = 0;
__uaccess_begin_nospec();
__get_user_asm_nozero(*(u32 *)to, from, ret,
"l", "k", "=r", 4);
__uaccess_end();
return ret;
}
}
return __copy_user_ll(to, (__force const void *)from, n); return __copy_user_ll(to, (__force const void *)from, n);
} }
......
...@@ -65,117 +65,13 @@ copy_to_user_mcsafe(void *to, const void *from, unsigned len) ...@@ -65,117 +65,13 @@ copy_to_user_mcsafe(void *to, const void *from, unsigned len)
static __always_inline __must_check unsigned long static __always_inline __must_check unsigned long
raw_copy_from_user(void *dst, const void __user *src, unsigned long size) raw_copy_from_user(void *dst, const void __user *src, unsigned long size)
{ {
int ret = 0; return copy_user_generic(dst, (__force void *)src, size);
if (!__builtin_constant_p(size))
return copy_user_generic(dst, (__force void *)src, size);
switch (size) {
case 1:
__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_nospec();
__get_user_asm_nozero(*(u16 *)dst, (u16 __user *)src,
ret, "w", "w", "=r", 2);
__uaccess_end();
return ret;
case 4:
__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_nospec();
__get_user_asm_nozero(*(u64 *)dst, (u64 __user *)src,
ret, "q", "", "=r", 8);
__uaccess_end();
return ret;
case 10:
__uaccess_begin_nospec();
__get_user_asm_nozero(*(u64 *)dst, (u64 __user *)src,
ret, "q", "", "=r", 10);
if (likely(!ret))
__get_user_asm_nozero(*(u16 *)(8 + (char *)dst),
(u16 __user *)(8 + (char __user *)src),
ret, "w", "w", "=r", 2);
__uaccess_end();
return ret;
case 16:
__uaccess_begin_nospec();
__get_user_asm_nozero(*(u64 *)dst, (u64 __user *)src,
ret, "q", "", "=r", 16);
if (likely(!ret))
__get_user_asm_nozero(*(u64 *)(8 + (char *)dst),
(u64 __user *)(8 + (char __user *)src),
ret, "q", "", "=r", 8);
__uaccess_end();
return ret;
default:
return copy_user_generic(dst, (__force void *)src, size);
}
} }
static __always_inline __must_check unsigned long static __always_inline __must_check unsigned long
raw_copy_to_user(void __user *dst, const void *src, unsigned long size) raw_copy_to_user(void __user *dst, const void *src, unsigned long size)
{ {
int ret = 0; return copy_user_generic((__force void *)dst, src, size);
if (!__builtin_constant_p(size))
return copy_user_generic((__force void *)dst, src, size);
switch (size) {
case 1:
__uaccess_begin();
__put_user_asm(*(u8 *)src, (u8 __user *)dst,
ret, "b", "b", "iq", 1);
__uaccess_end();
return ret;
case 2:
__uaccess_begin();
__put_user_asm(*(u16 *)src, (u16 __user *)dst,
ret, "w", "w", "ir", 2);
__uaccess_end();
return ret;
case 4:
__uaccess_begin();
__put_user_asm(*(u32 *)src, (u32 __user *)dst,
ret, "l", "k", "ir", 4);
__uaccess_end();
return ret;
case 8:
__uaccess_begin();
__put_user_asm(*(u64 *)src, (u64 __user *)dst,
ret, "q", "", "er", 8);
__uaccess_end();
return ret;
case 10:
__uaccess_begin();
__put_user_asm(*(u64 *)src, (u64 __user *)dst,
ret, "q", "", "er", 10);
if (likely(!ret)) {
asm("":::"memory");
__put_user_asm(4[(u16 *)src], 4 + (u16 __user *)dst,
ret, "w", "w", "ir", 2);
}
__uaccess_end();
return ret;
case 16:
__uaccess_begin();
__put_user_asm(*(u64 *)src, (u64 __user *)dst,
ret, "q", "", "er", 16);
if (likely(!ret)) {
asm("":::"memory");
__put_user_asm(1[(u64 *)src], 1 + (u64 __user *)dst,
ret, "q", "", "er", 8);
}
__uaccess_end();
return ret;
default:
return copy_user_generic((__force void *)dst, src, size);
}
} }
static __always_inline __must_check static __always_inline __must_check
......
This diff is collapsed.
...@@ -96,7 +96,8 @@ struct stack_frame_user { ...@@ -96,7 +96,8 @@ struct stack_frame_user {
}; };
static int static int
copy_stack_frame(const void __user *fp, struct stack_frame_user *frame) copy_stack_frame(const struct stack_frame_user __user *fp,
struct stack_frame_user *frame)
{ {
int ret; int ret;
...@@ -105,7 +106,8 @@ copy_stack_frame(const void __user *fp, struct stack_frame_user *frame) ...@@ -105,7 +106,8 @@ copy_stack_frame(const void __user *fp, struct stack_frame_user *frame)
ret = 1; ret = 1;
pagefault_disable(); pagefault_disable();
if (__copy_from_user_inatomic(frame, fp, sizeof(*frame))) if (__get_user(frame->next_fp, &fp->next_fp) ||
__get_user(frame->ret_addr, &fp->ret_addr))
ret = 0; ret = 0;
pagefault_enable(); pagefault_enable();
......
...@@ -98,7 +98,6 @@ void save_v86_state(struct kernel_vm86_regs *regs, int retval) ...@@ -98,7 +98,6 @@ void save_v86_state(struct kernel_vm86_regs *regs, int retval)
struct task_struct *tsk = current; struct task_struct *tsk = current;
struct vm86plus_struct __user *user; struct vm86plus_struct __user *user;
struct vm86 *vm86 = current->thread.vm86; struct vm86 *vm86 = current->thread.vm86;
long err = 0;
/* /*
* This gets called from entry.S with interrupts disabled, but * This gets called from entry.S with interrupts disabled, but
...@@ -114,37 +113,30 @@ void save_v86_state(struct kernel_vm86_regs *regs, int retval) ...@@ -114,37 +113,30 @@ void save_v86_state(struct kernel_vm86_regs *regs, int retval)
set_flags(regs->pt.flags, VEFLAGS, X86_EFLAGS_VIF | vm86->veflags_mask); set_flags(regs->pt.flags, VEFLAGS, X86_EFLAGS_VIF | vm86->veflags_mask);
user = vm86->user_vm86; user = vm86->user_vm86;
if (!access_ok(user, vm86->vm86plus.is_vm86pus ? if (!user_access_begin(user, vm86->vm86plus.is_vm86pus ?
sizeof(struct vm86plus_struct) : sizeof(struct vm86plus_struct) :
sizeof(struct vm86_struct))) { sizeof(struct vm86_struct)))
pr_alert("could not access userspace vm86 info\n"); goto Efault;
do_exit(SIGSEGV);
} unsafe_put_user(regs->pt.bx, &user->regs.ebx, Efault_end);
unsafe_put_user(regs->pt.cx, &user->regs.ecx, Efault_end);
put_user_try { unsafe_put_user(regs->pt.dx, &user->regs.edx, Efault_end);
put_user_ex(regs->pt.bx, &user->regs.ebx); unsafe_put_user(regs->pt.si, &user->regs.esi, Efault_end);
put_user_ex(regs->pt.cx, &user->regs.ecx); unsafe_put_user(regs->pt.di, &user->regs.edi, Efault_end);
put_user_ex(regs->pt.dx, &user->regs.edx); unsafe_put_user(regs->pt.bp, &user->regs.ebp, Efault_end);
put_user_ex(regs->pt.si, &user->regs.esi); unsafe_put_user(regs->pt.ax, &user->regs.eax, Efault_end);
put_user_ex(regs->pt.di, &user->regs.edi); unsafe_put_user(regs->pt.ip, &user->regs.eip, Efault_end);
put_user_ex(regs->pt.bp, &user->regs.ebp); unsafe_put_user(regs->pt.cs, &user->regs.cs, Efault_end);
put_user_ex(regs->pt.ax, &user->regs.eax); unsafe_put_user(regs->pt.flags, &user->regs.eflags, Efault_end);
put_user_ex(regs->pt.ip, &user->regs.eip); unsafe_put_user(regs->pt.sp, &user->regs.esp, Efault_end);
put_user_ex(regs->pt.cs, &user->regs.cs); unsafe_put_user(regs->pt.ss, &user->regs.ss, Efault_end);
put_user_ex(regs->pt.flags, &user->regs.eflags); unsafe_put_user(regs->es, &user->regs.es, Efault_end);
put_user_ex(regs->pt.sp, &user->regs.esp); unsafe_put_user(regs->ds, &user->regs.ds, Efault_end);
put_user_ex(regs->pt.ss, &user->regs.ss); unsafe_put_user(regs->fs, &user->regs.fs, Efault_end);
put_user_ex(regs->es, &user->regs.es); unsafe_put_user(regs->gs, &user->regs.gs, Efault_end);
put_user_ex(regs->ds, &user->regs.ds); unsafe_put_user(vm86->screen_bitmap, &user->screen_bitmap, Efault_end);
put_user_ex(regs->fs, &user->regs.fs);
put_user_ex(regs->gs, &user->regs.gs); user_access_end();
put_user_ex(vm86->screen_bitmap, &user->screen_bitmap);
} put_user_catch(err);
if (err) {
pr_alert("could not access userspace vm86 info\n");
do_exit(SIGSEGV);
}
preempt_disable(); preempt_disable();
tsk->thread.sp0 = vm86->saved_sp0; tsk->thread.sp0 = vm86->saved_sp0;
...@@ -159,6 +151,13 @@ void save_v86_state(struct kernel_vm86_regs *regs, int retval) ...@@ -159,6 +151,13 @@ void save_v86_state(struct kernel_vm86_regs *regs, int retval)
lazy_load_gs(vm86->regs32.gs); lazy_load_gs(vm86->regs32.gs);
regs->pt.ax = retval; regs->pt.ax = retval;
return;
Efault_end:
user_access_end();
Efault:
pr_alert("could not access userspace vm86 info\n");
do_exit(SIGSEGV);
} }
static void mark_screen_rdonly(struct mm_struct *mm) static void mark_screen_rdonly(struct mm_struct *mm)
...@@ -243,6 +242,7 @@ static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus) ...@@ -243,6 +242,7 @@ static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus)
struct kernel_vm86_regs vm86regs; struct kernel_vm86_regs vm86regs;
struct pt_regs *regs = current_pt_regs(); struct pt_regs *regs = current_pt_regs();
unsigned long err = 0; unsigned long err = 0;
struct vm86_struct v;
err = security_mmap_addr(0); err = security_mmap_addr(0);
if (err) { if (err) {
...@@ -278,39 +278,32 @@ static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus) ...@@ -278,39 +278,32 @@ static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus)
if (vm86->saved_sp0) if (vm86->saved_sp0)
return -EPERM; return -EPERM;
if (!access_ok(user_vm86, plus ? if (copy_from_user(&v, user_vm86,
sizeof(struct vm86_struct) : offsetof(struct vm86_struct, int_revectored)))
sizeof(struct vm86plus_struct)))
return -EFAULT; return -EFAULT;
memset(&vm86regs, 0, sizeof(vm86regs)); memset(&vm86regs, 0, sizeof(vm86regs));
get_user_try {
unsigned short seg; vm86regs.pt.bx = v.regs.ebx;
get_user_ex(vm86regs.pt.bx, &user_vm86->regs.ebx); vm86regs.pt.cx = v.regs.ecx;
get_user_ex(vm86regs.pt.cx, &user_vm86->regs.ecx); vm86regs.pt.dx = v.regs.edx;
get_user_ex(vm86regs.pt.dx, &user_vm86->regs.edx); vm86regs.pt.si = v.regs.esi;
get_user_ex(vm86regs.pt.si, &user_vm86->regs.esi); vm86regs.pt.di = v.regs.edi;
get_user_ex(vm86regs.pt.di, &user_vm86->regs.edi); vm86regs.pt.bp = v.regs.ebp;
get_user_ex(vm86regs.pt.bp, &user_vm86->regs.ebp); vm86regs.pt.ax = v.regs.eax;
get_user_ex(vm86regs.pt.ax, &user_vm86->regs.eax); vm86regs.pt.ip = v.regs.eip;
get_user_ex(vm86regs.pt.ip, &user_vm86->regs.eip); vm86regs.pt.cs = v.regs.cs;
get_user_ex(seg, &user_vm86->regs.cs); vm86regs.pt.flags = v.regs.eflags;
vm86regs.pt.cs = seg; vm86regs.pt.sp = v.regs.esp;
get_user_ex(vm86regs.pt.flags, &user_vm86->regs.eflags); vm86regs.pt.ss = v.regs.ss;
get_user_ex(vm86regs.pt.sp, &user_vm86->regs.esp); vm86regs.es = v.regs.es;
get_user_ex(seg, &user_vm86->regs.ss); vm86regs.ds = v.regs.ds;
vm86regs.pt.ss = seg; vm86regs.fs = v.regs.fs;
get_user_ex(vm86regs.es, &user_vm86->regs.es); vm86regs.gs = v.regs.gs;
get_user_ex(vm86regs.ds, &user_vm86->regs.ds);
get_user_ex(vm86regs.fs, &user_vm86->regs.fs); vm86->flags = v.flags;
get_user_ex(vm86regs.gs, &user_vm86->regs.gs); vm86->screen_bitmap = v.screen_bitmap;
vm86->cpu_type = v.cpu_type;
get_user_ex(vm86->flags, &user_vm86->flags);
get_user_ex(vm86->screen_bitmap, &user_vm86->screen_bitmap);
get_user_ex(vm86->cpu_type, &user_vm86->cpu_type);
} get_user_catch(err);
if (err)
return err;
if (copy_from_user(&vm86->int_revectored, if (copy_from_user(&vm86->int_revectored,
&user_vm86->int_revectored, &user_vm86->int_revectored,
......
...@@ -400,7 +400,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, ...@@ -400,7 +400,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
goto error; goto error;
ptep_user = (pt_element_t __user *)((void *)host_addr + offset); ptep_user = (pt_element_t __user *)((void *)host_addr + offset);
if (unlikely(__copy_from_user(&pte, ptep_user, sizeof(pte)))) if (unlikely(__get_user(pte, ptep_user)))
goto error; goto error;
walker->ptep_user[walker->level - 1] = ptep_user; walker->ptep_user[walker->level - 1] = ptep_user;
......
...@@ -80,18 +80,6 @@ __visible bool ex_handler_uaccess(const struct exception_table_entry *fixup, ...@@ -80,18 +80,6 @@ __visible bool ex_handler_uaccess(const struct exception_table_entry *fixup,
} }
EXPORT_SYMBOL(ex_handler_uaccess); EXPORT_SYMBOL(ex_handler_uaccess);
__visible bool ex_handler_ext(const struct exception_table_entry *fixup,
struct pt_regs *regs, int trapnr,
unsigned long error_code,
unsigned long fault_addr)
{
/* Special hack for uaccess_err */
current->thread.uaccess_err = 1;
regs->ip = ex_fixup_addr(fixup);
return true;
}
EXPORT_SYMBOL(ex_handler_ext);
__visible bool ex_handler_rdmsr_unsafe(const struct exception_table_entry *fixup, __visible bool ex_handler_rdmsr_unsafe(const struct exception_table_entry *fixup,
struct pt_regs *regs, int trapnr, struct pt_regs *regs, int trapnr,
unsigned long error_code, unsigned long error_code,
......
...@@ -483,12 +483,13 @@ extern void __user *compat_alloc_user_space(unsigned long len); ...@@ -483,12 +483,13 @@ extern void __user *compat_alloc_user_space(unsigned long len);
int compat_restore_altstack(const compat_stack_t __user *uss); int compat_restore_altstack(const compat_stack_t __user *uss);
int __compat_save_altstack(compat_stack_t __user *, unsigned long); int __compat_save_altstack(compat_stack_t __user *, unsigned long);
#define compat_save_altstack_ex(uss, sp) do { \ #define unsafe_compat_save_altstack(uss, sp, label) do { \
compat_stack_t __user *__uss = uss; \ compat_stack_t __user *__uss = uss; \
struct task_struct *t = current; \ struct task_struct *t = current; \
put_user_ex(ptr_to_compat((void __user *)t->sas_ss_sp), &__uss->ss_sp); \ unsafe_put_user(ptr_to_compat((void __user *)t->sas_ss_sp), \
put_user_ex(t->sas_ss_flags, &__uss->ss_flags); \ &__uss->ss_sp, label); \
put_user_ex(t->sas_ss_size, &__uss->ss_size); \ unsafe_put_user(t->sas_ss_flags, &__uss->ss_flags, label); \
unsafe_put_user(t->sas_ss_size, &__uss->ss_size, label); \
if (t->sas_ss_flags & SS_AUTODISARM) \ if (t->sas_ss_flags & SS_AUTODISARM) \
sas_ss_reset(t); \ sas_ss_reset(t); \
} while (0); } while (0);
......
...@@ -444,12 +444,12 @@ void signals_init(void); ...@@ -444,12 +444,12 @@ void signals_init(void);
int restore_altstack(const stack_t __user *); int restore_altstack(const stack_t __user *);
int __save_altstack(stack_t __user *, unsigned long); int __save_altstack(stack_t __user *, unsigned long);
#define save_altstack_ex(uss, sp) do { \ #define unsafe_save_altstack(uss, sp, label) do { \
stack_t __user *__uss = uss; \ stack_t __user *__uss = uss; \
struct task_struct *t = current; \ struct task_struct *t = current; \
put_user_ex((void __user *)t->sas_ss_sp, &__uss->ss_sp); \ unsafe_put_user((void __user *)t->sas_ss_sp, &__uss->ss_sp, label); \
put_user_ex(t->sas_ss_flags, &__uss->ss_flags); \ unsafe_put_user(t->sas_ss_flags, &__uss->ss_flags, label); \
put_user_ex(t->sas_ss_size, &__uss->ss_size); \ unsafe_put_user(t->sas_ss_size, &__uss->ss_size, label); \
if (t->sas_ss_flags & SS_AUTODISARM) \ if (t->sas_ss_flags & SS_AUTODISARM) \
sas_ss_reset(t); \ sas_ss_reset(t); \
} while (0); } while (0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment