From: Fangyu Yu <[email protected]>

machine_kexec_prepare() calls set_memory_x() on the per-image
control_code_page so the relocate stub copied into it can be executed
during a normal kexec. machine_kexec_cleanup() is empty, so when the
image is freed (via kexec -u, or because a later step in load failed)
the page is returned to the buddy allocator with its executable bit
still set. Once the page is reallocated for arbitrary kernel data,
the W^X invariant is broken: a writable page also marked executable.

Implement the architecture cleanup hook to call set_memory_nx() on
the control code page for non-crash images, mirroring the
set_memory_x() in prepare().

The crash path does not call set_memory_x() (the crash kernel is
loaded into the reserved crashkernel region whose pages are not in
the buddy allocator) and so does not need the cleanup.

Fixes: fba8a8674f68 ("RISC-V: Add kexec support")
Signed-off-by: Fangyu Yu <[email protected]>
---
 arch/riscv/kernel/machine_kexec.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/arch/riscv/kernel/machine_kexec.c 
b/arch/riscv/kernel/machine_kexec.c
index 2306ce3e5f22..ea6794c9f4c2 100644
--- a/arch/riscv/kernel/machine_kexec.c
+++ b/arch/riscv/kernel/machine_kexec.c
@@ -91,6 +91,19 @@ machine_kexec_prepare(struct kimage *image)
 void
 machine_kexec_cleanup(struct kimage *image)
 {
+       void *control_code_buffer;
+
+       if (image->type == KEXEC_TYPE_CRASH || !image->control_code_page)
+               return;
+
+       /*
+        * machine_kexec_prepare() called set_memory_x() on the control
+        * code page for non-crash images. Revert it before kimage_free()
+        * returns the page to the buddy allocator, so we do not leak an
+        * executable page back into general allocation.
+        */
+       control_code_buffer = page_address(image->control_code_page);
+       set_memory_nx((unsigned long)control_code_buffer, 1);
 }
 
 
-- 
2.50.1


Reply via email to