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

Peter Maydell posted 1 patch 3 days, 12 hours ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20260226175549.1319476-1-peter.maydell@linaro.org
Maintainers: Jason Wang <jasowang@redhat.com>
hw/net/smc91c111.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
[PATCH] hw/net/smc91c111: Don't allow negative-length packets
Posted by Peter Maydell 3 days, 12 hours ago
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>
---
 hw/net/smc91c111.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

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++;
-- 
2.43.0
Re: [PATCH] hw/net/smc91c111: Don't allow negative-length packets
Posted by Philippe Mathieu-Daudé 3 days, 9 hours ago
On 26/2/26 18:55, Peter Maydell wrote:
> 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>
> ---
>   hw/net/smc91c111.c | 16 ++++++++++++++--
>   1 file changed, 14 insertions(+), 2 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>