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

x86/entry/64: Really create an error-entry-from-usermode code path

In 539f51136500 ("x86/asm/entry/64: Disentangle error_entry/exit
gsbase/ebx/usermode code"), I arranged the code slightly wrong
-- IRET faults would skip the code path that was intended to
execute on all error entries from user mode. Fix it up.

While we're at it, make all the labels in error_entry local.

This does not fix a bug, but we'll need it, and it slightly
shrinks the code.

Signed-off-by: Andy Lutomirski <luto@kernel.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Denys Vlasenko <vda.linux@googlemail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rik van Riel <riel@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: paulmck@linux.vnet.ibm.com
Link: http://lkml.kernel.org/r/91e17891e49fa3d61357eadc451529ad48143ee1.1435952415.git.luto@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Andy Lutomirski and committed by
Ingo Molnar
cb6f64ed c5c46f59

+16 -12
+16 -12
arch/x86/entry/entry_64.S
··· 1143 1143 SAVE_EXTRA_REGS 8 1144 1144 xorl %ebx, %ebx 1145 1145 testb $3, CS+8(%rsp) 1146 - jz error_kernelspace 1146 + jz .Lerror_kernelspace 1147 1147 1148 - /* We entered from user mode */ 1148 + .Lerror_entry_from_usermode_swapgs: 1149 + /* 1150 + * We entered from user mode or we're pretending to have entered 1151 + * from user mode due to an IRET fault. 1152 + */ 1149 1153 SWAPGS 1150 1154 1151 - error_entry_done: 1155 + .Lerror_entry_from_usermode_after_swapgs: 1156 + .Lerror_entry_done: 1152 1157 TRACE_IRQS_OFF 1153 1158 ret 1154 1159 ··· 1163 1158 * truncated RIP for IRET exceptions returning to compat mode. Check 1164 1159 * for these here too. 1165 1160 */ 1166 - error_kernelspace: 1161 + .Lerror_kernelspace: 1167 1162 incl %ebx 1168 1163 leaq native_irq_return_iret(%rip), %rcx 1169 1164 cmpq %rcx, RIP+8(%rsp) 1170 - je error_bad_iret 1165 + je .Lerror_bad_iret 1171 1166 movl %ecx, %eax /* zero extend */ 1172 1167 cmpq %rax, RIP+8(%rsp) 1173 - je bstep_iret 1168 + je .Lbstep_iret 1174 1169 cmpq $gs_change, RIP+8(%rsp) 1175 - jne error_entry_done 1170 + jne .Lerror_entry_done 1176 1171 1177 1172 /* 1178 1173 * hack: gs_change can fail with user gsbase. If this happens, fix up 1179 1174 * gsbase and proceed. We'll fix up the exception and land in 1180 1175 * gs_change's error handler with kernel gsbase. 1181 1176 */ 1182 - SWAPGS 1183 - jmp error_entry_done 1177 + jmp .Lerror_entry_from_usermode_swapgs 1184 1178 1185 - bstep_iret: 1179 + .Lbstep_iret: 1186 1180 /* Fix truncated RIP */ 1187 1181 movq %rcx, RIP+8(%rsp) 1188 1182 /* fall through */ 1189 1183 1190 - error_bad_iret: 1184 + .Lerror_bad_iret: 1191 1185 /* 1192 1186 * We came from an IRET to user mode, so we have user gsbase. 1193 1187 * Switch to kernel gsbase: ··· 1202 1198 call fixup_bad_iret 1203 1199 mov %rax, %rsp 1204 1200 decl %ebx 1205 - jmp error_entry_done 1201 + jmp .Lerror_entry_from_usermode_after_swapgs 1206 1202 END(error_entry) 1207 1203 1208 1204