aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorDavid Vrabel <david.vrabel@citrix.com>2012-10-19 12:29:07 -0400
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2012-10-19 15:17:59 -0400
commita349e23d1cf746f8bdc603dcc61fae9ee4a695f6 (patch)
tree49df313d4d1e37189e1ae6f052d11381e1443f80 /arch
parentee7b5958e2494619ee3ff52de68580feed6906a2 (diff)
xen/x86: don't corrupt %eip when returning from a signal handler
In 32 bit guests, if a userspace process has %eax == -ERESTARTSYS (-512) or -ERESTARTNOINTR (-513) when it is interrupted by an event /and/ the process has a pending signal then %eip (and %eax) are corrupted when returning to the main process after handling the signal. The application may then crash with SIGSEGV or a SIGILL or it may have subtly incorrect behaviour (depending on what instruction it returned to). The occurs because handle_signal() is incorrectly thinking that there is a system call that needs to restarted so it adjusts %eip and %eax to re-execute the system call instruction (even though user space had not done a system call). If %eax == -514 (-ERESTARTNOHAND (-514) or -ERESTART_RESTARTBLOCK (-516) then handle_signal() only corrupted %eax (by setting it to -EINTR). This may cause the application to crash or have incorrect behaviour. handle_signal() assumes that regs->orig_ax >= 0 means a system call so any kernel entry point that is not for a system call must push a negative value for orig_ax. For example, for physical interrupts on bare metal the inverse of the vector is pushed and page_fault() sets regs->orig_ax to -1, overwriting the hardware provided error code. xen_hypervisor_callback() was incorrectly pushing 0 for orig_ax instead of -1. Classic Xen kernels pushed %eax which works as %eax cannot be both non-negative and -RESTARTSYS (etc.), but using -1 is consistent with other non-system call entry points and avoids some of the tests in handle_signal(). There were similar bugs in xen_failsafe_callback() of both 32 and 64-bit guests. If the fault was corrected and the normal return path was used then 0 was incorrectly pushed as the value for orig_ax. Signed-off-by: David Vrabel <david.vrabel@citrix.com> Acked-by: Jan Beulich <JBeulich@suse.com> Acked-by: Ian Campbell <ian.campbell@citrix.com> Cc: stable@vger.kernel.org Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kernel/entry_32.S8
-rw-r--r--arch/x86/kernel/entry_64.S2
2 files changed, 6 insertions, 4 deletions
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 623f28837476..8f8e8eea9085 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -1016,7 +1016,7 @@ ENTRY(xen_sysenter_target)
1016 1016
1017ENTRY(xen_hypervisor_callback) 1017ENTRY(xen_hypervisor_callback)
1018 CFI_STARTPROC 1018 CFI_STARTPROC
1019 pushl_cfi $0 1019 pushl_cfi $-1 /* orig_ax = -1 => not a system call */
1020 SAVE_ALL 1020 SAVE_ALL
1021 TRACE_IRQS_OFF 1021 TRACE_IRQS_OFF
1022 1022
@@ -1058,14 +1058,16 @@ ENTRY(xen_failsafe_callback)
10582: mov 8(%esp),%es 10582: mov 8(%esp),%es
10593: mov 12(%esp),%fs 10593: mov 12(%esp),%fs
10604: mov 16(%esp),%gs 10604: mov 16(%esp),%gs
1061 /* EAX == 0 => Category 1 (Bad segment)
1062 EAX != 0 => Category 2 (Bad IRET) */
1061 testl %eax,%eax 1063 testl %eax,%eax
1062 popl_cfi %eax 1064 popl_cfi %eax
1063 lea 16(%esp),%esp 1065 lea 16(%esp),%esp
1064 CFI_ADJUST_CFA_OFFSET -16 1066 CFI_ADJUST_CFA_OFFSET -16
1065 jz 5f 1067 jz 5f
1066 addl $16,%esp 1068 addl $16,%esp
1067 jmp iret_exc # EAX != 0 => Category 2 (Bad IRET) 1069 jmp iret_exc
10685: pushl_cfi $0 # EAX == 0 => Category 1 (Bad segment) 10705: pushl_cfi $-1 /* orig_ax = -1 => not a system call */
1069 SAVE_ALL 1071 SAVE_ALL
1070 jmp ret_from_exception 1072 jmp ret_from_exception
1071 CFI_ENDPROC 1073 CFI_ENDPROC
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 69babd8c834f..dcdd0ea33a32 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -1363,7 +1363,7 @@ ENTRY(xen_failsafe_callback)
1363 CFI_RESTORE r11 1363 CFI_RESTORE r11
1364 addq $0x30,%rsp 1364 addq $0x30,%rsp
1365 CFI_ADJUST_CFA_OFFSET -0x30 1365 CFI_ADJUST_CFA_OFFSET -0x30
1366 pushq_cfi $0 1366 pushq_cfi $-1 /* orig_ax = -1 => not a system call */
1367 SAVE_ALL 1367 SAVE_ALL
1368 jmp error_exit 1368 jmp error_exit
1369 CFI_ENDPROC 1369 CFI_ENDPROC