x86/unwind/orc: Fix premature unwind stoppage due to IRET frames
authorJosh Poimboeuf <jpoimboe@redhat.com>
Sat, 25 Apr 2020 10:06:14 +0000 (05:06 -0500)
committerIngo Molnar <mingo@kernel.org>
Sat, 25 Apr 2020 10:22:29 +0000 (12:22 +0200)
commit81b67439d147677d844d492fcbd03712ea438f42
tree90b6cbaac6840c2830068e1979f2919bd7bbb9a5
parenta0f81bf26888048100bf017fadf438a5bdffa8d8
x86/unwind/orc: Fix premature unwind stoppage due to IRET frames

The following execution path is possible:

  fsnotify()
    [ realign the stack and store previous SP in R10 ]
    <IRQ>
      [ only IRET regs saved ]
      common_interrupt()
        interrupt_entry()
  <NMI>
    [ full pt_regs saved ]
    ...
    [ unwind stack ]

When the unwinder goes through the NMI and the IRQ on the stack, and
then sees fsnotify(), it doesn't have access to the value of R10,
because it only has the five IRET registers.  So the unwind stops
prematurely.

However, because the interrupt_entry() code is careful not to clobber
R10 before saving the full regs, the unwinder should be able to read R10
from the previously saved full pt_regs associated with the NMI.

Handle this case properly.  When encountering an IRET regs frame
immediately after a full pt_regs frame, use the pt_regs as a backup
which can be used to get the C register values.

Also, note that a call frame resets the 'prev_regs' value, because a
function is free to clobber the registers.  For this fix to work, the
IRET and full regs frames must be adjacent, with no FUNC frames in
between.  So replace the FUNC hint in interrupt_entry() with an
IRET_REGS hint.

Fixes: ee9f8fce9964 ("x86/unwind: Add the ORC unwinder")
Reviewed-by: Miroslav Benes <mbenes@suse.cz>
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Dave Jones <dsj@fb.com>
Cc: Jann Horn <jannh@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Vince Weaver <vincent.weaver@maine.edu>
Link: https://lore.kernel.org/r/97a408167cc09f1cfa0de31a7b70dd88868d743f.1587808742.git.jpoimboe@redhat.com
arch/x86/entry/entry_64.S
arch/x86/include/asm/unwind.h
arch/x86/kernel/unwind_orc.c