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

527e2d
From dc4ff14029538f4f2787271b98d6e8e403cbfcc5 Mon Sep 17 00:00:00 2001
527e2d
From: Jon Maloy <jmaloy@redhat.com>
527e2d
Date: Fri, 26 Feb 2021 01:06:42 -0500
527e2d
Subject: [PATCH] ide: atapi: check logical block address and read size
527e2d
 (CVE-2020-29443)
527e2d
527e2d
RH-Author: Jon Maloy <jmaloy@redhat.com>
527e2d
Message-id: <20210226010642.3200257-2-jmaloy@redhat.com>
527e2d
Patchwork-id: 101270
527e2d
O-Subject: [RHEL-7.9.z qemu-kvm PATCH v2 1/1] ide: atapi: check logical block address and read size (CVE-2020-29443)
527e2d
Bugzilla: 1917449
527e2d
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
527e2d
RH-Acked-by: Danilo de Paula <ddepaula@redhat.com>
527e2d
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
527e2d
527e2d
From: Prasad J Pandit <pjp@fedoraproject.org>
527e2d
527e2d
While processing ATAPI cmd_read/cmd_read_cd commands,
527e2d
Logical Block Address (LBA) maybe invalid OR closer to the last block,
527e2d
leading to an OOB access issues. Add range check to avoid it.
527e2d
527e2d
Fixes: CVE-2020-29443
527e2d
Reported-by: Wenxiang Qian <leonwxqian@gmail.com>
527e2d
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
527e2d
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
527e2d
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
527e2d
Message-Id: <20210118115130.457044-1-ppandit@redhat.com>
527e2d
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
527e2d
527e2d
(cherry picked from commit b8d7f1bc59276fec85e4d09f1567613a3e14d31e)
527e2d
Conflict: There is a conflict in cmd_read_cd(), because
527e2d
commit e7bd708ec85e ("atapi: classify read_cd as conditionally
527e2d
returning data") is missing in this code version. That seems to be an
527e2d
unrelated fix that drags in further changes, so instead of applying it
527e2d
we choose to adapt the commit directly to the current code version.
527e2d
Signed-off-by: Jon Maloy <jmaloy@redhat.com>
527e2d
Signed-off-by: Jon Maloy <jmaloy.redhat.com>
527e2d
---
527e2d
 hw/ide/atapi.c | 29 ++++++++++++++++++++++++-----
527e2d
 1 file changed, 24 insertions(+), 5 deletions(-)
527e2d
527e2d
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
527e2d
index 490070a1b4..bef74914d1 100644
527e2d
--- a/hw/ide/atapi.c
527e2d
+++ b/hw/ide/atapi.c
527e2d
@@ -267,6 +267,8 @@ static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size)
527e2d
 static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors,
527e2d
                                    int sector_size)
527e2d
 {
527e2d
+    assert(0 <= lba && lba < (s->nb_sectors >> 2));
527e2d
+
527e2d
     s->lba = lba;
527e2d
     s->packet_transfer_size = nb_sectors * sector_size;
527e2d
     s->elementary_transfer_size = 0;
527e2d
@@ -365,6 +367,8 @@ eot:
527e2d
 static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors,
527e2d
                                    int sector_size)
527e2d
 {
527e2d
+    assert(0 <= lba && lba < (s->nb_sectors >> 2));
527e2d
+
527e2d
     s->lba = lba;
527e2d
     s->packet_transfer_size = nb_sectors * sector_size;
527e2d
     s->io_buffer_index = 0;
527e2d
@@ -823,7 +827,10 @@ static void cmd_prevent_allow_medium_removal(IDEState *s, uint8_t* buf)
527e2d
 
527e2d
 static void cmd_read(IDEState *s, uint8_t* buf)
527e2d
 {
527e2d
-    int nb_sectors, lba;
527e2d
+    unsigned int nb_sectors, lba;
527e2d
+
527e2d
+    /* Total logical sectors of ATAPI_SECTOR_SIZE(=2048) bytes */
527e2d
+    uint64_t total_sectors = s->nb_sectors >> 2;
527e2d
 
527e2d
     if (buf[0] == GPCMD_READ_10) {
527e2d
         nb_sectors = ube16_to_cpu(buf + 7);
527e2d
@@ -831,27 +838,39 @@ static void cmd_read(IDEState *s, uint8_t* buf)
527e2d
         nb_sectors = ube32_to_cpu(buf + 6);
527e2d
     }
527e2d
 
527e2d
-    lba = ube32_to_cpu(buf + 2);
527e2d
     if (nb_sectors == 0) {
527e2d
         ide_atapi_cmd_ok(s);
527e2d
         return;
527e2d
     }
527e2d
 
527e2d
+    lba = ldl_be_p(buf + 2);
527e2d
+    if (lba >= total_sectors || lba + nb_sectors - 1 >= total_sectors) {
527e2d
+        ide_atapi_cmd_error(s, ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR);
527e2d
+        return;
527e2d
+    }
527e2d
+
527e2d
     ide_atapi_cmd_read(s, lba, nb_sectors, 2048);
527e2d
 }
527e2d
 
527e2d
 static void cmd_read_cd(IDEState *s, uint8_t* buf)
527e2d
 {
527e2d
-    int nb_sectors, lba, transfer_request;
527e2d
+    unsigned int nb_sectors, lba, transfer_request;
527e2d
 
527e2d
-    nb_sectors = (buf[6] << 16) | (buf[7] << 8) | buf[8];
527e2d
-    lba = ube32_to_cpu(buf + 2);
527e2d
+    /* Total logical sectors of ATAPI_SECTOR_SIZE(=2048) bytes */
527e2d
+    uint64_t total_sectors = s->nb_sectors >> 2;
527e2d
 
527e2d
+    nb_sectors = (buf[6] << 16) | (buf[7] << 8) | buf[8];
527e2d
     if (nb_sectors == 0) {
527e2d
         ide_atapi_cmd_ok(s);
527e2d
         return;
527e2d
     }
527e2d
 
527e2d
+    lba = ldl_be_p(buf + 2);
527e2d
+    if (lba >= total_sectors || lba + nb_sectors - 1 >= total_sectors) {
527e2d
+        ide_atapi_cmd_error(s, ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR);
527e2d
+        return;
527e2d
+    }
527e2d
+
527e2d
     transfer_request = buf[9];
527e2d
     switch(transfer_request & 0xf8) {
527e2d
     case 0x00:
527e2d
-- 
527e2d
2.18.2
527e2d