x86_64, traps: Rework bad_iret
authorAndy Lutomirski <luto@amacapital.net>
Sun, 23 Nov 2014 02:00:33 +0000 (18:00 -0800)
committerZefan Li <lizefan@huawei.com>
Mon, 2 Feb 2015 09:05:23 +0000 (17:05 +0800)
commitc0cb6036899b7ef63f4cac1c9a951c87ff78686e
treeb91f5bcd82cdfc63d067e6713cc2304fbabaacdb
parentfbe1dd0c2eb7fcd9b21aac5bfee924a9e0223f1b
x86_64, traps: Rework bad_iret

commit b645af2d5905c4e32399005b867987919cbfc3ae upstream.

It's possible for iretq to userspace to fail.  This can happen because
of a bad CS, SS, or RIP.

Historically, we've handled it by fixing up an exception from iretq to
land at bad_iret, which pretends that the failed iret frame was really
the hardware part of #GP(0) from userspace.  To make this work, there's
an extra fixup to fudge the gs base into a usable state.

This is suboptimal because it loses the original exception.  It's also
buggy because there's no guarantee that we were on the kernel stack to
begin with.  For example, if the failing iret happened on return from an
NMI, then we'll end up executing general_protection on the NMI stack.
This is bad for several reasons, the most immediate of which is that
general_protection, as a non-paranoid idtentry, will try to deliver
signals and/or schedule from the wrong stack.

This patch throws out bad_iret entirely.  As a replacement, it augments
the existing swapgs fudge into a full-blown iret fixup, mostly written
in C.  It's should be clearer and more correct.

Signed-off-by: Andy Lutomirski <luto@amacapital.net>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
[bwh: Backported to 3.2:
 - We didn't use the _ASM_EXTABLE macro
 - Don't use __visible]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: Zefan Li <lizefan@huawei.com>
arch/x86/kernel/entry_64.S
arch/x86/kernel/traps.c