2022-09-23 01:36:47

by Daniel Verkamp

[permalink] [raw]
Subject: [PATCH] x86: also disable FSRM if ERMS is disabled

In the "Fast Short REP MOVSB" path of memmove, if we take the path where
the FSRM flag is enabled but the ERMS flag is not, there is no longer a
check for length >= 0x20 (both alternatives will be replaced with NOPs).
If a memmove() requiring a forward copy of less than 0x20 bytes happens
in this case, the `sub $0x20, %rdx` will cause the length to roll around
to a huge value and the copy will eventually hit a page fault.

This is not intended to happen, as the comment above the alternatives
mentions "FSRM implies ERMS".

However, there is a check in early_init_intel() that can disable ERMS,
so we should also be disabling FSRM in this path to maintain correctness
of the memmove() optimization.

Cc: [email protected]
Fixes: f444a5ff95dc ("x86/cpufeatures: Add support for fast short REP; MOVSB")
Signed-off-by: Daniel Verkamp <[email protected]>
---
arch/x86/kernel/cpu/intel.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index 2d7ea5480ec3..71b412f820c7 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -328,6 +328,7 @@ static void early_init_intel(struct cpuinfo_x86 *c)
pr_info("Disabled fast string operations\n");
setup_clear_cpu_cap(X86_FEATURE_REP_GOOD);
setup_clear_cpu_cap(X86_FEATURE_ERMS);
+ setup_clear_cpu_cap(X86_FEATURE_FSRM);
}
}

--
2.37.3.998.g577e59143f-goog


2022-09-23 11:22:58

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH] x86: also disable FSRM if ERMS is disabled

On Thu, Sep 22, 2022 at 05:58:27PM -0700, Daniel Verkamp wrote:
> In the "Fast Short REP MOVSB" path of memmove, if we take the path where
> the FSRM flag is enabled but the ERMS flag is not, there is no longer a
> check for length >= 0x20 (both alternatives will be replaced with NOPs).
> If a memmove() requiring a forward copy of less than 0x20 bytes happens
> in this case, the `sub $0x20, %rdx` will cause the length to roll around
> to a huge value and the copy will eventually hit a page fault.
>
> This is not intended to happen, as the comment above the alternatives
> mentions "FSRM implies ERMS".
>
> However, there is a check in early_init_intel() that can disable ERMS,
> so we should also be disabling FSRM in this path to maintain correctness
> of the memmove() optimization.

Is this something you hit in a real-world scenario? If so, how exactly?

Thx.

--
Regards/Gruss,
Boris.

https://people.kernel.org/tglx/notes-about-netiquette

2022-09-23 17:59:59

by Daniel Verkamp

[permalink] [raw]
Subject: Re: [PATCH] x86: also disable FSRM if ERMS is disabled

On Fri, Sep 23, 2022 at 4:13 AM Borislav Petkov <[email protected]> wrote:
>
> On Thu, Sep 22, 2022 at 05:58:27PM -0700, Daniel Verkamp wrote:
> > In the "Fast Short REP MOVSB" path of memmove, if we take the path where
> > the FSRM flag is enabled but the ERMS flag is not, there is no longer a
> > check for length >= 0x20 (both alternatives will be replaced with NOPs).
> > If a memmove() requiring a forward copy of less than 0x20 bytes happens
> > in this case, the `sub $0x20, %rdx` will cause the length to roll around
> > to a huge value and the copy will eventually hit a page fault.
> >
> > This is not intended to happen, as the comment above the alternatives
> > mentions "FSRM implies ERMS".
> >
> > However, there is a check in early_init_intel() that can disable ERMS,
> > so we should also be disabling FSRM in this path to maintain correctness
> > of the memmove() optimization.
>
> Is this something you hit in a real-world scenario? If so, how exactly?
>
> Thx.

Yes, we hit this in crosvm when booting the guest kernel with either
OVMF or u-boot on an Intel 12th Gen CPU. The guest kernel boots fine
when loaded directly (using the crosvm kernel loader and not running
any firmware setup in the guest), but it crashes when booting with
firmware inside the first forward memmove() after alternatives are set
up (which happens to be in printk). I haven't gotten to the bottom of
why exactly using firmware is causing this to be set up in an
inconsistent way, but this is a real-world situation, not just a
hypothetical.

Now that I look at it with fresh eyes again, maybe we should instead
directly patch the memmove FSRM alternative so that the flag-set
version just does the same jmp as the ERMS one. I can prepare a patch
for that instead of (or in addition to) this one if that sounds
better.

Thanks,
-- Daniel

2022-09-23 18:01:25

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH] x86: also disable FSRM if ERMS is disabled

On Fri, Sep 23, 2022 at 10:25:05AM -0700, Daniel Verkamp wrote:
> Yes, we hit this in crosvm when booting the guest kernel with either
> OVMF or u-boot on an Intel 12th Gen CPU. The guest kernel boots fine
> when loaded directly (using the crosvm kernel loader and not running
> any firmware setup in the guest), but it crashes when booting with
> firmware inside the first forward memmove() after alternatives are set
> up (which happens to be in printk). I haven't gotten to the bottom of
> why exactly using firmware is causing this to be set up in an
> inconsistent way, but this is a real-world situation, not just a
> hypothetical.

Sounds like broken virt firmware or so. And if that is not an issue on
baremetal, then the virt stack should be fixed - not the kernel.

> Now that I look at it with fresh eyes again, maybe we should instead
> directly patch the memmove FSRM alternative so that the flag-set
> version just does the same jmp as the ERMS one. I can prepare a patch
> for that instead of (or in addition to) this one if that sounds
> better.

So, if the virt firmware deviates from how the real hardware behaves,
then the kernel needs no fixing.

So you'd have to figure out why is the virt firmware causing this and
not baremetal.

Then we can talk about fixes.

Thx.

--
Regards/Gruss,
Boris.

https://people.kernel.org/tglx/notes-about-netiquette