Commit a4306434 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull address-limit checking fixes from Ingo Molnar:
 "This fixes a number of bugs in the address-limit (USER_DS) checks that
  got introduced in the merge window, (mostly) affecting the ARM and
  ARM64 platforms"

* 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  arm64/syscalls: Move address limit check in loop
  arm/syscalls: Optimize address limit check
  Revert "arm/syscalls: Check address limit on user-mode return"
  syscalls: Use CHECK_DATA_CORRUPTION for addr_limit_user_check
parents a3028247 a2048e34
...@@ -139,11 +139,10 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, ...@@ -139,11 +139,10 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
#define TIF_NEED_RESCHED 1 /* rescheduling necessary */ #define TIF_NEED_RESCHED 1 /* rescheduling necessary */
#define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */
#define TIF_UPROBE 3 /* breakpointed or singlestepping */ #define TIF_UPROBE 3 /* breakpointed or singlestepping */
#define TIF_FSCHECK 4 /* Check FS is USER_DS on return */ #define TIF_SYSCALL_TRACE 4 /* syscall trace active */
#define TIF_SYSCALL_TRACE 5 /* syscall trace active */ #define TIF_SYSCALL_AUDIT 5 /* syscall auditing active */
#define TIF_SYSCALL_AUDIT 6 /* syscall auditing active */ #define TIF_SYSCALL_TRACEPOINT 6 /* syscall tracepoint instrumentation */
#define TIF_SYSCALL_TRACEPOINT 7 /* syscall tracepoint instrumentation */ #define TIF_SECCOMP 7 /* seccomp syscall filtering active */
#define TIF_SECCOMP 8 /* seccomp syscall filtering active */
#define TIF_NOHZ 12 /* in adaptive nohz mode */ #define TIF_NOHZ 12 /* in adaptive nohz mode */
#define TIF_USING_IWMMXT 17 #define TIF_USING_IWMMXT 17
...@@ -154,7 +153,6 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, ...@@ -154,7 +153,6 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
#define _TIF_UPROBE (1 << TIF_UPROBE) #define _TIF_UPROBE (1 << TIF_UPROBE)
#define _TIF_FSCHECK (1 << TIF_FSCHECK)
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT)
...@@ -169,8 +167,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, ...@@ -169,8 +167,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
* Change these and you break ASM code in entry-common.S * Change these and you break ASM code in entry-common.S
*/ */
#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \ #define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \
_TIF_NOTIFY_RESUME | _TIF_UPROBE | \ _TIF_NOTIFY_RESUME | _TIF_UPROBE)
_TIF_FSCHECK)
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* __ASM_ARM_THREAD_INFO_H */ #endif /* __ASM_ARM_THREAD_INFO_H */
...@@ -70,8 +70,6 @@ static inline void set_fs(mm_segment_t fs) ...@@ -70,8 +70,6 @@ static inline void set_fs(mm_segment_t fs)
{ {
current_thread_info()->addr_limit = fs; current_thread_info()->addr_limit = fs;
modify_domain(DOMAIN_KERNEL, fs ? DOMAIN_CLIENT : DOMAIN_MANAGER); modify_domain(DOMAIN_KERNEL, fs ? DOMAIN_CLIENT : DOMAIN_MANAGER);
/* On user-mode return, check fs is correct */
set_thread_flag(TIF_FSCHECK);
} }
#define segment_eq(a, b) ((a) == (b)) #define segment_eq(a, b) ((a) == (b))
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <asm/unistd.h> #include <asm/unistd.h>
#include <asm/ftrace.h> #include <asm/ftrace.h>
#include <asm/unwind.h> #include <asm/unwind.h>
#include <asm/memory.h>
#ifdef CONFIG_AEABI #ifdef CONFIG_AEABI
#include <asm/unistd-oabi.h> #include <asm/unistd-oabi.h>
#endif #endif
...@@ -48,12 +49,14 @@ ret_fast_syscall: ...@@ -48,12 +49,14 @@ ret_fast_syscall:
UNWIND(.fnstart ) UNWIND(.fnstart )
UNWIND(.cantunwind ) UNWIND(.cantunwind )
disable_irq_notrace @ disable interrupts disable_irq_notrace @ disable interrupts
ldr r2, [tsk, #TI_ADDR_LIMIT]
cmp r2, #TASK_SIZE
blne addr_limit_check_failed
ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing
tst r1, #_TIF_SYSCALL_WORK tst r1, #_TIF_SYSCALL_WORK | _TIF_WORK_MASK
bne fast_work_pending
tst r1, #_TIF_WORK_MASK
bne fast_work_pending bne fast_work_pending
/* perform architecture specific actions before user return */ /* perform architecture specific actions before user return */
arch_ret_to_user r1, lr arch_ret_to_user r1, lr
...@@ -76,16 +79,16 @@ ret_fast_syscall: ...@@ -76,16 +79,16 @@ ret_fast_syscall:
UNWIND(.cantunwind ) UNWIND(.cantunwind )
str r0, [sp, #S_R0 + S_OFF]! @ save returned r0 str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
disable_irq_notrace @ disable interrupts disable_irq_notrace @ disable interrupts
ldr r2, [tsk, #TI_ADDR_LIMIT]
cmp r2, #TASK_SIZE
blne addr_limit_check_failed
ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing
tst r1, #_TIF_SYSCALL_WORK tst r1, #_TIF_SYSCALL_WORK | _TIF_WORK_MASK
bne fast_work_pending
tst r1, #_TIF_WORK_MASK
beq no_work_pending beq no_work_pending
UNWIND(.fnend ) UNWIND(.fnend )
ENDPROC(ret_fast_syscall) ENDPROC(ret_fast_syscall)
/* Slower path - fall through to work_pending */ /* Slower path - fall through to work_pending */
fast_work_pending:
#endif #endif
tst r1, #_TIF_SYSCALL_WORK tst r1, #_TIF_SYSCALL_WORK
...@@ -111,6 +114,9 @@ ENTRY(ret_to_user) ...@@ -111,6 +114,9 @@ ENTRY(ret_to_user)
ret_slow_syscall: ret_slow_syscall:
disable_irq_notrace @ disable interrupts disable_irq_notrace @ disable interrupts
ENTRY(ret_to_user_from_irq) ENTRY(ret_to_user_from_irq)
ldr r2, [tsk, #TI_ADDR_LIMIT]
cmp r2, #TASK_SIZE
blne addr_limit_check_failed
ldr r1, [tsk, #TI_FLAGS] ldr r1, [tsk, #TI_FLAGS]
tst r1, #_TIF_WORK_MASK tst r1, #_TIF_WORK_MASK
bne slow_work_pending bne slow_work_pending
......
...@@ -614,10 +614,6 @@ do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall) ...@@ -614,10 +614,6 @@ do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
* Update the trace code with the current status. * Update the trace code with the current status.
*/ */
trace_hardirqs_off(); trace_hardirqs_off();
/* Check valid user FS if needed */
addr_limit_user_check();
do { do {
if (likely(thread_flags & _TIF_NEED_RESCHED)) { if (likely(thread_flags & _TIF_NEED_RESCHED)) {
schedule(); schedule();
...@@ -678,3 +674,9 @@ struct page *get_signal_page(void) ...@@ -678,3 +674,9 @@ struct page *get_signal_page(void)
return page; return page;
} }
/* Defer to generic check */
asmlinkage void addr_limit_check_failed(void)
{
addr_limit_user_check();
}
...@@ -751,10 +751,10 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, ...@@ -751,10 +751,10 @@ asmlinkage void do_notify_resume(struct pt_regs *regs,
*/ */
trace_hardirqs_off(); trace_hardirqs_off();
do {
/* Check valid user FS if needed */ /* Check valid user FS if needed */
addr_limit_user_check(); addr_limit_user_check();
do {
if (thread_flags & _TIF_NEED_RESCHED) { if (thread_flags & _TIF_NEED_RESCHED) {
schedule(); schedule();
} else { } else {
......
...@@ -221,21 +221,25 @@ static inline int is_syscall_trace_event(struct trace_event_call *tp_event) ...@@ -221,21 +221,25 @@ static inline int is_syscall_trace_event(struct trace_event_call *tp_event)
} \ } \
static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)) static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__))
#ifdef TIF_FSCHECK
/* /*
* Called before coming back to user-mode. Returning to user-mode with an * Called before coming back to user-mode. Returning to user-mode with an
* address limit different than USER_DS can allow to overwrite kernel memory. * address limit different than USER_DS can allow to overwrite kernel memory.
*/ */
static inline void addr_limit_user_check(void) static inline void addr_limit_user_check(void)
{ {
#ifdef TIF_FSCHECK
if (!test_thread_flag(TIF_FSCHECK)) if (!test_thread_flag(TIF_FSCHECK))
return; return;
#endif
BUG_ON(!segment_eq(get_fs(), USER_DS)); if (CHECK_DATA_CORRUPTION(!segment_eq(get_fs(), USER_DS),
"Invalid address limit on user-mode return"))
force_sig(SIGKILL, current);
#ifdef TIF_FSCHECK
clear_thread_flag(TIF_FSCHECK); clear_thread_flag(TIF_FSCHECK);
}
#endif #endif
}
asmlinkage long sys32_quotactl(unsigned int cmd, const char __user *special, asmlinkage long sys32_quotactl(unsigned int cmd, const char __user *special,
qid_t id, void __user *addr); qid_t id, void __user *addr);
......
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