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