Commit d8e19f8042 for qemu.org

commit d8e19f8042dcaff8e077292209c8196acb150bdd
Author: Peter Maydell <peter.maydell@linaro.org>
Date:   Fri Mar 6 09:01:12 2026 +0000

    hw/net/smc91c111: Don't allow negative-length packets

    The smc91c111 data frame format in memory (figure 8-1 in the
    datasheet) includes a "byte count" field which is intended to be the
    total size of the data frame, including not just the packet data but
    also the leading and trailing information like the status word and
    the byte count field itself.  It is therefore possible for the guest
    to set this to a value so small that the leading and trailing fields
    won't fit and the packet has effectively a negative area.

    We weren't checking for this, with the result that when we subtract 6
    from the length to get the length of the packet proper we end up with
    a negative length, which is then inconsistently handled in the
    qemu_send_packet() code such that we can try to transmit a very large
    amount of data and read off the end of the device's data array.

    Treat excessively small length values the same way we do excessively
    large values.  As with the oversized case, the datasheet does not
    describe what happens for this software error case, and there is no
    relevant tx error condition for this, so we just log and drop the
    packet.

    Cc: qemu-stable@nongnu.org
    Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3304
    Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
    Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
    Message-id: 20260226175549.1319476-1-peter.maydell@linaro.org

diff --git a/hw/net/smc91c111.c b/hw/net/smc91c111.c
index 3420d8e28e..3b526524fb 100644
--- a/hw/net/smc91c111.c
+++ b/hw/net/smc91c111.c
@@ -30,6 +30,12 @@
  * LAN91C111 datasheet).
  */
 #define MAX_PACKET_SIZE 2048
+/*
+ * Size of the non-data fields in a data frame: status word,
+ * byte count, control byte, and last data byte; this defines
+ * the smallest value the byte count in the frame can validly be.
+ */
+#define MIN_PACKET_SIZE 6

 #define TYPE_SMC91C111 "smc91c111"
 OBJECT_DECLARE_SIMPLE_TYPE(smc91c111_state, SMC91C111)
@@ -289,7 +295,7 @@ static void smc91c111_do_tx(smc91c111_state *s)
         *(p++) = 0x40;
         len = *(p++);
         len |= ((int)*(p++)) << 8;
-        if (len > MAX_PACKET_SIZE) {
+        if (len < MIN_PACKET_SIZE || len > MAX_PACKET_SIZE) {
             /*
              * Datasheet doesn't say what to do here, and there is no
              * relevant tx error condition listed. Log, and drop the packet.
@@ -300,7 +306,13 @@ static void smc91c111_do_tx(smc91c111_state *s)
             smc91c111_complete_tx_packet(s, packetnum);
             continue;
         }
-        len -= 6;
+        /*
+         * Convert from size of the data frame to number of bytes of
+         * actual packet data. Whether the "last data byte" field is
+         * included in the packet depends on the ODD bit in the control
+         * byte at the end of the frame.
+         */
+        len -= MIN_PACKET_SIZE;
         control = p[len + 1];
         if (control & 0x20)
             len++;