On 2026/07/21 20:11, Laurent Vivier wrote:
rx_desc_len is migrated as a raw uint8_t from the stream, but it
is a derived value that can be computed from the register state in
core.mac[RCTL]. A crafted migration stream can set rx_desc_len to
an invalid value (e.g. 64), causing a stack buffer overflow in
e1000e_write_packet_to_guest() which copies rx_desc_len bytes into
a 32-byte stack union.

Recalculate rx_desc_len from the register state in post_load,
ignoring the untrusted value from the stream.

Cc: [email protected]
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3869
Signed-off-by: Laurent Vivier <[email protected]>
---
  hw/net/e1000e_core.c | 2 ++
  1 file changed, 2 insertions(+)

diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c
index 46e156a5ddc2..31eb39e4aa40 100644
--- a/hw/net/e1000e_core.c
+++ b/hw/net/e1000e_core.c
@@ -3557,5 +3557,7 @@ e1000e_core_post_load(E1000ECore *core)
      e1000e_intrmgr_resume(core);
      e1000e_autoneg_resume(core);
+ e1000e_calc_rxdesclen(core);

e1000e_set_rx_control()
e1000e has similar derived values in rxbuf_min_shift, rxbuf_sizes[], and rx_desc_buf_size, and e1000e_set_rx_control() computes it in sequence:

    e1000e_parse_rxbufsize(core);
    e1000e_calc_rxdesclen(core);
    core->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1 +
                                E1000_RING_DESC_LEN_SHIFT;

I suggest creating a function to replicate this sequence for e1000e_core_post_load() instead of only calling e1000e_calc_rxdesclen().

Regards,
Akihiko Odaki

+
      return 0;
  }


Reply via email to