Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fbfb872f authored by Nathan Lynch's avatar Nathan Lynch Committed by Russell King
Browse files

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: default avatarNathan Lynch <nathan_lynch@mentor.com>
Acked-by: default avatarWill Deacon <will.deacon@arm.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 7a0bd497
Loading
Loading
Loading
Loading
+62 −0
Original line number Diff line number Diff line
#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 */
+2 −0
Original line number Diff line number Diff line
@@ -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);
}

+1 −1
Original line number Diff line number Diff line
@@ -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();
+1 −16
Original line number Diff line number Diff line
@@ -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