@samitouri / QOSamiQemu / commits / d8e19f8042

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

Peter Maydell committed Mar 6, 2026 at 09:01 UTC d8e19f8042dcaff8e077292209c8196acb150bdd
1 file changed +14 -2
hw/net/smc91c111.c
+14 -2
@@ -30,6 +30,12 @@
30 * LAN91C111 datasheet).
31 */
32 #define MAX_PACKET_SIZE 2048
33 +/*
34 + * Size of the non-data fields in a data frame: status word,
35 + * byte count, control byte, and last data byte; this defines
36 + * the smallest value the byte count in the frame can validly be.
37 + */
38 +#define MIN_PACKET_SIZE 6
39
40 #define TYPE_SMC91C111 "smc91c111"
41 OBJECT_DECLARE_SIMPLE_TYPE(smc91c111_state, SMC91C111)
@@ -289,7 +295,7 @@ static void smc91c111_do_tx(smc91c111_state *s)
295 *(p++) = 0x40;
296 len = *(p++);
297 len |= ((int)*(p++)) << 8;
292 - if (len > MAX_PACKET_SIZE) {
298 + if (len < MIN_PACKET_SIZE || len > MAX_PACKET_SIZE) {
299 /*
300 * Datasheet doesn't say what to do here, and there is no
301 * relevant tx error condition listed. Log, and drop the packet.
@@ -300,7 +306,13 @@ static void smc91c111_do_tx(smc91c111_state *s)
306 smc91c111_complete_tx_packet(s, packetnum);
307 continue;
308 }
303 - len -= 6;
309 + /*
310 + * Convert from size of the data frame to number of bytes of
311 + * actual packet data. Whether the "last data byte" field is
312 + * included in the packet depends on the ODD bit in the control
313 + * byte at the end of the frame.
314 + */
315 + len -= MIN_PACKET_SIZE;
316 control = p[len + 1];
317 if (control & 0x20)
318 len++;