1be5c7
From fe4abbda80eea7f65b6b5cc544a806fb6e064917 Mon Sep 17 00:00:00 2001
1be5c7
From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= <philmd@redhat.com>
1be5c7
Date: Thu, 18 Nov 2021 12:57:32 +0100
1be5c7
Subject: [PATCH 2/3] hw/block/fdc: Prevent end-of-track overrun
1be5c7
 (CVE-2021-3507)
1be5c7
MIME-Version: 1.0
1be5c7
Content-Type: text/plain; charset=UTF-8
1be5c7
Content-Transfer-Encoding: 8bit
1be5c7
1be5c7
RH-Author: Jon Maloy <jmaloy@redhat.com>
1be5c7
RH-MergeRequest: 194: hw/block/fdc: Prevent end-of-track overrun (CVE-2021-3507)
1be5c7
RH-Commit: [1/2] 31fa0351382b4ca5bd989b09e4d811ae73040673 (jmaloy/qemu-kvm)
1be5c7
RH-Bugzilla: 1951521
1be5c7
RH-Acked-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
1be5c7
RH-Acked-by: Thomas Huth <thuth@redhat.com>
1be5c7
RH-Acked-by: Hanna Reitz <hreitz@redhat.com>
1be5c7
1be5c7
Per the 82078 datasheet, if the end-of-track (EOT byte in
1be5c7
the FIFO) is more than the number of sectors per side, the
1be5c7
command is terminated unsuccessfully:
1be5c7
1be5c7
* 5.2.5 DATA TRANSFER TERMINATION
1be5c7
1be5c7
  The 82078 supports terminal count explicitly through
1be5c7
  the TC pin and implicitly through the underrun/over-
1be5c7
  run and end-of-track (EOT) functions. For full sector
1be5c7
  transfers, the EOT parameter can define the last
1be5c7
  sector to be transferred in a single or multisector
1be5c7
  transfer. If the last sector to be transferred is a par-
1be5c7
  tial sector, the host can stop transferring the data in
1be5c7
  mid-sector, and the 82078 will continue to complete
1be5c7
  the sector as if a hardware TC was received. The
1be5c7
  only difference between these implicit functions and
1be5c7
  TC is that they return "abnormal termination" result
1be5c7
  status. Such status indications can be ignored if they
1be5c7
  were expected.
1be5c7
1be5c7
* 6.1.3 READ TRACK
1be5c7
1be5c7
  This command terminates when the EOT specified
1be5c7
  number of sectors have been read. If the 82078
1be5c7
  does not find an I D Address Mark on the diskette
1be5c7
  after the second· occurrence of a pulse on the
1be5c7
  INDX# pin, then it sets the IC code in Status Regis-
1be5c7
  ter 0 to "01" (Abnormal termination), sets the MA bit
1be5c7
  in Status Register 1 to "1", and terminates the com-
1be5c7
  mand.
1be5c7
1be5c7
* 6.1.6 VERIFY
1be5c7
1be5c7
  Refer to Table 6-6 and Table 6-7 for information
1be5c7
  concerning the values of MT and EC versus SC and
1be5c7
  EOT value.
1be5c7
1be5c7
* Table 6·6. Result Phase Table
1be5c7
1be5c7
* Table 6-7. Verify Command Result Phase Table
1be5c7
1be5c7
Fix by aborting the transfer when EOT > # Sectors Per Side.
1be5c7
1be5c7
Cc: qemu-stable@nongnu.org
1be5c7
Cc: Hervé Poussineau <hpoussin@reactos.org>
1be5c7
Fixes: baca51faff0 ("floppy driver: disk geometry auto detect")
1be5c7
Reported-by: Alexander Bulekov <alxndr@bu.edu>
1be5c7
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/339
1be5c7
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
1be5c7
Message-Id: <20211118115733.4038610-2-philmd@redhat.com>
1be5c7
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
1be5c7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1be5c7
(cherry picked from commit defac5e2fbddf8423a354ff0454283a2115e1367)
1be5c7
Signed-off-by: Jon Maloy <jmaloy@redhat.com>
1be5c7
---
1be5c7
 hw/block/fdc.c | 8 ++++++++
1be5c7
 1 file changed, 8 insertions(+)
1be5c7
1be5c7
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
1be5c7
index 97fa6de423..755a26c114 100644
1be5c7
--- a/hw/block/fdc.c
1be5c7
+++ b/hw/block/fdc.c
1be5c7
@@ -1531,6 +1531,14 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
1be5c7
         int tmp;
1be5c7
         fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]);
1be5c7
         tmp = (fdctrl->fifo[6] - ks + 1);
1be5c7
+        if (tmp < 0) {
1be5c7
+            FLOPPY_DPRINTF("invalid EOT: %d\n", tmp);
1be5c7
+            fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA, 0x00);
1be5c7
+            fdctrl->fifo[3] = kt;
1be5c7
+            fdctrl->fifo[4] = kh;
1be5c7
+            fdctrl->fifo[5] = ks;
1be5c7
+            return;
1be5c7
+        }
1be5c7
         if (fdctrl->fifo[0] & 0x80)
1be5c7
             tmp += fdctrl->fifo[6];
1be5c7
         fdctrl->data_len *= tmp;
1be5c7
-- 
1be5c7
2.35.3
1be5c7