Blame SOURCES/kvm-ide-atapi-check-logical-block-address-and-read-size-.patch

a19a21
From 0453588f95294ed5ce912cb8b810a322bf9d91e0 Mon Sep 17 00:00:00 2001
a19a21
From: Jon Maloy <jmaloy@redhat.com>
a19a21
Date: Thu, 25 Feb 2021 19:43:02 -0500
a19a21
Subject: [PATCH] ide: atapi: check logical block address and read size
a19a21
 (CVE-2020-29443)
a19a21
MIME-Version: 1.0
a19a21
Content-Type: text/plain; charset=UTF-8
a19a21
Content-Transfer-Encoding: 8bit
a19a21
a19a21
RH-Author: Jon Maloy <jmaloy@redhat.com>
a19a21
Message-id: <20210225194302.3137699-2-jmaloy@redhat.com>
a19a21
Patchwork-id: 101208
a19a21
O-Subject: [RHEL-8.4.0 qemu-kvm PATCH v2 1/1] ide: atapi: check logical block address and read size (CVE-2020-29443)
a19a21
Bugzilla: 1917451
a19a21
RH-Acked-by: Philippe Mathieu-Daudé <philmd@redhat.com>
a19a21
RH-Acked-by: Danilo de Paula <ddepaula@redhat.com>
a19a21
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
a19a21
a19a21
From: Prasad J Pandit <pjp@fedoraproject.org>
a19a21
a19a21
While processing ATAPI cmd_read/cmd_read_cd commands,
a19a21
Logical Block Address (LBA) maybe invalid OR closer to the last block,
a19a21
leading to an OOB access issues. Add range check to avoid it.
a19a21
a19a21
Fixes: CVE-2020-29443
a19a21
Reported-by: Wenxiang Qian <leonwxqian@gmail.com>
a19a21
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
a19a21
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
a19a21
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
a19a21
Message-Id: <20210118115130.457044-1-ppandit@redhat.com>
a19a21
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
a19a21
a19a21
(cherry picked from commit b8d7f1bc59276fec85e4d09f1567613a3e14d31e)
a19a21
Signed-off-by: Jon Maloy <jmaloy@redhat.com>
a19a21
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
a19a21
---
a19a21
 hw/ide/atapi.c | 30 ++++++++++++++++++++++++------
a19a21
 1 file changed, 24 insertions(+), 6 deletions(-)
a19a21
a19a21
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
a19a21
index 17a9d635d8..d064935c8d 100644
a19a21
--- a/hw/ide/atapi.c
a19a21
+++ b/hw/ide/atapi.c
a19a21
@@ -320,6 +320,8 @@ static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size)
a19a21
 static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors,
a19a21
                                    int sector_size)
a19a21
 {
a19a21
+    assert(0 <= lba && lba < (s->nb_sectors >> 2));
a19a21
+
a19a21
     s->lba = lba;
a19a21
     s->packet_transfer_size = nb_sectors * sector_size;
a19a21
     s->elementary_transfer_size = 0;
a19a21
@@ -418,6 +420,8 @@ eot:
a19a21
 static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors,
a19a21
                                    int sector_size)
a19a21
 {
a19a21
+    assert(0 <= lba && lba < (s->nb_sectors >> 2));
a19a21
+
a19a21
     s->lba = lba;
a19a21
     s->packet_transfer_size = nb_sectors * sector_size;
a19a21
     s->io_buffer_size = 0;
a19a21
@@ -971,35 +975,49 @@ static void cmd_prevent_allow_medium_removal(IDEState *s, uint8_t* buf)
a19a21
 
a19a21
 static void cmd_read(IDEState *s, uint8_t* buf)
a19a21
 {
a19a21
-    int nb_sectors, lba;
a19a21
+    unsigned int nb_sectors, lba;
a19a21
+
a19a21
+    /* Total logical sectors of ATAPI_SECTOR_SIZE(=2048) bytes */
a19a21
+    uint64_t total_sectors = s->nb_sectors >> 2;
a19a21
 
a19a21
     if (buf[0] == GPCMD_READ_10) {
a19a21
         nb_sectors = lduw_be_p(buf + 7);
a19a21
     } else {
a19a21
         nb_sectors = ldl_be_p(buf + 6);
a19a21
     }
a19a21
-
a19a21
-    lba = ldl_be_p(buf + 2);
a19a21
     if (nb_sectors == 0) {
a19a21
         ide_atapi_cmd_ok(s);
a19a21
         return;
a19a21
     }
a19a21
 
a19a21
+    lba = ldl_be_p(buf + 2);
a19a21
+    if (lba >= total_sectors || lba + nb_sectors - 1 >= total_sectors) {
a19a21
+        ide_atapi_cmd_error(s, ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR);
a19a21
+        return;
a19a21
+    }
a19a21
+
a19a21
     ide_atapi_cmd_read(s, lba, nb_sectors, 2048);
a19a21
 }
a19a21
 
a19a21
 static void cmd_read_cd(IDEState *s, uint8_t* buf)
a19a21
 {
a19a21
-    int nb_sectors, lba, transfer_request;
a19a21
+    unsigned int nb_sectors, lba, transfer_request;
a19a21
 
a19a21
-    nb_sectors = (buf[6] << 16) | (buf[7] << 8) | buf[8];
a19a21
-    lba = ldl_be_p(buf + 2);
a19a21
+    /* Total logical sectors of ATAPI_SECTOR_SIZE(=2048) bytes */
a19a21
+    uint64_t total_sectors = s->nb_sectors >> 2;
a19a21
 
a19a21
+    nb_sectors = (buf[6] << 16) | (buf[7] << 8) | buf[8];
a19a21
     if (nb_sectors == 0) {
a19a21
         ide_atapi_cmd_ok(s);
a19a21
         return;
a19a21
     }
a19a21
 
a19a21
+    lba = ldl_be_p(buf + 2);
a19a21
+    if (lba >= total_sectors || lba + nb_sectors - 1 >= total_sectors) {
a19a21
+        ide_atapi_cmd_error(s, ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR);
a19a21
+        return;
a19a21
+    }
a19a21
+
a19a21
     transfer_request = buf[9] & 0xf8;
a19a21
     if (transfer_request == 0x00) {
a19a21
         /* nothing */
a19a21
-- 
a19a21
2.27.0
a19a21