On 10/28/24 05:18, Andrew Cooper wrote:
Both are used to pass information from early_microcode_load() to
microcode_init_cache(), and both constitute use-after-free's in certain cases.

  * ucode_mod is a copy of the module_t identified by `ucode=$n`.  Except it's
    a copy from prior to Xen relocating the modules.  microcode_init_cache()
    might happen to find the data still intact in it's old location, but it
    might be an arbitrary part of some other module.

  * ucode_blob is a stashed pointer to a bootstrap_map() which becomes invalid
    the moment control returns to __start_xen(), where other logic is free to
    to make temporary mappings.  This was even noticed and
    microcode_init_cache() adjusted to "fix" the stashed pointers.

The information which should be passed between these two functions is which
module to look in.  Introduce early_mod_idx for this purpose.  opt_scan can be
reused to distinguish between CPIO archives and raw containers.

Notably this means microcode_init_cache() doesn't need to scan all modules any
more; we know exactly which one to look in.  However, we do re-parse the CPIO
header for simplicity.

Furthermore, microcode_init_cache(), being a presmp_initcall does not need to
use bootstrap_map() to access modules; it can use mfn_to_virt() directly,
which avoids needing to funnel exit paths through bootstrap_unmap().

Fold microcode_scan_module() into what is now it's single caller.  It operates
on the function-wide idx/data/size state which allows for a unified "found"
path irrespective of module selection method.

This resolves all issues to do with holding pointers (physical or virtual)
across returning to __start_xen().

Signed-off-by: Andrew Cooper <[email protected]>
---
CC: Jan Beulich <[email protected]>
CC: Roger Pau MonnĂ© <[email protected]>
CC: Daniel P. Smith <[email protected]>
---

Reviewed-by: Daniel P. Smith <[email protected]>

Reply via email to