* [RFC PATCH 0/3] Make kexec work with CONFIG_DEBUG_RODATA enabled
@ 2014-04-09 16:50 Nikolay Borisov
2014-04-09 16:50 ` [RFC PATCH 1/3] ARM: kexec: Make kexec work with read-only kernel .text section Nikolay Borisov
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Nikolay Borisov @ 2014-04-09 16:50 UTC (permalink / raw)
To: linux-arm-kernel
This patch makes kexec work on a kernel that has its .text section set to read
only. The main reason of doing it is because there is a patch in the making
(http://lists.infradead.org/pipermail/linux-arm-kernel/2014-April/244779.html)
which aims to make it possible to flag the kernel's code section as read-only,
rendering kexec inoperable.
The first patch does the actual functional changes while the 2nd one is
optionail and is only to be used in case you have already applied the aforementioned
CONFIG_DEBUG_RODATA patch
Patch 3 is also optional and tries to make the assembly code a bit more "sane"
by introducing a .struct to describe the parameters for the kernel relocation
stub.
Those patches have been tested on linux 3.14 on THUMB-2/non-THUMB-2 host
kernels.
Nikolay Borisov (3):
ARM: kexec: Make kexec work with read-only kernel .text section
ARM: Kconfig: remove dependence of CONFIG_DEBUG_RODATA on !kexec
ARM: kexec: Use .struct to describe relocate_new_kernel parameter
layout
arch/arm/kernel/machine_kexec.c | 54 ++++++++++++++++++++++++++++-----------
arch/arm/kernel/relocate_kernel.S | 47 +++++++++++++++++-----------------
arch/arm/mm/Kconfig | 2 +-
3 files changed, 63 insertions(+), 40 deletions(-)
--
1.8.1.5
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC PATCH 1/3] ARM: kexec: Make kexec work with read-only kernel .text section
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
2014-04-09 18:13 ` 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 16:50 ` [RFC PATCH 3/3] ARM: kexec: Use .struct to describe relocate_new_kernel parameter layout Nikolay Borisov
2 siblings, 1 reply; 7+ messages in thread
From: Nikolay Borisov @ 2014-04-09 16:50 UTC (permalink / raw)
To: linux-arm-kernel
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
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [RFC PATCH 2/3] ARM: Kconfig: remove dependence of CONFIG_DEBUG_RODATA on !kexec
2014-04-09 16:50 [RFC PATCH 0/3] Make kexec work with CONFIG_DEBUG_RODATA enabled Nikolay Borisov
2014-04-09 16:50 ` [RFC PATCH 1/3] ARM: kexec: Make kexec work with read-only kernel .text section Nikolay Borisov
@ 2014-04-09 16:50 ` 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
2 siblings, 1 reply; 7+ messages in thread
From: Nikolay Borisov @ 2014-04-09 16:50 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Nikolay Borisov <Nikolay.Borisov@arm.com>
---
arch/arm/mm/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 3c7adea..ed58326 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -970,7 +970,7 @@ config ARM_KERNMEM_PERMS
config DEBUG_RODATA
bool "Make kernel text and rodata read-only"
- depends on ARM_KERNMEM_PERMS && KEXEC=n && KPROBES=n
+ depends on ARM_KERNMEM_PERMS && KPROBES=n
default y
help
If this is set, kernel text and rodata will be made read-only.
--
1.8.1.5
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [RFC PATCH 3/3] ARM: kexec: Use .struct to describe relocate_new_kernel parameter layout
2014-04-09 16:50 [RFC PATCH 0/3] Make kexec work with CONFIG_DEBUG_RODATA enabled Nikolay Borisov
2014-04-09 16:50 ` [RFC PATCH 1/3] ARM: kexec: Make kexec work with read-only kernel .text section Nikolay Borisov
2014-04-09 16:50 ` [RFC PATCH 2/3] ARM: Kconfig: remove dependence of CONFIG_DEBUG_RODATA on !kexec Nikolay Borisov
@ 2014-04-09 16:50 ` Nikolay Borisov
2 siblings, 0 replies; 7+ messages in thread
From: Nikolay Borisov @ 2014-04-09 16:50 UTC (permalink / raw)
To: linux-arm-kernel
This removes dependence on assembly-time modification of existing
symbols, by using struct to describe the parameter block layout in
a more natural way.
Signed-off-by: Nikolay Borisov <Nikolay.Borisov@arm.com>
---
arch/arm/kernel/machine_kexec.c | 26 ++++++++++-------------
arch/arm/kernel/relocate_kernel.S | 44 ++++++++++++++++++---------------------
2 files changed, 31 insertions(+), 39 deletions(-)
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
index ee55e2e..7c0e4a2 100644
--- a/arch/arm/kernel/machine_kexec.c
+++ b/arch/arm/kernel/machine_kexec.c
@@ -22,10 +22,10 @@
extern void relocate_new_kernel(void);
extern const unsigned int relocate_new_kernel_size;
-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;
+extern const unsigned long kexec_start_address_offset;
+extern const unsigned long kexec_indirection_page_offset;
+extern const unsigned long kexec_mach_type_offset;
+extern const unsigned long kexec_boot_atags_offset;
static atomic_t waiting_for_crash_ipi;
@@ -153,25 +153,21 @@ void (*kexec_reinit)(void);
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 get_offset(sym) ((uintptr_t)&(sym) + relocate_new_kernel_size)
#define patch_value(offset,res) \
- *(unsigned long *)(copied_template + (offset)) = (res)
+ *(unsigned long *)(copied_template + get_offset(offset)) = (res)
- patch_value(start_addr_offset, image->start);
- patch_value(indir_page_offset, page_list);
- patch_value(mach_type_offset, machine_arch_type);
+ patch_value(kexec_start_address_offset, image->start);
+ patch_value(kexec_indirection_page_offset, page_list);
+ patch_value(kexec_mach_type_offset, machine_arch_type);
if (!dt_mem)
- patch_value(boot_atags_offset, image->start -
+ patch_value(kexec_boot_atags_offset, image->start -
KEXEC_ARM_ZIMAGE_OFFSET +
KEXEC_ARM_ATAGS_OFFSET);
else
- patch_value(boot_atags_offset, dt_mem);
+ patch_value(kexec_boot_atags_offset, dt_mem);
}
void machine_kexec(struct kimage *image)
diff --git a/arch/arm/kernel/relocate_kernel.S b/arch/arm/kernel/relocate_kernel.S
index a8eb0e0..fbb22a7 100644
--- a/arch/arm/kernel/relocate_kernel.S
+++ b/arch/arm/kernel/relocate_kernel.S
@@ -12,8 +12,8 @@
ENTRY(relocate_new_kernel)
- ldr r0,kexec_indirection_page
- ldr r1,kexec_start_address
+ ldr r0,kexec_indirection_page_offset + relocate_new_kernel_size
+ ldr r1,kexec_start_address_offset + relocate_new_kernel_size
/*
* If there is no indirection page (we are doing crashdumps)
@@ -60,36 +60,32 @@ ENTRY(relocate_new_kernel)
/* Jump to relocated kernel */
mov lr,r1
mov r0,#0
- ldr r1,kexec_mach_type
- ldr r2,kexec_boot_atags
+ ldr r1,kexec_mach_type_offset + relocate_new_kernel_size
+ ldr r2,kexec_boot_atags_offset + relocate_new_kernel_size
ARM( mov pc, lr )
THUMB( bx lr )
- .align
-
- .globl kexec_start_address
-kexec_start_address:
- .long 0x0
-
- .globl kexec_indirection_page
-kexec_indirection_page:
- .long 0x0
-
- .globl kexec_mach_type
-kexec_mach_type:
- .long 0x0
-
- /* phy addr of the atags for the new kernel */
- .globl kexec_boot_atags
-kexec_boot_atags:
- .long 0x0
ENDPROC(relocate_new_kernel)
-relocate_new_kernel_end:
+
.globl relocate_new_kernel_size
relocate_new_kernel_size:
- .long relocate_new_kernel_end - relocate_new_kernel
+ .long . - relocate_new_kernel
+
+ .align
+
+ .struct 4 /* offsets are from relocate_new_kernel_size */
+
+ .macro parameter name /* declare space for a word-sized parameter */
+ .globl \name
+ \name: .long 0
+ .endm
+
+parameter kexec_start_address_offset
+parameter kexec_indirection_page_offset
+parameter kexec_mach_type_offset
+parameter kexec_boot_atags_offset
--
1.8.1.5
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [RFC PATCH 1/3] ARM: kexec: Make kexec work with read-only kernel .text section
2014-04-09 16:50 ` [RFC PATCH 1/3] ARM: kexec: Make kexec work with read-only kernel .text section Nikolay Borisov
@ 2014-04-09 18:13 ` Kees Cook
2014-04-22 0:16 ` Kees Cook
0 siblings, 1 reply; 7+ messages in thread
From: Kees Cook @ 2014-04-09 18:13 UTC (permalink / raw)
To: linux-arm-kernel
On Wed, Apr 9, 2014 at 9:50 AM, Nikolay Borisov <Nikolay.Borisov@arm.com> wrote:
> 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>
Thanks for working on this!
Reviewed-by: Kees Cook <keescook@chromium.org>
-Kees
> ---
> 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
>
>
--
Kees Cook
Chrome OS Security
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC PATCH 2/3] ARM: Kconfig: remove dependence of CONFIG_DEBUG_RODATA on !kexec
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
0 siblings, 0 replies; 7+ messages in thread
From: Kees Cook @ 2014-04-09 18:14 UTC (permalink / raw)
To: linux-arm-kernel
On Wed, Apr 9, 2014 at 9:50 AM, Nikolay Borisov <Nikolay.Borisov@arm.com> wrote:
>
> Signed-off-by: Nikolay Borisov <Nikolay.Borisov@arm.com>
> ---
> arch/arm/mm/Kconfig | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
> index 3c7adea..ed58326 100644
> --- a/arch/arm/mm/Kconfig
> +++ b/arch/arm/mm/Kconfig
> @@ -970,7 +970,7 @@ config ARM_KERNMEM_PERMS
>
> config DEBUG_RODATA
> bool "Make kernel text and rodata read-only"
> - depends on ARM_KERNMEM_PERMS && KEXEC=n && KPROBES=n
> + depends on ARM_KERNMEM_PERMS && KPROBES=n
> default y
> help
> If this is set, kernel text and rodata will be made read-only.
> --
> 1.8.1.5
>
>
Thanks!
Acked-by: Kees Cook <keescook@chromium.org>
--
Kees Cook
Chrome OS Security
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC PATCH 1/3] ARM: kexec: Make kexec work with read-only kernel .text section
2014-04-09 18:13 ` Kees Cook
@ 2014-04-22 0:16 ` Kees Cook
0 siblings, 0 replies; 7+ messages in thread
From: Kees Cook @ 2014-04-22 0:16 UTC (permalink / raw)
To: linux-arm-kernel
On Wed, Apr 9, 2014 at 11:13 AM, Kees Cook <keescook@chromium.org> wrote:
> On Wed, Apr 9, 2014 at 9:50 AM, Nikolay Borisov <Nikolay.Borisov@arm.com> wrote:
>> 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>
>
> Thanks for working on this!
>
> Reviewed-by: Kees Cook <keescook@chromium.org>
...and now that I've actually got a kexec setup working, I've tested this too.
Tested-by: Kees Cook <keescook@chromium.org>
Thanks!
-Kees
>
> -Kees
>
>> ---
>> 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
>>
>>
>
>
>
> --
> Kees Cook
> Chrome OS Security
--
Kees Cook
Chrome OS Security
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2014-04-22 0:16 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-04-09 16:50 [RFC PATCH 0/3] Make kexec work with CONFIG_DEBUG_RODATA enabled Nikolay Borisov
2014-04-09 16:50 ` [RFC PATCH 1/3] ARM: kexec: Make kexec work with read-only kernel .text section Nikolay Borisov
2014-04-09 18:13 ` 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
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).