Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+63 -47
+1 -3
arch/arm64/include/asm/efi.h
··· 132 132 * Defer the switch to the current thread's TTBR0_EL1 133 133 * until uaccess_enable(). Restore the current 134 134 * thread's saved ttbr0 corresponding to its active_mm 135 - * (if different from init_mm). 136 135 */ 137 136 cpu_set_reserved_ttbr0(); 138 - if (current->active_mm != &init_mm) 139 - update_saved_ttbr0(current, current->active_mm); 137 + update_saved_ttbr0(current, current->active_mm); 140 138 } 141 139 } 142 140 }
+23 -23
arch/arm64/include/asm/mmu_context.h
··· 156 156 157 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 - */ 168 - static inline void 169 - enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) 170 - { 171 - } 172 - 173 159 #ifdef CONFIG_ARM64_SW_TTBR0_PAN 174 160 static inline void update_saved_ttbr0(struct task_struct *tsk, 175 161 struct mm_struct *mm) 176 162 { 177 - if (system_uses_ttbr0_pan()) { 178 - BUG_ON(mm->pgd == swapper_pg_dir); 179 - task_thread_info(tsk)->ttbr0 = 180 - virt_to_phys(mm->pgd) | ASID(mm) << 48; 181 - } 163 + u64 ttbr; 164 + 165 + if (!system_uses_ttbr0_pan()) 166 + return; 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 175 #else 184 176 static inline void update_saved_ttbr0(struct task_struct *tsk, ··· 178 186 { 179 187 } 180 188 #endif 189 + 190 + static inline void 191 + enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) 192 + { 193 + /* 194 + * We don't actually care about the ttbr0 mapping, so point it at the 195 + * zero page. 196 + */ 197 + update_saved_ttbr0(tsk, &init_mm); 198 + } 181 199 182 200 static inline void __switch_mm(struct mm_struct *next) 183 201 { ··· 216 214 * Update the saved TTBR0_EL1 of the scheduled-in task as the previous 217 215 * value may have not been initialised yet (activate_mm caller) or the 218 216 * ASID has changed since the last run (following the context switch 219 - * of another thread of the same process). Avoid setting the reserved 220 - * TTBR0_EL1 to swapper_pg_dir (init_mm; e.g. via idle_task_exit). 217 + * of another thread of the same process). 221 218 */ 222 - if (next != &init_mm) 223 - update_saved_ttbr0(tsk, next); 219 + update_saved_ttbr0(tsk, next); 224 220 } 225 221 226 222 #define deactivate_mm(tsk,mm) do { } while (0)
+30 -21
arch/arm64/kernel/fpsimd.c
··· 114 114 * returned from the 2nd syscall yet, TIF_FOREIGN_FPSTATE is still set so 115 115 * whatever is in the FPSIMD registers is not saved to memory, but discarded. 116 116 */ 117 - static DEFINE_PER_CPU(struct fpsimd_state *, fpsimd_last_state); 117 + struct fpsimd_last_state_struct { 118 + struct fpsimd_state *st; 119 + bool sve_in_use; 120 + }; 121 + 122 + static DEFINE_PER_CPU(struct fpsimd_last_state_struct, fpsimd_last_state); 118 123 119 124 /* Default VL for tasks that don't set it explicitly: */ 120 125 static int sve_default_vl = -1; ··· 910 905 */ 911 906 struct fpsimd_state *st = &next->thread.fpsimd_state; 912 907 913 - if (__this_cpu_read(fpsimd_last_state) == st 908 + if (__this_cpu_read(fpsimd_last_state.st) == st 914 909 && st->cpu == smp_processor_id()) 915 910 clear_tsk_thread_flag(next, TIF_FOREIGN_FPSTATE); 916 911 else ··· 997 992 } 998 993 999 994 /* 995 + * Associate current's FPSIMD context with this cpu 996 + * Preemption must be disabled when calling this function. 997 + */ 998 + static void fpsimd_bind_to_cpu(void) 999 + { 1000 + struct fpsimd_last_state_struct *last = 1001 + this_cpu_ptr(&fpsimd_last_state); 1002 + struct fpsimd_state *st = &current->thread.fpsimd_state; 1003 + 1004 + last->st = st; 1005 + last->sve_in_use = test_thread_flag(TIF_SVE); 1006 + st->cpu = smp_processor_id(); 1007 + } 1008 + 1009 + /* 1000 1010 * Load the userland FPSIMD state of 'current' from memory, but only if the 1001 1011 * FPSIMD state already held in the registers is /not/ the most recent FPSIMD 1002 1012 * state of 'current' ··· 1024 1004 local_bh_disable(); 1025 1005 1026 1006 if (test_and_clear_thread_flag(TIF_FOREIGN_FPSTATE)) { 1027 - struct fpsimd_state *st = &current->thread.fpsimd_state; 1028 - 1029 1007 task_fpsimd_load(); 1030 - __this_cpu_write(fpsimd_last_state, st); 1031 - st->cpu = smp_processor_id(); 1008 + fpsimd_bind_to_cpu(); 1032 1009 } 1033 1010 1034 1011 local_bh_enable(); ··· 1049 1032 1050 1033 task_fpsimd_load(); 1051 1034 1052 - if (test_and_clear_thread_flag(TIF_FOREIGN_FPSTATE)) { 1053 - struct fpsimd_state *st = &current->thread.fpsimd_state; 1054 - 1055 - __this_cpu_write(fpsimd_last_state, st); 1056 - st->cpu = smp_processor_id(); 1057 - } 1035 + if (test_and_clear_thread_flag(TIF_FOREIGN_FPSTATE)) 1036 + fpsimd_bind_to_cpu(); 1058 1037 1059 1038 local_bh_enable(); 1060 1039 } ··· 1065 1052 1066 1053 static inline void fpsimd_flush_cpu_state(void) 1067 1054 { 1068 - __this_cpu_write(fpsimd_last_state, NULL); 1055 + __this_cpu_write(fpsimd_last_state.st, NULL); 1069 1056 } 1070 1057 1071 1058 /* ··· 1078 1065 #ifdef CONFIG_ARM64_SVE 1079 1066 void sve_flush_cpu_state(void) 1080 1067 { 1081 - struct fpsimd_state *const fpstate = __this_cpu_read(fpsimd_last_state); 1082 - struct task_struct *tsk; 1068 + struct fpsimd_last_state_struct const *last = 1069 + this_cpu_ptr(&fpsimd_last_state); 1083 1070 1084 - if (!fpstate) 1085 - return; 1086 - 1087 - tsk = container_of(fpstate, struct task_struct, thread.fpsimd_state); 1088 - if (test_tsk_thread_flag(tsk, TIF_SVE)) 1071 + if (last->st && last->sve_in_use) 1089 1072 fpsimd_flush_cpu_state(); 1090 1073 } 1091 1074 #endif /* CONFIG_ARM64_SVE */ ··· 1276 1267 #ifdef CONFIG_HOTPLUG_CPU 1277 1268 static int fpsimd_cpu_dead(unsigned int cpu) 1278 1269 { 1279 - per_cpu(fpsimd_last_state, cpu) = NULL; 1270 + per_cpu(fpsimd_last_state.st, cpu) = NULL; 1280 1271 return 0; 1281 1272 } 1282 1273
+9
arch/arm64/kernel/process.c
··· 314 314 clear_tsk_thread_flag(p, TIF_SVE); 315 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 326 if (likely(!(p->flags & PF_KTHREAD))) { 318 327 *childregs = *current_pt_regs(); 319 328 childregs->regs[0] = 0;