Commit a349e23d authored by David Vrabel's avatar David Vrabel Committed by Konrad Rzeszutek Wilk

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: default avatarDavid Vrabel <david.vrabel@citrix.com>
Acked-by: default avatarJan Beulich <JBeulich@suse.com>
Acked-by: default avatarIan Campbell <ian.campbell@citrix.com>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
parent ee7b5958
...@@ -1016,7 +1016,7 @@ ENTRY(xen_sysenter_target) ...@@ -1016,7 +1016,7 @@ ENTRY(xen_sysenter_target)
ENTRY(xen_hypervisor_callback) ENTRY(xen_hypervisor_callback)
CFI_STARTPROC CFI_STARTPROC
pushl_cfi $0 pushl_cfi $-1 /* orig_ax = -1 => not a system call */
SAVE_ALL SAVE_ALL
TRACE_IRQS_OFF TRACE_IRQS_OFF
...@@ -1058,14 +1058,16 @@ ENTRY(xen_failsafe_callback) ...@@ -1058,14 +1058,16 @@ ENTRY(xen_failsafe_callback)
2: mov 8(%esp),%es 2: mov 8(%esp),%es
3: mov 12(%esp),%fs 3: mov 12(%esp),%fs
4: mov 16(%esp),%gs 4: mov 16(%esp),%gs
/* EAX == 0 => Category 1 (Bad segment)
EAX != 0 => Category 2 (Bad IRET) */
testl %eax,%eax testl %eax,%eax
popl_cfi %eax popl_cfi %eax
lea 16(%esp),%esp lea 16(%esp),%esp
CFI_ADJUST_CFA_OFFSET -16 CFI_ADJUST_CFA_OFFSET -16
jz 5f jz 5f
addl $16,%esp addl $16,%esp
jmp iret_exc # EAX != 0 => Category 2 (Bad IRET) jmp iret_exc
5: pushl_cfi $0 # EAX == 0 => Category 1 (Bad segment) 5: pushl_cfi $-1 /* orig_ax = -1 => not a system call */
SAVE_ALL SAVE_ALL
jmp ret_from_exception jmp ret_from_exception
CFI_ENDPROC CFI_ENDPROC
......
...@@ -1363,7 +1363,7 @@ ENTRY(xen_failsafe_callback) ...@@ -1363,7 +1363,7 @@ ENTRY(xen_failsafe_callback)
CFI_RESTORE r11 CFI_RESTORE r11
addq $0x30,%rsp addq $0x30,%rsp
CFI_ADJUST_CFA_OFFSET -0x30 CFI_ADJUST_CFA_OFFSET -0x30
pushq_cfi $0 pushq_cfi $-1 /* orig_ax = -1 => not a system call */
SAVE_ALL SAVE_ALL
jmp error_exit jmp error_exit
CFI_ENDPROC CFI_ENDPROC
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment