aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSalman Qazi <sqazi@google.com>2012-10-01 20:29:25 -0400
committerSteven Rostedt <rostedt@goodmis.org>2012-11-02 11:29:36 -0400
commit28696f434fef0efa97534b59986ad33b9c4df7f8 (patch)
tree2b91ecd62ee6c82d727584b2753fa09c4094b1c6
parent269833bd5a0f4443873da358b71675a890b47c3c (diff)
x86: Don't clobber top of pt_regs in nested NMI
The nested NMI modifies the place (instruction, flags and stack) that the first NMI will iret to. However, the copy of registers modified is exactly the one that is the part of pt_regs in the first NMI. This can change the behaviour of the first NMI. In particular, Google's arch_trigger_all_cpu_backtrace handler also prints regions of memory surrounding addresses appearing in registers. This results in handled exceptions, after which nested NMIs start coming in. These nested NMIs change the value of registers in pt_regs. This can cause the original NMI handler to produce incorrect output. We solve this problem by interchanging the position of the preserved copy of the iret registers ("saved") and the copy subject to being trampled by nested NMI ("copied"). Link: http://lkml.kernel.org/r/20121002002919.27236.14388.stgit@dungbeetle.mtv.corp.google.com Signed-off-by: Salman Qazi <sqazi@google.com> [ Added a needed CFI_ADJUST_CFA_OFFSET ] Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--arch/x86/kernel/entry_64.S41
1 files changed, 27 insertions, 14 deletions
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index b51b2c7ee51f..811795db4fc6 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -1699,9 +1699,10 @@ nested_nmi:
1699 1699
17001: 17001:
1701 /* Set up the interrupted NMIs stack to jump to repeat_nmi */ 1701 /* Set up the interrupted NMIs stack to jump to repeat_nmi */
1702 leaq -6*8(%rsp), %rdx 1702 leaq -1*8(%rsp), %rdx
1703 movq %rdx, %rsp 1703 movq %rdx, %rsp
1704 CFI_ADJUST_CFA_OFFSET 6*8 1704 CFI_ADJUST_CFA_OFFSET 1*8
1705 leaq -10*8(%rsp), %rdx
1705 pushq_cfi $__KERNEL_DS 1706 pushq_cfi $__KERNEL_DS
1706 pushq_cfi %rdx 1707 pushq_cfi %rdx
1707 pushfq_cfi 1708 pushfq_cfi
@@ -1709,8 +1710,8 @@ nested_nmi:
1709 pushq_cfi $repeat_nmi 1710 pushq_cfi $repeat_nmi
1710 1711
1711 /* Put stack back */ 1712 /* Put stack back */
1712 addq $(11*8), %rsp 1713 addq $(6*8), %rsp
1713 CFI_ADJUST_CFA_OFFSET -11*8 1714 CFI_ADJUST_CFA_OFFSET -6*8
1714 1715
1715nested_nmi_out: 1716nested_nmi_out:
1716 popq_cfi %rdx 1717 popq_cfi %rdx
@@ -1736,18 +1737,18 @@ first_nmi:
1736 * +-------------------------+ 1737 * +-------------------------+
1737 * | NMI executing variable | 1738 * | NMI executing variable |
1738 * +-------------------------+ 1739 * +-------------------------+
1739 * | Saved SS |
1740 * | Saved Return RSP |
1741 * | Saved RFLAGS |
1742 * | Saved CS |
1743 * | Saved RIP |
1744 * +-------------------------+
1745 * | copied SS | 1740 * | copied SS |
1746 * | copied Return RSP | 1741 * | copied Return RSP |
1747 * | copied RFLAGS | 1742 * | copied RFLAGS |
1748 * | copied CS | 1743 * | copied CS |
1749 * | copied RIP | 1744 * | copied RIP |
1750 * +-------------------------+ 1745 * +-------------------------+
1746 * | Saved SS |
1747 * | Saved Return RSP |
1748 * | Saved RFLAGS |
1749 * | Saved CS |
1750 * | Saved RIP |
1751 * +-------------------------+
1751 * | pt_regs | 1752 * | pt_regs |
1752 * +-------------------------+ 1753 * +-------------------------+
1753 * 1754 *
@@ -1763,9 +1764,14 @@ first_nmi:
1763 /* Set the NMI executing variable on the stack. */ 1764 /* Set the NMI executing variable on the stack. */
1764 pushq_cfi $1 1765 pushq_cfi $1
1765 1766
1767 /*
1768 * Leave room for the "copied" frame
1769 */
1770 subq $(5*8), %rsp
1771
1766 /* Copy the stack frame to the Saved frame */ 1772 /* Copy the stack frame to the Saved frame */
1767 .rept 5 1773 .rept 5
1768 pushq_cfi 6*8(%rsp) 1774 pushq_cfi 11*8(%rsp)
1769 .endr 1775 .endr
1770 CFI_DEF_CFA_OFFSET SS+8-RIP 1776 CFI_DEF_CFA_OFFSET SS+8-RIP
1771 1777
@@ -1786,12 +1792,15 @@ repeat_nmi:
1786 * is benign for the non-repeat case, where 1 was pushed just above 1792 * is benign for the non-repeat case, where 1 was pushed just above
1787 * to this very stack slot). 1793 * to this very stack slot).
1788 */ 1794 */
1789 movq $1, 5*8(%rsp) 1795 movq $1, 10*8(%rsp)
1790 1796
1791 /* Make another copy, this one may be modified by nested NMIs */ 1797 /* Make another copy, this one may be modified by nested NMIs */
1798 addq $(10*8), %rsp
1799 CFI_ADJUST_CFA_OFFSET -10*8
1792 .rept 5 1800 .rept 5
1793 pushq_cfi 4*8(%rsp) 1801 pushq_cfi -6*8(%rsp)
1794 .endr 1802 .endr
1803 subq $(5*8), %rsp
1795 CFI_DEF_CFA_OFFSET SS+8-RIP 1804 CFI_DEF_CFA_OFFSET SS+8-RIP
1796end_repeat_nmi: 1805end_repeat_nmi:
1797 1806
@@ -1842,8 +1851,12 @@ nmi_swapgs:
1842 SWAPGS_UNSAFE_STACK 1851 SWAPGS_UNSAFE_STACK
1843nmi_restore: 1852nmi_restore:
1844 RESTORE_ALL 8 1853 RESTORE_ALL 8
1854
1855 /* Pop the extra iret frame */
1856 addq $(5*8), %rsp
1857
1845 /* Clear the NMI executing stack variable */ 1858 /* Clear the NMI executing stack variable */
1846 movq $0, 10*8(%rsp) 1859 movq $0, 5*8(%rsp)
1847 jmp irq_return 1860 jmp irq_return
1848 CFI_ENDPROC 1861 CFI_ENDPROC
1849END(nmi) 1862END(nmi)