Skip to content

Commit fbfb872

Browse files
nlynch-mentorRussell King
authored andcommitted
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 <[email protected]> Acked-by: Will Deacon <[email protected]> Cc: <[email protected]> Signed-off-by: Russell King <[email protected]>
1 parent 7a0bd49 commit fbfb872

File tree

4 files changed

+66
-17
lines changed

4 files changed

+66
-17
lines changed

arch/arm/include/asm/tls.h

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#ifndef __ASMARM_TLS_H
22
#define __ASMARM_TLS_H
33

4+
#include <linux/compiler.h>
5+
#include <asm/thread_info.h>
6+
47
#ifdef __ASSEMBLY__
58
#include <asm/asm-offsets.h>
69
.macro switch_tls_none, base, tp, tpuser, tmp1, tmp2
@@ -50,6 +53,47 @@
5053
#endif
5154

5255
#ifndef __ASSEMBLY__
56+
57+
static inline void set_tls(unsigned long val)
58+
{
59+
struct thread_info *thread;
60+
61+
thread = current_thread_info();
62+
63+
thread->tp_value[0] = val;
64+
65+
/*
66+
* This code runs with preemption enabled and therefore must
67+
* be reentrant with respect to switch_tls.
68+
*
69+
* We need to ensure ordering between the shadow state and the
70+
* hardware state, so that we don't corrupt the hardware state
71+
* with a stale shadow state during context switch.
72+
*
73+
* If we're preempted here, switch_tls will load TPIDRURO from
74+
* thread_info upon resuming execution and the following mcr
75+
* is merely redundant.
76+
*/
77+
barrier();
78+
79+
if (!tls_emu) {
80+
if (has_tls_reg) {
81+
asm("mcr p15, 0, %0, c13, c0, 3"
82+
: : "r" (val));
83+
} else {
84+
/*
85+
* User space must never try to access this
86+
* directly. Expect your app to break
87+
* eventually if you do so. The user helper
88+
* at 0xffff0fe0 must be used instead. (see
89+
* entry-armv.S for details)
90+
*/
91+
*((unsigned int *)0xffff0ff0) = val;
92+
}
93+
94+
}
95+
}
96+
5397
static inline unsigned long get_tpuser(void)
5498
{
5599
unsigned long reg = 0;
@@ -59,5 +103,23 @@ static inline unsigned long get_tpuser(void)
59103

60104
return reg;
61105
}
106+
107+
static inline void set_tpuser(unsigned long val)
108+
{
109+
/* Since TPIDRURW is fully context-switched (unlike TPIDRURO),
110+
* we need not update thread_info.
111+
*/
112+
if (has_tls_reg && !tls_emu) {
113+
asm("mcr p15, 0, %0, c13, c0, 2"
114+
: : "r" (val));
115+
}
116+
}
117+
118+
static inline void flush_tls(void)
119+
{
120+
set_tls(0);
121+
set_tpuser(0);
122+
}
123+
62124
#endif
63125
#endif /* __ASMARM_TLS_H */

arch/arm/kernel/process.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,8 @@ void flush_thread(void)
334334
memset(&tsk->thread.debug, 0, sizeof(struct debug_info));
335335
memset(&thread->fpstate, 0, sizeof(union fp_state));
336336

337+
flush_tls();
338+
337339
thread_notify(THREAD_NOTIFY_FLUSH, thread);
338340
}
339341

arch/arm/kernel/thumbee.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ static int thumbee_notifier(struct notifier_block *self, unsigned long cmd, void
4545

4646
switch (cmd) {
4747
case THREAD_NOTIFY_FLUSH:
48-
thread->thumbee_state = 0;
48+
teehbr_write(0);
4949
break;
5050
case THREAD_NOTIFY_SWITCH:
5151
current_thread_info()->thumbee_state = teehbr_read();

arch/arm/kernel/traps.c

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,6 @@ do_cache_op(unsigned long start, unsigned long end, int flags)
581581
#define NR(x) ((__ARM_NR_##x) - __ARM_NR_BASE)
582582
asmlinkage int arm_syscall(int no, struct pt_regs *regs)
583583
{
584-
struct thread_info *thread = current_thread_info();
585584
siginfo_t info;
586585

587586
if ((no >> 16) != (__ARM_NR_BASE>> 16))
@@ -632,21 +631,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
632631
return regs->ARM_r0;
633632

634633
case NR(set_tls):
635-
thread->tp_value[0] = regs->ARM_r0;
636-
if (tls_emu)
637-
return 0;
638-
if (has_tls_reg) {
639-
asm ("mcr p15, 0, %0, c13, c0, 3"
640-
: : "r" (regs->ARM_r0));
641-
} else {
642-
/*
643-
* User space must never try to access this directly.
644-
* Expect your app to break eventually if you do so.
645-
* The user helper at 0xffff0fe0 must be used instead.
646-
* (see entry-armv.S for details)
647-
*/
648-
*((unsigned int *)0xffff0ff0) = regs->ARM_r0;
649-
}
634+
set_tls(regs->ARM_r0);
650635
return 0;
651636

652637
#ifdef CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG

0 commit comments

Comments
 (0)