yeahuh / rpms / qemu-kvm

Forked from rpms/qemu-kvm 2 years ago
Clone

Blame SOURCES/kvm-scsi-generic-avoid-possible-out-of-bounds-access-to-.patch

ae23c9
From 63cee29a64ac6a02695a91f7a8f29ac0c17ef3f0 Mon Sep 17 00:00:00 2001
ae23c9
From: Paolo Bonzini <pbonzini@redhat.com>
ae23c9
Date: Tue, 26 Feb 2019 14:44:14 +0000
ae23c9
Subject: [PATCH] scsi-generic: avoid possible out-of-bounds access to r->buf
ae23c9
ae23c9
RH-Author: Paolo Bonzini <pbonzini@redhat.com>
ae23c9
Message-id: <20190226144414.5700-1-pbonzini@redhat.com>
ae23c9
Patchwork-id: 84717
ae23c9
O-Subject: [RHEL8.0 qemu-kvm PATCH] scsi-generic: avoid possible out-of-bounds access to r->buf
ae23c9
Bugzilla: 1668162
ae23c9
RH-Acked-by: Thomas Huth <thuth@redhat.com>
ae23c9
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
ae23c9
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
ae23c9
ae23c9
Bugzilla: 1668162
ae23c9
ae23c9
Brew build: 20372796
ae23c9
ae23c9
Whenever the allocation length of a SCSI request is shorter than the size of the
ae23c9
VPD page list, page_idx is used blindly to index into r->buf.  Even though
ae23c9
the stores in the insertion sort are protected against overflows, the same is not
ae23c9
true of the reads and the final store of 0xb0.
ae23c9
ae23c9
This basically does the same thing as commit 57dbb58d80 ("scsi-generic: avoid
ae23c9
out-of-bounds access to VPD page list", 2018-11-06), except that here the
ae23c9
allocation length can be chosen by the guest.  Note that according to the SCSI
ae23c9
standard, the contents of the PAGE LENGTH field are not altered based
ae23c9
on the allocation length.
ae23c9
ae23c9
The code was introduced by commit 6c219fc8a1 ("scsi-generic: keep VPD
ae23c9
page list sorted", 2018-11-06) but the overflow was already possible before.
ae23c9
ae23c9
Reported-by: Kevin Wolf <kwolf@redhat.com>
ae23c9
Fixes: a71c775b24ebc664129eb1d9b4c360590353efd5
ae23c9
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
ae23c9
(cherry picked from commit e909ff93698851777faac3c45d03c1b73f311ea6)
ae23c9
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
ae23c9
---
ae23c9
 hw/scsi/scsi-generic.c | 18 ++++++++++--------
ae23c9
 1 file changed, 10 insertions(+), 8 deletions(-)
ae23c9
ae23c9
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
ae23c9
index 4ac53e4..e21adf9 100644
ae23c9
--- a/hw/scsi/scsi-generic.c
ae23c9
+++ b/hw/scsi/scsi-generic.c
ae23c9
@@ -183,7 +183,7 @@ static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s)
ae23c9
             /* Also take care of the opt xfer len. */
ae23c9
             stl_be_p(&r->buf[12],
ae23c9
                     MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12])));
ae23c9
-        } else if (s->needs_vpd_bl_emulation && page == 0x00) {
ae23c9
+        } else if (s->needs_vpd_bl_emulation && page == 0x00 && r->buflen >= 4) {
ae23c9
             /*
ae23c9
              * Now we're capable of supplying the VPD Block Limits
ae23c9
              * response if the hardware can't. Add it in the INQUIRY
ae23c9
@@ -194,18 +194,20 @@ static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s)
ae23c9
              * and will use it to proper setup the SCSI device.
ae23c9
              *
ae23c9
              * VPD page numbers must be sorted, so insert 0xb0 at the
ae23c9
-             * right place with an in-place insert.  After the initialization
ae23c9
-             * part of the for loop is executed, the device response is
ae23c9
-             * at r[0] to r[page_idx - 1].
ae23c9
+             * right place with an in-place insert.  When the while loop
ae23c9
+             * begins the device response is at r[0] to r[page_idx - 1].
ae23c9
              */
ae23c9
-            for (page_idx = lduw_be_p(r->buf + 2) + 4;
ae23c9
-                 page_idx > 4 && r->buf[page_idx - 1] >= 0xb0;
ae23c9
-                 page_idx--) {
ae23c9
+            page_idx = lduw_be_p(r->buf + 2) + 4;
ae23c9
+            page_idx = MIN(page_idx, r->buflen);
ae23c9
+            while (page_idx > 4 && r->buf[page_idx - 1] >= 0xb0) {
ae23c9
                 if (page_idx < r->buflen) {
ae23c9
                     r->buf[page_idx] = r->buf[page_idx - 1];
ae23c9
                 }
ae23c9
+                page_idx--;
ae23c9
+            }
ae23c9
+            if (page_idx < r->buflen) {
ae23c9
+                r->buf[page_idx] = 0xb0;
ae23c9
             }
ae23c9
-            r->buf[page_idx] = 0xb0;
ae23c9
             stw_be_p(r->buf + 2, lduw_be_p(r->buf + 2) + 1);
ae23c9
         }
ae23c9
     }
ae23c9
-- 
ae23c9
1.8.3.1
ae23c9