Skip to content

Commit 4ce827b

Browse files
jpoimboerafaeljw
authored andcommitted
x86/power/64: Fix hibernation return address corruption
In kernel bug 150021, a kernel panic was reported when restoring a hibernate image. Only a picture of the oops was reported, so I can't paste the whole thing here. But here are the most interesting parts: kernel tried to execute NX-protected page - exploit attempt? (uid: 0) BUG: unable to handle kernel paging request at ffff8804615cfd78 ... RIP: ffff8804615cfd78 RSP: ffff8804615f0000 RBP: ffff8804615cfdc0 ... Call Trace: do_signal+0x23 exit_to_usermode_loop+0x64 ... The RIP is on the same page as RBP, so it apparently started executing on the stack. The bug was bisected to commit ef0f3ed (x86/asm/power: Create stack frames in hibernate_asm_64.S), which in retrospect seems quite dangerous, since that code saves and restores the stack pointer from a global variable ('saved_context'). There are a lot of moving parts in the hibernate save and restore paths, so I don't know exactly what caused the panic. Presumably, a FRAME_END was executed without the corresponding FRAME_BEGIN, or vice versa. That would corrupt the return address on the stack and would be consistent with the details of the above panic. [ rjw: One major problem is that by the time the FRAME_BEGIN in restore_registers() is executed, the stack pointer value may not be valid any more. Namely, the stack area pointed to by it previously may have been overwritten by some image memory contents and that page frame may now be used for whatever different purpose it had been allocated for before hibernation. In that case, the FRAME_BEGIN will corrupt that memory. ] Instead of doing the frame pointer save/restore around the bounds of the affected functions, just do it around the call to swsusp_save(). That has the same effect of ensuring that if swsusp_save() sleeps, the frame pointers will be correct. It's also a much more obviously safe way to do it than the original patch. And objtool still doesn't report any warnings. Fixes: ef0f3ed (x86/asm/power: Create stack frames in hibernate_asm_64.S) Link: https://bugzilla.kernel.org/show_bug.cgi?id=150021 Cc: 4.6+ <stable@vger.kernel.org> # 4.6+ Reported-by: Andre Reinke <andre.reinke@mailbox.org> Tested-by: Andre Reinke <andre.reinke@mailbox.org> Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Acked-by: Ingo Molnar <mingo@kernel.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent fe12c00 commit 4ce827b

File tree

1 file changed

+1
-3
lines changed

1 file changed

+1
-3
lines changed

arch/x86/power/hibernate_asm_64.S

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
#include <asm/frame.h>
2525

2626
ENTRY(swsusp_arch_suspend)
27-
FRAME_BEGIN
2827
movq $saved_context, %rax
2928
movq %rsp, pt_regs_sp(%rax)
3029
movq %rbp, pt_regs_bp(%rax)
@@ -48,6 +47,7 @@ ENTRY(swsusp_arch_suspend)
4847
movq %cr3, %rax
4948
movq %rax, restore_cr3(%rip)
5049

50+
FRAME_BEGIN
5151
call swsusp_save
5252
FRAME_END
5353
ret
@@ -104,7 +104,6 @@ ENTRY(core_restore_code)
104104
/* code below belongs to the image kernel */
105105
.align PAGE_SIZE
106106
ENTRY(restore_registers)
107-
FRAME_BEGIN
108107
/* go back to the original page tables */
109108
movq %r9, %cr3
110109

@@ -145,6 +144,5 @@ ENTRY(restore_registers)
145144
/* tell the hibernation core that we've just restored the memory */
146145
movq %rax, in_suspend(%rip)
147146

148-
FRAME_END
149147
ret
150148
ENDPROC(restore_registers)

0 commit comments

Comments
 (0)