|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH] x86/boot: Make alternative patching NMI-safe
On Mon, Feb 05, 2018 at 10:24:58AM +0000, Andrew Cooper wrote:
> During patching, there is a very slim risk that an NMI or MCE interrupt in the
> middle of altering the code in the NMI/MCE paths, in which case bad things
> will happen.
>
> The NMI risk can be eliminated by running the patching loop in NMI context, at
> which point the CPU will defer further NMIs until patching is complete.
Oh, that is a very simple fix.
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx>
>
> Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
> ---
> CC: Jan Beulich <JBeulich@xxxxxxxx>
> ---
> xen/arch/x86/alternative.c | 61
> +++++++++++++++++++++++++++++++---------------
> 1 file changed, 42 insertions(+), 19 deletions(-)
>
> diff --git a/xen/arch/x86/alternative.c b/xen/arch/x86/alternative.c
> index ee18e6c..521f896 100644
> --- a/xen/arch/x86/alternative.c
> +++ b/xen/arch/x86/alternative.c
> @@ -16,6 +16,7 @@
> */
>
> #include <xen/types.h>
> +#include <asm/apic.h>
> #include <asm/processor.h>
> #include <asm/alternative.h>
> #include <xen/init.h>
> @@ -82,11 +83,6 @@ static const unsigned char * const p6_nops[ASM_NOP_MAX+1]
> init_or_livepatch_cons
>
> static const unsigned char * const *ideal_nops init_or_livepatch_data =
> p6_nops;
>
> -static int __init mask_nmi_callback(const struct cpu_user_regs *regs, int
> cpu)
> -{
> - return 1;
> -}
> -
> static void __init arch_init_ideal_nops(void)
> {
> switch ( boot_cpu_data.x86_vendor )
> @@ -203,24 +199,50 @@ void init_or_livepatch apply_alternatives(const struct
> alt_instr *start,
> }
>
> /*
> + * At boot time, we patch alternatives in NMI context. This means that the
> + * active NMI-shadow will defer any further NMIs, removing the slim race
> + * condition where an NMI hits while we are midway though patching some
> + * instructions in the NMI path.
> + */
> +static int __init nmi_apply_alternatives(const struct cpu_user_regs *regs,
> + int cpu)
> +{
> + static bool __initdata once;
> +
> + /*
> + * More than one NMI may occur between the two set_nmi_callback() below.
> + * We only need to apply alternatives once.
> + */
> + if ( !once )
> + {
> + unsigned long cr0;
> +
> + once = true;
> +
> + cr0 = read_cr0();
> +
> + /* Disable WP to allow patching read-only pages. */
> + write_cr0(cr0 & ~X86_CR0_WP);
> +
> + apply_alternatives(__alt_instructions, __alt_instructions_end);
> +
> + write_cr0(cr0);
> + }
> +
> + return 1;
> +}
> +
> +/*
> * This routine is called with local interrupt disabled and used during
> * bootup.
> */
> void __init alternative_instructions(void)
> {
> nmi_callback_t *saved_nmi_callback;
> - unsigned long cr0 = read_cr0();
>
> arch_init_ideal_nops();
>
> /*
> - * The patching is not fully atomic, so try to avoid local interruptions
> - * that might execute the to be patched code.
> - * Other CPUs are not running.
> - */
> - saved_nmi_callback = set_nmi_callback(mask_nmi_callback);
> -
> - /*
> * Don't stop machine check exceptions while patching.
> * MCEs only happen when something got corrupted and in this
> * case we must do something about the corruption.
> @@ -232,13 +254,14 @@ void __init alternative_instructions(void)
> */
> ASSERT(!local_irq_is_enabled());
>
> - /* Disable WP to allow application of alternatives to read-only pages. */
> - write_cr0(cr0 & ~X86_CR0_WP);
> -
> - apply_alternatives(__alt_instructions, __alt_instructions_end);
> + /*
> + * As soon as the callback is set up, the next NMI will trigger patching,
> + * even an NMI ahead of our explicit self-NMI.
> + */
> + saved_nmi_callback = set_nmi_callback(nmi_apply_alternatives);
>
> - /* Reinstate WP. */
> - write_cr0(cr0);
> + /* Send ourselves an NMI to trigger the callback. */
> + self_nmi();
>
> set_nmi_callback(saved_nmi_callback);
> }
> --
> 2.1.4
>
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@xxxxxxxxxxxxxxxxxxxx
> https://lists.xenproject.org/mailman/listinfo/xen-devel
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |