aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-12-08 13:08:23 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-12-08 13:08:23 -0500
commit6e7e7f4ddc742c390f289b98fe1e53e7487facd7 (patch)
treefbb26f7a662f6c6f311d0862b80d8985aeac0564
parent3625de4b2872e7d25730749680af029ba0957e18 (diff)
parentcb968afc789821cdf9e17e79ef08ab90e5bae0f2 (diff)
Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
Pull arm64 fixes from Will Deacon: "Fix some more FP register fallout from the SVE patches and also some problems with the PGD tracking in our software PAN emulation code, after we received a crash report from a 3.18 kernel running a backport. Summary: - fix SW PAN pgd shadowing for kernel threads, EFI and exiting user tasks - fix FP register leak when a task_struct is re-allocated - fix potential use-after-free in FP state tracking used by KVM" * tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: arm64/sve: Avoid dereference of dead task_struct in KVM guest entry arm64: SW PAN: Update saved ttbr0 value on enter_lazy_tlb arm64: SW PAN: Point saved ttbr0 at the zero page when switching to init_mm arm64: fpsimd: Abstract out binding of task's fpsimd context to the cpu. arm64: fpsimd: Prevent registers leaking from dead tasks
-rw-r--r--arch/arm64/include/asm/efi.h4
-rw-r--r--arch/arm64/include/asm/mmu_context.h46
-rw-r--r--arch/arm64/kernel/fpsimd.c51
-rw-r--r--arch/arm64/kernel/process.c9
4 files changed, 63 insertions, 47 deletions
diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
index 650344d01124..c4cd5081d78b 100644
--- a/arch/arm64/include/asm/efi.h
+++ b/arch/arm64/include/asm/efi.h
@@ -132,11 +132,9 @@ static inline void efi_set_pgd(struct mm_struct *mm)
132 * Defer the switch to the current thread's TTBR0_EL1 132 * Defer the switch to the current thread's TTBR0_EL1
133 * until uaccess_enable(). Restore the current 133 * until uaccess_enable(). Restore the current
134 * thread's saved ttbr0 corresponding to its active_mm 134 * thread's saved ttbr0 corresponding to its active_mm
135 * (if different from init_mm).
136 */ 135 */
137 cpu_set_reserved_ttbr0(); 136 cpu_set_reserved_ttbr0();
138 if (current->active_mm != &init_mm) 137 update_saved_ttbr0(current, current->active_mm);
139 update_saved_ttbr0(current, current->active_mm);
140 } 138 }
141 } 139 }
142} 140}
diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h
index 3257895a9b5e..9d155fa9a507 100644
--- a/arch/arm64/include/asm/mmu_context.h
+++ b/arch/arm64/include/asm/mmu_context.h
@@ -156,29 +156,21 @@ void check_and_switch_context(struct mm_struct *mm, unsigned int cpu);
156 156
157#define init_new_context(tsk,mm) ({ atomic64_set(&(mm)->context.id, 0); 0; }) 157#define init_new_context(tsk,mm) ({ atomic64_set(&(mm)->context.id, 0); 0; })
158 158
159/*
160 * This is called when "tsk" is about to enter lazy TLB mode.
161 *
162 * mm: describes the currently active mm context
163 * tsk: task which is entering lazy tlb
164 * cpu: cpu number which is entering lazy tlb
165 *
166 * tsk->mm will be NULL
167 */
168static inline void
169enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
170{
171}
172
173#ifdef CONFIG_ARM64_SW_TTBR0_PAN 159#ifdef CONFIG_ARM64_SW_TTBR0_PAN
174static inline void update_saved_ttbr0(struct task_struct *tsk, 160static inline void update_saved_ttbr0(struct task_struct *tsk,
175 struct mm_struct *mm) 161 struct mm_struct *mm)
176{ 162{
177 if (system_uses_ttbr0_pan()) { 163 u64 ttbr;
178 BUG_ON(mm->pgd == swapper_pg_dir); 164
179 task_thread_info(tsk)->ttbr0 = 165 if (!system_uses_ttbr0_pan())
180 virt_to_phys(mm->pgd) | ASID(mm) << 48; 166 return;
181 } 167
168 if (mm == &init_mm)
169 ttbr = __pa_symbol(empty_zero_page);
170 else
171 ttbr = virt_to_phys(mm->pgd) | ASID(mm) << 48;
172
173 task_thread_info(tsk)->ttbr0 = ttbr;
182} 174}
183#else 175#else
184static inline void update_saved_ttbr0(struct task_struct *tsk, 176static inline void update_saved_ttbr0(struct task_struct *tsk,
@@ -187,6 +179,16 @@ static inline void update_saved_ttbr0(struct task_struct *tsk,
187} 179}
188#endif 180#endif
189 181
182static inline void
183enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
184{
185 /*
186 * We don't actually care about the ttbr0 mapping, so point it at the
187 * zero page.
188 */
189 update_saved_ttbr0(tsk, &init_mm);
190}
191
190static inline void __switch_mm(struct mm_struct *next) 192static inline void __switch_mm(struct mm_struct *next)
191{ 193{
192 unsigned int cpu = smp_processor_id(); 194 unsigned int cpu = smp_processor_id();
@@ -214,11 +216,9 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
214 * Update the saved TTBR0_EL1 of the scheduled-in task as the previous 216 * Update the saved TTBR0_EL1 of the scheduled-in task as the previous
215 * value may have not been initialised yet (activate_mm caller) or the 217 * value may have not been initialised yet (activate_mm caller) or the
216 * ASID has changed since the last run (following the context switch 218 * ASID has changed since the last run (following the context switch
217 * of another thread of the same process). Avoid setting the reserved 219 * of another thread of the same process).
218 * TTBR0_EL1 to swapper_pg_dir (init_mm; e.g. via idle_task_exit).
219 */ 220 */
220 if (next != &init_mm) 221 update_saved_ttbr0(tsk, next);
221 update_saved_ttbr0(tsk, next);
222} 222}
223 223
224#define deactivate_mm(tsk,mm) do { } while (0) 224#define deactivate_mm(tsk,mm) do { } while (0)
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 5084e699447a..540a1e010eb5 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -114,7 +114,12 @@
114 * returned from the 2nd syscall yet, TIF_FOREIGN_FPSTATE is still set so 114 * returned from the 2nd syscall yet, TIF_FOREIGN_FPSTATE is still set so
115 * whatever is in the FPSIMD registers is not saved to memory, but discarded. 115 * whatever is in the FPSIMD registers is not saved to memory, but discarded.
116 */ 116 */
117static DEFINE_PER_CPU(struct fpsimd_state *, fpsimd_last_state); 117struct fpsimd_last_state_struct {
118 struct fpsimd_state *st;
119 bool sve_in_use;
120};
121
122static DEFINE_PER_CPU(struct fpsimd_last_state_struct, fpsimd_last_state);
118 123
119/* Default VL for tasks that don't set it explicitly: */ 124/* Default VL for tasks that don't set it explicitly: */
120static int sve_default_vl = -1; 125static int sve_default_vl = -1;
@@ -905,7 +910,7 @@ void fpsimd_thread_switch(struct task_struct *next)
905 */ 910 */
906 struct fpsimd_state *st = &next->thread.fpsimd_state; 911 struct fpsimd_state *st = &next->thread.fpsimd_state;
907 912
908 if (__this_cpu_read(fpsimd_last_state) == st 913 if (__this_cpu_read(fpsimd_last_state.st) == st
909 && st->cpu == smp_processor_id()) 914 && st->cpu == smp_processor_id())
910 clear_tsk_thread_flag(next, TIF_FOREIGN_FPSTATE); 915 clear_tsk_thread_flag(next, TIF_FOREIGN_FPSTATE);
911 else 916 else
@@ -992,6 +997,21 @@ void fpsimd_signal_preserve_current_state(void)
992} 997}
993 998
994/* 999/*
1000 * Associate current's FPSIMD context with this cpu
1001 * Preemption must be disabled when calling this function.
1002 */
1003static void fpsimd_bind_to_cpu(void)
1004{
1005 struct fpsimd_last_state_struct *last =
1006 this_cpu_ptr(&fpsimd_last_state);
1007 struct fpsimd_state *st = &current->thread.fpsimd_state;
1008
1009 last->st = st;
1010 last->sve_in_use = test_thread_flag(TIF_SVE);
1011 st->cpu = smp_processor_id();
1012}
1013
1014/*
995 * Load the userland FPSIMD state of 'current' from memory, but only if the 1015 * Load the userland FPSIMD state of 'current' from memory, but only if the
996 * FPSIMD state already held in the registers is /not/ the most recent FPSIMD 1016 * FPSIMD state already held in the registers is /not/ the most recent FPSIMD
997 * state of 'current' 1017 * state of 'current'
@@ -1004,11 +1024,8 @@ void fpsimd_restore_current_state(void)
1004 local_bh_disable(); 1024 local_bh_disable();
1005 1025
1006 if (test_and_clear_thread_flag(TIF_FOREIGN_FPSTATE)) { 1026 if (test_and_clear_thread_flag(TIF_FOREIGN_FPSTATE)) {
1007 struct fpsimd_state *st = &current->thread.fpsimd_state;
1008
1009 task_fpsimd_load(); 1027 task_fpsimd_load();
1010 __this_cpu_write(fpsimd_last_state, st); 1028 fpsimd_bind_to_cpu();
1011 st->cpu = smp_processor_id();
1012 } 1029 }
1013 1030
1014 local_bh_enable(); 1031 local_bh_enable();
@@ -1032,12 +1049,8 @@ void fpsimd_update_current_state(struct fpsimd_state *state)
1032 1049
1033 task_fpsimd_load(); 1050 task_fpsimd_load();
1034 1051
1035 if (test_and_clear_thread_flag(TIF_FOREIGN_FPSTATE)) { 1052 if (test_and_clear_thread_flag(TIF_FOREIGN_FPSTATE))
1036 struct fpsimd_state *st = &current->thread.fpsimd_state; 1053 fpsimd_bind_to_cpu();
1037
1038 __this_cpu_write(fpsimd_last_state, st);
1039 st->cpu = smp_processor_id();
1040 }
1041 1054
1042 local_bh_enable(); 1055 local_bh_enable();
1043} 1056}
@@ -1052,7 +1065,7 @@ void fpsimd_flush_task_state(struct task_struct *t)
1052 1065
1053static inline void fpsimd_flush_cpu_state(void) 1066static inline void fpsimd_flush_cpu_state(void)
1054{ 1067{
1055 __this_cpu_write(fpsimd_last_state, NULL); 1068 __this_cpu_write(fpsimd_last_state.st, NULL);
1056} 1069}
1057 1070
1058/* 1071/*
@@ -1065,14 +1078,10 @@ static inline void fpsimd_flush_cpu_state(void)
1065#ifdef CONFIG_ARM64_SVE 1078#ifdef CONFIG_ARM64_SVE
1066void sve_flush_cpu_state(void) 1079void sve_flush_cpu_state(void)
1067{ 1080{
1068 struct fpsimd_state *const fpstate = __this_cpu_read(fpsimd_last_state); 1081 struct fpsimd_last_state_struct const *last =
1069 struct task_struct *tsk; 1082 this_cpu_ptr(&fpsimd_last_state);
1070
1071 if (!fpstate)
1072 return;
1073 1083
1074 tsk = container_of(fpstate, struct task_struct, thread.fpsimd_state); 1084 if (last->st && last->sve_in_use)
1075 if (test_tsk_thread_flag(tsk, TIF_SVE))
1076 fpsimd_flush_cpu_state(); 1085 fpsimd_flush_cpu_state();
1077} 1086}
1078#endif /* CONFIG_ARM64_SVE */ 1087#endif /* CONFIG_ARM64_SVE */
@@ -1267,7 +1276,7 @@ static inline void fpsimd_pm_init(void) { }
1267#ifdef CONFIG_HOTPLUG_CPU 1276#ifdef CONFIG_HOTPLUG_CPU
1268static int fpsimd_cpu_dead(unsigned int cpu) 1277static int fpsimd_cpu_dead(unsigned int cpu)
1269{ 1278{
1270 per_cpu(fpsimd_last_state, cpu) = NULL; 1279 per_cpu(fpsimd_last_state.st, cpu) = NULL;
1271 return 0; 1280 return 0;
1272} 1281}
1273 1282
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index b2adcce7bc18..6b7dcf4310ac 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -314,6 +314,15 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
314 clear_tsk_thread_flag(p, TIF_SVE); 314 clear_tsk_thread_flag(p, TIF_SVE);
315 p->thread.sve_state = NULL; 315 p->thread.sve_state = NULL;
316 316
317 /*
318 * In case p was allocated the same task_struct pointer as some
319 * other recently-exited task, make sure p is disassociated from
320 * any cpu that may have run that now-exited task recently.
321 * Otherwise we could erroneously skip reloading the FPSIMD
322 * registers for p.
323 */
324 fpsimd_flush_task_state(p);
325
317 if (likely(!(p->flags & PF_KTHREAD))) { 326 if (likely(!(p->flags & PF_KTHREAD))) {
318 *childregs = *current_pt_regs(); 327 *childregs = *current_pt_regs();
319 childregs->regs[0] = 0; 328 childregs->regs[0] = 0;