@samitouri / QOSamiQemu / commits / 8cbcf75793

hw/net/xilinx_axienet: Don't write checksums off end of packet

The xilinx_axienet device has ethernet checksum offloading, with a mode where the guest provides the offsets within the packet where the data to be checksummed starts, and where the final checksum should be written into the packet. We don't sanity check the TX_CSINSERT offset before writing the checksum data into it, which means the guest can pass us a value that is larger than the packet itself and cause us to write the checksum off the end of the buffer. We also don't explicitly check the TX_CSBEGIN offset; this doesn't currently cause any problems because we will pass a negative length to net_checksum_add() which does nothing, but it's a potential trap for the future if the type used for the length gets changed to be unsigned. Explicitly check the offsets. The datasheet doesn't say what happens if the guest misprograms this, so we choose to log an error and send the packet as-is. Cc: qemu-stable@nongnu.org Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3599 Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260706162704.787495-1-peter.maydell@linaro.org> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>

Peter Maydell committed Jul 6, 2026 at 17:27 UTC 8cbcf7579355f995340aa27ad197ef61c4969c06
1 file changed +18 -11
hw/net/xilinx_axienet.c
+18 -11
@@ -922,20 +922,27 @@ xilinx_axienet_data_stream_push(StreamSink *obj, uint8_t *buf, size_t size,
922 if (s->hdr[0] & 1) {
923 unsigned int start_off = s->hdr[1] >> 16;
924 unsigned int write_off = s->hdr[1] & 0xffff;
925 - uint32_t tmp_csum;
926 - uint16_t csum;
925
928 - tmp_csum = net_checksum_add(s->txpos - start_off,
929 - buf + start_off);
930 - /* Accumulate the seed. */
931 - tmp_csum += s->hdr[2] & 0xffff;
926 + if (start_off > s->txpos || write_off + 2 > s->txpos) {
927 + qemu_log_mask(LOG_GUEST_ERROR,
928 + "%s: offsets outside packet, skipping checksum\n",
929 + TYPE_XILINX_AXI_ENET);
930 + } else {
931 + uint32_t tmp_csum;
932 + uint16_t csum;
933 +
934 + tmp_csum = net_checksum_add(s->txpos - start_off,
935 + buf + start_off);
936 + /* Accumulate the seed. */
937 + tmp_csum += s->hdr[2] & 0xffff;
938
933 - /* Fold the 32bit partial checksum. */
934 - csum = net_checksum_finish(tmp_csum);
939 + /* Fold the 32bit partial checksum. */
940 + csum = net_checksum_finish(tmp_csum);
941
936 - /* Writeback. */
937 - buf[write_off] = csum >> 8;
938 - buf[write_off + 1] = csum & 0xff;
942 + /* Writeback. */
943 + buf[write_off] = csum >> 8;
944 + buf[write_off + 1] = csum & 0xff;
945 + }
946 }
947
948 qemu_send_packet(qemu_get_queue(s->nic), buf, s->txpos);