ARM: 8148/1: flush TLS and thumbee register state during exec
The TPIDRURO and TPIDRURW registers need to be flushed during exec; otherwise TLS information is potentially leaked. TPIDRURO in particular needs careful treatment. Since flush_thread basically needs the same code used to set the TLS in arm_syscall, pull that into a common set_tls helper in tls.h and use it in both places. Similarly, TEEHBR needs to be cleared during exec as well. Clearing its save slot in thread_info isn't right as there is no guarantee that a thread switch will occur before the new program runs. Just setting the register directly is sufficient. Signed-off-by: Nathan Lynch <nathan_lynch@mentor.com> Acked-by: Will Deacon <will.deacon@arm.com> Cc: <stable@vger.kernel.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
7a0bd49713
commit
fbfb872f5f
|
@ -1,6 +1,9 @@
|
|||
#ifndef __ASMARM_TLS_H
|
||||
#define __ASMARM_TLS_H
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <asm/thread_info.h>
|
||||
|
||||
#ifdef __ASSEMBLY__
|
||||
#include <asm/asm-offsets.h>
|
||||
.macro switch_tls_none, base, tp, tpuser, tmp1, tmp2
|
||||
|
@ -50,6 +53,47 @@
|
|||
#endif
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
static inline void set_tls(unsigned long val)
|
||||
{
|
||||
struct thread_info *thread;
|
||||
|
||||
thread = current_thread_info();
|
||||
|
||||
thread->tp_value[0] = val;
|
||||
|
||||
/*
|
||||
* This code runs with preemption enabled and therefore must
|
||||
* be reentrant with respect to switch_tls.
|
||||
*
|
||||
* We need to ensure ordering between the shadow state and the
|
||||
* hardware state, so that we don't corrupt the hardware state
|
||||
* with a stale shadow state during context switch.
|
||||
*
|
||||
* If we're preempted here, switch_tls will load TPIDRURO from
|
||||
* thread_info upon resuming execution and the following mcr
|
||||
* is merely redundant.
|
||||
*/
|
||||
barrier();
|
||||
|
||||
if (!tls_emu) {
|
||||
if (has_tls_reg) {
|
||||
asm("mcr p15, 0, %0, c13, c0, 3"
|
||||
: : "r" (val));
|
||||
} else {
|
||||
/*
|
||||
* User space must never try to access this
|
||||
* directly. Expect your app to break
|
||||
* eventually if you do so. The user helper
|
||||
* at 0xffff0fe0 must be used instead. (see
|
||||
* entry-armv.S for details)
|
||||
*/
|
||||
*((unsigned int *)0xffff0ff0) = val;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned long get_tpuser(void)
|
||||
{
|
||||
unsigned long reg = 0;
|
||||
|
@ -59,5 +103,23 @@ static inline unsigned long get_tpuser(void)
|
|||
|
||||
return reg;
|
||||
}
|
||||
|
||||
static inline void set_tpuser(unsigned long val)
|
||||
{
|
||||
/* Since TPIDRURW is fully context-switched (unlike TPIDRURO),
|
||||
* we need not update thread_info.
|
||||
*/
|
||||
if (has_tls_reg && !tls_emu) {
|
||||
asm("mcr p15, 0, %0, c13, c0, 2"
|
||||
: : "r" (val));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void flush_tls(void)
|
||||
{
|
||||
set_tls(0);
|
||||
set_tpuser(0);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* __ASMARM_TLS_H */
|
||||
|
|
|
@ -334,6 +334,8 @@ void flush_thread(void)
|
|||
memset(&tsk->thread.debug, 0, sizeof(struct debug_info));
|
||||
memset(&thread->fpstate, 0, sizeof(union fp_state));
|
||||
|
||||
flush_tls();
|
||||
|
||||
thread_notify(THREAD_NOTIFY_FLUSH, thread);
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ static int thumbee_notifier(struct notifier_block *self, unsigned long cmd, void
|
|||
|
||||
switch (cmd) {
|
||||
case THREAD_NOTIFY_FLUSH:
|
||||
thread->thumbee_state = 0;
|
||||
teehbr_write(0);
|
||||
break;
|
||||
case THREAD_NOTIFY_SWITCH:
|
||||
current_thread_info()->thumbee_state = teehbr_read();
|
||||
|
|
|
@ -581,7 +581,6 @@ do_cache_op(unsigned long start, unsigned long end, int flags)
|
|||
#define NR(x) ((__ARM_NR_##x) - __ARM_NR_BASE)
|
||||
asmlinkage int arm_syscall(int no, struct pt_regs *regs)
|
||||
{
|
||||
struct thread_info *thread = current_thread_info();
|
||||
siginfo_t info;
|
||||
|
||||
if ((no >> 16) != (__ARM_NR_BASE>> 16))
|
||||
|
@ -632,21 +631,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
|
|||
return regs->ARM_r0;
|
||||
|
||||
case NR(set_tls):
|
||||
thread->tp_value[0] = regs->ARM_r0;
|
||||
if (tls_emu)
|
||||
return 0;
|
||||
if (has_tls_reg) {
|
||||
asm ("mcr p15, 0, %0, c13, c0, 3"
|
||||
: : "r" (regs->ARM_r0));
|
||||
} else {
|
||||
/*
|
||||
* User space must never try to access this directly.
|
||||
* Expect your app to break eventually if you do so.
|
||||
* The user helper at 0xffff0fe0 must be used instead.
|
||||
* (see entry-armv.S for details)
|
||||
*/
|
||||
*((unsigned int *)0xffff0ff0) = regs->ARM_r0;
|
||||
}
|
||||
set_tls(regs->ARM_r0);
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG
|
||||
|
|
Loading…
Reference in New Issue