diff mbox series

[02/10] x86/ucode: Delete the microcode_init() initcall

Message ID 20241028091856.2151603-3-andrew.cooper3@citrix.com (mailing list archive)
State New
Headers show
Series x86/ucode: Fix module-handling use-aftere-free's | expand

Commit Message

Andrew Cooper Oct. 28, 2024, 9:18 a.m. UTC
The comment highlights just how bogus this really is.  Being an initcall, the
boot allocator is long gone, and bootstrap_unmap() is a no-op.

The fact there is nothing to do should be a giant red flag about the validity
of the mappings "being freed".  Indeed, they both constitute use-after-frees.

We could move the size/data/end clobbering into microcode_init_cache() which
is the final consumer of the information, but we're intending to delete these
static variables entirely, and it's less churn to just leave them dangling for
a few patches.

No functional change.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
CC: Jan Beulich <JBeulich@suse.com>
CC: Roger Pau Monné <roger.pau@citrix.com>
CC: Daniel P. Smith <dpsmith@apertussolutions.com>

After the $N'th rearranging, this could actually be merged into "x86/ucode:
Drop ucode_mod and ucode_blob" with no effect on the intermediate patches.
---
 xen/arch/x86/cpu/microcode/core.c | 22 ----------------------
 1 file changed, 22 deletions(-)

Comments

Jan Beulich Oct. 28, 2024, 1:38 p.m. UTC | #1
On 28.10.2024 10:18, Andrew Cooper wrote:
> The comment highlights just how bogus this really is.  Being an initcall, the
> boot allocator is long gone, and bootstrap_unmap() is a no-op.

How's the boot allocator coming into the picture here? This is all about
(un)mapping, not allocating.

> The fact there is nothing to do should be a giant red flag about the validity
> of the mappings "being freed".  Indeed, they both constitute use-after-frees.

I can't spot any use-after-free; the pointers in question ...

> --- a/xen/arch/x86/cpu/microcode/core.c
> +++ b/xen/arch/x86/cpu/microcode/core.c
> @@ -758,28 +758,6 @@ int microcode_update(XEN_GUEST_HANDLE(const_void) buf,
>      return continue_hypercall_on_cpu(0, microcode_update_helper, buffer);
>  }
>  
> -static int __init cf_check microcode_init(void)
> -{
> -    /*
> -     * At this point, all CPUs should have updated their microcode
> -     * via the early_microcode_* paths so free the microcode blob.
> -     */
> -    if ( ucode_blob.size )
> -    {
> -        bootstrap_unmap();
> -        ucode_blob.size = 0;
> -        ucode_blob.data = NULL;
> -    }
> -    else if ( ucode_mod.mod_end )
> -    {
> -        bootstrap_unmap();
> -        ucode_mod.mod_end = 0;
> -    }
> -
> -    return 0;
> -}
> -__initcall(microcode_init);

... aren't used anywhere. bootstrap_unmap() is "just in case" (perhaps indeed
a no-op at least nowadays), and the rest is field clobbering. I'm okay with the
code change, so
Acked-by: Jan Beulich <jbeulich@suse.com>
yet I'd like to ask for the description to be "softened" some.

Jan
Andrew Cooper Oct. 28, 2024, 5:12 p.m. UTC | #2
On 28/10/2024 1:38 pm, Jan Beulich wrote:
> On 28.10.2024 10:18, Andrew Cooper wrote:
>> The comment highlights just how bogus this really is.  Being an initcall, the
>> boot allocator is long gone, and bootstrap_unmap() is a no-op.
> How's the boot allocator coming into the picture here? This is all about
> (un)mapping, not allocating.
>
>> The fact there is nothing to do should be a giant red flag about the validity
>> of the mappings "being freed".  Indeed, they both constitute use-after-frees.
> I can't spot any use-after-free; the pointers in question ...
>
>> --- a/xen/arch/x86/cpu/microcode/core.c
>> +++ b/xen/arch/x86/cpu/microcode/core.c
>> @@ -758,28 +758,6 @@ int microcode_update(XEN_GUEST_HANDLE(const_void) buf,
>>      return continue_hypercall_on_cpu(0, microcode_update_helper, buffer);
>>  }
>>  
>> -static int __init cf_check microcode_init(void)
>> -{
>> -    /*
>> -     * At this point, all CPUs should have updated their microcode
>> -     * via the early_microcode_* paths so free the microcode blob.
>> -     */
>> -    if ( ucode_blob.size )
>> -    {
>> -        bootstrap_unmap();
>> -        ucode_blob.size = 0;
>> -        ucode_blob.data = NULL;
>> -    }
>> -    else if ( ucode_mod.mod_end )
>> -    {
>> -        bootstrap_unmap();
>> -        ucode_mod.mod_end = 0;
>> -    }
>> -
>> -    return 0;
>> -}
>> -__initcall(microcode_init);
> ... aren't used anywhere. bootstrap_unmap() is "just in case" (perhaps indeed
> a no-op at least nowadays), and the rest is field clobbering. I'm okay with the
> code change, so
> Acked-by: Jan Beulich <jbeulich@suse.com>
> yet I'd like to ask for the description to be "softened" some.

As I said, this could be folded into patch 9, given this particular
arrangement of the series.

The UAFs are apparent *because* the comment demonstrates a false line of
reasoning.

ucode_mod literally is used after free.  ucode=$n is genuinely buggy
today, because its a stash of a physical pointer across move_xen().

ucode_blob stashes a virtual pointer.  This was even noticed in
dc380df12acf ("x86/ucode: load microcode earlier on boot CPU")

---
It needs to rescan the modules in order to find the new virtual address
of the ucode blob because it changes during the boot process, e.g.
from 0x00000000010802fc to 0xffff83204dac52fc.
---

which highlighted the problem but duct-taped over it.

~Andrew
Jan Beulich Oct. 29, 2024, 7:48 a.m. UTC | #3
On 28.10.2024 18:12, Andrew Cooper wrote:
> On 28/10/2024 1:38 pm, Jan Beulich wrote:
>> On 28.10.2024 10:18, Andrew Cooper wrote:
>>> The comment highlights just how bogus this really is.  Being an initcall, the
>>> boot allocator is long gone, and bootstrap_unmap() is a no-op.
>> How's the boot allocator coming into the picture here? This is all about
>> (un)mapping, not allocating.
>>
>>> The fact there is nothing to do should be a giant red flag about the validity
>>> of the mappings "being freed".  Indeed, they both constitute use-after-frees.
>> I can't spot any use-after-free; the pointers in question ...
>>
>>> --- a/xen/arch/x86/cpu/microcode/core.c
>>> +++ b/xen/arch/x86/cpu/microcode/core.c
>>> @@ -758,28 +758,6 @@ int microcode_update(XEN_GUEST_HANDLE(const_void) buf,
>>>      return continue_hypercall_on_cpu(0, microcode_update_helper, buffer);
>>>  }
>>>  
>>> -static int __init cf_check microcode_init(void)
>>> -{
>>> -    /*
>>> -     * At this point, all CPUs should have updated their microcode
>>> -     * via the early_microcode_* paths so free the microcode blob.
>>> -     */
>>> -    if ( ucode_blob.size )
>>> -    {
>>> -        bootstrap_unmap();
>>> -        ucode_blob.size = 0;
>>> -        ucode_blob.data = NULL;
>>> -    }
>>> -    else if ( ucode_mod.mod_end )
>>> -    {
>>> -        bootstrap_unmap();
>>> -        ucode_mod.mod_end = 0;
>>> -    }
>>> -
>>> -    return 0;
>>> -}
>>> -__initcall(microcode_init);
>> ... aren't used anywhere. bootstrap_unmap() is "just in case" (perhaps indeed
>> a no-op at least nowadays), and the rest is field clobbering. I'm okay with the
>> code change, so
>> Acked-by: Jan Beulich <jbeulich@suse.com>
>> yet I'd like to ask for the description to be "softened" some.
> 
> As I said, this could be folded into patch 9, given this particular
> arrangement of the series.

I certainly don't mind the folding, but then I'd still like to see the
description of the resulting patch before giving a (hopefully) unconditional
ack.

> The UAFs are apparent *because* the comment demonstrates a false line of
> reasoning.
> 
> ucode_mod literally is used after free.  ucode=$n is genuinely buggy
> today, because its a stash of a physical pointer across move_xen().

Maybe my problem is that the UAF is elsewhere, not in the code you delete?
If so, it might help to simply point out where the actual bad use is. As it
stands, microcode_init() doesn't have any uses (reads), only writes. What I
agree with is that the comment there is at best misleading.

Jan

> ucode_blob stashes a virtual pointer.  This was even noticed in
> dc380df12acf ("x86/ucode: load microcode earlier on boot CPU")
> 
> ---
> It needs to rescan the modules in order to find the new virtual address
> of the ucode blob because it changes during the boot process, e.g.
> from 0x00000000010802fc to 0xffff83204dac52fc.
> ---
> 
> which highlighted the problem but duct-taped over it.
> 
> ~Andrew
diff mbox series

Patch

diff --git a/xen/arch/x86/cpu/microcode/core.c b/xen/arch/x86/cpu/microcode/core.c
index 9a2cc631d2aa..3e815f1880af 100644
--- a/xen/arch/x86/cpu/microcode/core.c
+++ b/xen/arch/x86/cpu/microcode/core.c
@@ -758,28 +758,6 @@  int microcode_update(XEN_GUEST_HANDLE(const_void) buf,
     return continue_hypercall_on_cpu(0, microcode_update_helper, buffer);
 }
 
-static int __init cf_check microcode_init(void)
-{
-    /*
-     * At this point, all CPUs should have updated their microcode
-     * via the early_microcode_* paths so free the microcode blob.
-     */
-    if ( ucode_blob.size )
-    {
-        bootstrap_unmap();
-        ucode_blob.size = 0;
-        ucode_blob.data = NULL;
-    }
-    else if ( ucode_mod.mod_end )
-    {
-        bootstrap_unmap();
-        ucode_mod.mod_end = 0;
-    }
-
-    return 0;
-}
-__initcall(microcode_init);
-
 /* Load a cached update to current cpu */
 int microcode_update_one(void)
 {