Re: [PATCH] x86/intel/quark: Parameterize the kernel's IMR lock logic

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



* Bryan O'Donoghue <pure.logic@xxxxxxxxxxxxxxxxx> wrote:

> Currently when setting up an IMR around the kernel's .text area we lock
> that IMR, preventing further modification. While superficially this appears
> to be the right thing to do, in fact this doesn't account for a legitimate
> change in the memory map such as when executing a new kernel via kexec.
> 
> In such a scenario a second kernel can have a different size and location
> to it's predecessor and can view some of the memory occupied by it's
> predecessor as legitimately usable DMA RAM. If this RAM were then
> subsequently allocated to DMA agents within the system it could conceivably
> trigger an IMR violation.
> 
> This patch fixes the this potential situation by keeping the kernel's .text
> section IMR lock bit false by default, thus ensuring that a user of the
> system will have kexec just work without having to pass special parameters
> on the kernel command line to influence the state of the kernel's IMR. If a
> user so desires then it is possible to explicitly set the lock bit to true.
> 
> The new parameter is kernel_imr and this may be set to kernel_imr=locked or
> kernel_imr=unlocked.
> 
> Signed-off-by: Bryan O'Donoghue <pure.logic@xxxxxxxxxxxxxxxxx>
> Reported-by: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx>
> ---
>  Documentation/kernel-parameters.txt |  7 +++++++
>  arch/x86/platform/intel-quark/imr.c | 39 +++++++++++++++++++++++++++++++------
>  2 files changed, 40 insertions(+), 6 deletions(-)
> 
> diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
> index 9a53c92..1aad1d2 100644
> --- a/Documentation/kernel-parameters.txt
> +++ b/Documentation/kernel-parameters.txt
> @@ -1359,6 +1359,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
>  			        hardware thread id mappings.
>  				Format: <cpu>:<hwthread>
>  
> +	kernel_imr=	[X86, INTEL_IMR] Control the lock bit for the Isolated
> +			Memory Region protecting the kernel's .text section on
> +			X86 architectures that support IMRs such as Quark X1000.
> +			When an IMR lock bit is set it is not possible to unset
> +			it without a CPU reset.
> +			Format : {locked | unlocked (default) }
> +
>  	keep_bootcon	[KNL]
>  			Do not unregister boot console at start. This is only
>  			useful for debugging when something happens in the window
> diff --git a/arch/x86/platform/intel-quark/imr.c b/arch/x86/platform/intel-quark/imr.c
> index c61b6c3..8249f65 100644
> --- a/arch/x86/platform/intel-quark/imr.c
> +++ b/arch/x86/platform/intel-quark/imr.c
> @@ -37,6 +37,7 @@
>  struct imr_device {
>  	struct dentry	*file;
>  	bool		init;
> +	bool		kernel_imr_locked;
>  	struct mutex	lock;
>  	int		max_imr;
>  	int		reg_base;
> @@ -568,10 +569,15 @@ static inline int imr_clear(int reg)
>   * BIOS and Grub both setup IMRs around compressed kernel, initrd memory
>   * that need to be removed before the kernel hands out one of the IMR
>   * encased addresses to a downstream DMA agent such as the SD or Ethernet.
> + * Additionally if the current kernel is executing via kexec then we need to
> + * tear down the IMR the previous kernel had setup.
> + *
>   * IMRs on Galileo are setup to immediately reset the system on violation.
>   * As a result if you're running a root filesystem from SD - you'll need
>   * the boot-time IMRs torn down or you'll find seemingly random resets when
> - * using your filesystem.
> + * using your filesystem; similarly if you're doing a kexec boot of Linux then
> + * its required to sanitize the memory map with-respect to the previous IMR
> + * settings.
>   *
>   * @idev:	pointer to imr_device structure.
>   * @return:
> @@ -592,14 +598,20 @@ static void __init imr_fixup_memmap(struct imr_device *idev)
>  	end = (unsigned long)__end_rodata - 1;
>  
>  	/*
> -	 * Setup a locked IMR around the physical extent of the kernel
> -	 * from the beginning of the .text secton to the end of the
> -	 * .rodata section as one physically contiguous block.
> +	 * Setup an IMR around the physical extent of the kernel from the
> +	 * beginning of the .text section to the end of the .rodata section
> +	 * as one physically contiguous block.
>  	 *
>  	 * We don't round up @size since it is already PAGE_SIZE aligned.
>  	 * See vmlinux.lds.S for details.
> +	 *
> +	 * By default this IMR is unlocked to enable subsequent kernels booted
> +	 * by kexec to tear down the IMR we are setting up below. Its possible
> +	 * to set this IMR to the locked state by passing kernel_imr=locked on
> +	 * the kernel command line.
>  	 */
> -	ret = imr_add_range(base, size, IMR_CPU, IMR_CPU, true);
> +	ret = imr_add_range(base, size, IMR_CPU, IMR_CPU,
> +			    imr_dev.kernel_imr_locked);
>  	if (ret < 0) {
>  		pr_err("unable to setup IMR for kernel: %zu KiB (%lx - %lx)\n",
>  			size / 1024, start, end);
> @@ -617,8 +629,23 @@ static const struct x86_cpu_id imr_ids[] __initconst = {
>  MODULE_DEVICE_TABLE(x86cpu, imr_ids);
>  
>  /**
> - * imr_init - entry point for IMR driver.
> + * imr_kernel_lock_setup - control the lock bit of the kernel's IMR
>   *
> + */
> +static int __init imr_kernel_lock_setup(char *str)
> +{
> +	if (!strcmp(str, "unlocked"))
> +		imr_dev.kernel_imr_locked = false;
> +	else if (!strcmp(str, "locked"))
> +		imr_dev.kernel_imr_locked = true;
> +	else
> +		return 0;
> +	return 1;
> +}
> +__setup("kernel_imr=", imr_kernel_lock_setup);
> +
> +/**
> + * imr_init - entry point for IMR driver.
>   * return: -ENODEV for no IMR support 0 if good to go.
>   */
>  static int __init imr_init(void)
> -- 
> 2.5.0

So why not simply do the patch below? Very few people use boot parameters, and the 
complexity does not seem to be worth it.

Furthermore I think an IMR range in itself is safe enough - it's not like such 
register state is going to be randomly corrupted, even with the 'lock' bit unset. 
So it's a perfectly fine protective measure against accidental memory corruption 
from the DMA space. It should not try to be more than that.

And once we do this, I suggest we get rid of the 'lock' parameter altogether - 
that will further simplify the code.

Thanks,

	Ingo

===============>

 arch/x86/platform/intel-quark/imr.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/platform/intel-quark/imr.c b/arch/x86/platform/intel-quark/imr.c
index 0a3736f03edc..f7c4f523910f 100644
--- a/arch/x86/platform/intel-quark/imr.c
+++ b/arch/x86/platform/intel-quark/imr.c
@@ -587,7 +587,7 @@ static void __init imr_fixup_memmap(struct imr_device *idev)
 	 * We don't round up @size since it is already PAGE_SIZE aligned.
 	 * See vmlinux.lds.S for details.
 	 */
-	ret = imr_add_range(base, size, IMR_CPU, IMR_CPU, true);
+	ret = imr_add_range(base, size, IMR_CPU, IMR_CPU, false);
 	if (ret < 0) {
 		pr_err("unable to setup IMR for kernel: %zu KiB (%lx - %lx)\n",
 			size / 1024, start, end);
--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux