linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: Nikolay.Borisov@arm.com (Nikolay Borisov)
To: linux-arm-kernel@lists.infradead.org
Subject: [RFC PATCH 1/3] ARM: kexec: Make kexec work with read-only kernel .text section
Date: Wed,  9 Apr 2014 17:50:36 +0100	[thread overview]
Message-ID: <1397062238-10515-2-git-send-email-Nikolay.Borisov@arm.com> (raw)
In-Reply-To: <1397062238-10515-1-git-send-email-Nikolay.Borisov@arm.com>

Currently, as part of preparing the machine to boot a new kernel, Arm's kexec
backend will patch some memory location which are allocated in the kernel's
.text section. This will work only if the aforementioned section is not set
to read-only, otherwise an OOPS will be produced  and kexec won't work.

This patch modifies the way those memory location are being patched by first
copying them from the .text section (the template) to a special buffer and
then patching the values in the already-copied buffer, thus obviating the
need to touch the kernel's code section.

Finally, given the fact that code now works irrespective whether the kexec stub
is RO or not just move it to .rodata

Signed-off-by: Nikolay Borisov <Nikolay.Borisov@arm.com>
---
 arch/arm/kernel/machine_kexec.c   | 58 +++++++++++++++++++++++++++++----------
 arch/arm/kernel/relocate_kernel.S |  3 ++
 2 files changed, 46 insertions(+), 15 deletions(-)

diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
index f0d180d..ee55e2e 100644
--- a/arch/arm/kernel/machine_kexec.c
+++ b/arch/arm/kernel/machine_kexec.c
@@ -22,13 +22,15 @@
 extern void relocate_new_kernel(void);
 extern const unsigned int relocate_new_kernel_size;
 
-extern unsigned long kexec_start_address;
-extern unsigned long kexec_indirection_page;
-extern unsigned long kexec_mach_type;
-extern unsigned long kexec_boot_atags;
+extern const unsigned long kexec_start_address;
+extern const unsigned long kexec_indirection_page;
+extern const unsigned long kexec_mach_type;
+extern const unsigned long kexec_boot_atags;
 
 static atomic_t waiting_for_crash_ipi;
 
+static unsigned long dt_mem;
+
 /*
  * Provide a dummy crash_notes definition while crash dump arrives to arm.
  * This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
@@ -63,8 +65,13 @@ int machine_kexec_prepare(struct kimage *image)
 		if (err)
 			return err;
 
+		/*
+		 * We used to write directly to kexec_atag_boots
+		 * this is forbidden when .text section is RO, cache it
+		 * in a static var instead
+		 */
 		if (be32_to_cpu(header) == OF_DT_HEADER)
-			kexec_boot_atags = current_segment->mem;
+			dt_mem = current_segment->mem;
 	}
 	return 0;
 }
@@ -139,9 +146,36 @@ void machine_crash_shutdown(struct pt_regs *regs)
  */
 void (*kexec_reinit)(void);
 
+/*
+ * Instead of patching the kernel .text (which might be Read-only by
+ * CONFIG_DEBUG_RODATA), patch the already-copied template.
+ */
+static void patch_boot_parameters(char *copied_template, struct kimage *image) {
+
+	unsigned long page_list = image->head & PAGE_MASK;
+	uintptr_t base = (uintptr_t)relocate_new_kernel & ~(uintptr_t)1;
+	uintptr_t start_addr_offset = (uintptr_t)&kexec_start_address - base;
+	uintptr_t indir_page_offset = (uintptr_t)&kexec_indirection_page - base;
+	uintptr_t mach_type_offset = (uintptr_t)&kexec_mach_type - base;
+	uintptr_t boot_atags_offset = (uintptr_t)&kexec_boot_atags - base;
+
+#define patch_value(offset,res) \
+	*(unsigned long *)(copied_template + (offset)) = (res)
+
+	patch_value(start_addr_offset, image->start);
+	patch_value(indir_page_offset, page_list);
+	patch_value(mach_type_offset, machine_arch_type);
+
+	if (!dt_mem)
+		patch_value(boot_atags_offset, image->start -
+				 KEXEC_ARM_ZIMAGE_OFFSET +
+				 KEXEC_ARM_ATAGS_OFFSET);
+	else
+		patch_value(boot_atags_offset, dt_mem);
+}
+
 void machine_kexec(struct kimage *image)
 {
-	unsigned long page_list;
 	unsigned long reboot_code_buffer_phys;
 	unsigned long reboot_entry = (unsigned long)relocate_new_kernel;
 	unsigned long reboot_entry_phys;
@@ -155,21 +189,12 @@ void machine_kexec(struct kimage *image)
 	 */
 	BUG_ON(num_online_cpus() > 1);
 
-	page_list = image->head & PAGE_MASK;
 
 	/* we need both effective and real address here */
 	reboot_code_buffer_phys =
 	    page_to_pfn(image->control_code_page) << PAGE_SHIFT;
 	reboot_code_buffer = page_address(image->control_code_page);
 
-	/* Prepare parameters for reboot_code_buffer*/
-	kexec_start_address = image->start;
-	kexec_indirection_page = page_list;
-	kexec_mach_type = machine_arch_type;
-	if (!kexec_boot_atags)
-		kexec_boot_atags = image->start - KEXEC_ARM_ZIMAGE_OFFSET + KEXEC_ARM_ATAGS_OFFSET;
-
-
 	/* copy our kernel relocation code to the control code page */
 	reboot_entry = fncpy(reboot_code_buffer,
 			     reboot_entry,
@@ -177,6 +202,9 @@ void machine_kexec(struct kimage *image)
 	reboot_entry_phys = (unsigned long)reboot_entry +
 		(reboot_code_buffer_phys - (unsigned long)reboot_code_buffer);
 
+	/* Prepare parameters for reboot_code_buffer*/
+	patch_boot_parameters(reboot_code_buffer, image);
+
 	printk(KERN_INFO "Bye!\n");
 
 	if (kexec_reinit)
diff --git a/arch/arm/kernel/relocate_kernel.S b/arch/arm/kernel/relocate_kernel.S
index 9585896..a8eb0e0 100644
--- a/arch/arm/kernel/relocate_kernel.S
+++ b/arch/arm/kernel/relocate_kernel.S
@@ -5,6 +5,9 @@
 #include <linux/linkage.h>
 #include <asm/kexec.h>
 
+/* Exectution of this template in place is a bug: make it non-executable: */
+	.section .rodata, "a"
+
 	.align	3	/* not needed for this code, but keeps fncpy() happy */
 
 ENTRY(relocate_new_kernel)
-- 
1.8.1.5

  reply	other threads:[~2014-04-09 16:50 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-04-09 16:50 [RFC PATCH 0/3] Make kexec work with CONFIG_DEBUG_RODATA enabled Nikolay Borisov
2014-04-09 16:50 ` Nikolay Borisov [this message]
2014-04-09 18:13   ` [RFC PATCH 1/3] ARM: kexec: Make kexec work with read-only kernel .text section Kees Cook
2014-04-22  0:16     ` Kees Cook
2014-04-09 16:50 ` [RFC PATCH 2/3] ARM: Kconfig: remove dependence of CONFIG_DEBUG_RODATA on !kexec Nikolay Borisov
2014-04-09 18:14   ` Kees Cook
2014-04-09 16:50 ` [RFC PATCH 3/3] ARM: kexec: Use .struct to describe relocate_new_kernel parameter layout Nikolay Borisov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1397062238-10515-2-git-send-email-Nikolay.Borisov@arm.com \
    --to=nikolay.borisov@arm.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).