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

7711c0
From afb03b05279fbb6e405ca1815e419f8ec3650a2c Mon Sep 17 00:00:00 2001
7711c0
From: John Snow <jsnow@redhat.com>
7711c0
Date: Wed, 6 Feb 2019 18:42:16 +0100
7711c0
Subject: [PATCH 10/33] scsi-generic: avoid possible out-of-bounds access to
7711c0
 r->buf
7711c0
7711c0
RH-Author: John Snow <jsnow@redhat.com>
7711c0
Message-id: <20190206184216.15861-2-jsnow@redhat.com>
7711c0
Patchwork-id: 84258
7711c0
O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/1] scsi-generic: avoid possible out-of-bounds access to r->buf
7711c0
Bugzilla: 1668999
7711c0
CVE: CVE-2019-6501/20190111
7711c0
RH-Acked-by: Max Reitz <mreitz@redhat.com>
7711c0
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
7711c0
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
7711c0
7711c0
From: Paolo Bonzini <pbonzini@redhat.com>
7711c0
7711c0
Whenever the allocation length of a SCSI request is shorter than the size of the
7711c0
VPD page list, page_idx is used blindly to index into r->buf.  Even though
7711c0
the stores in the insertion sort are protected against overflows, the same is not
7711c0
true of the reads and the final store of 0xb0.
7711c0
7711c0
This basically does the same thing as commit 57dbb58d80 ("scsi-generic: avoid
7711c0
out-of-bounds access to VPD page list", 2018-11-06), except that here the
7711c0
allocation length can be chosen by the guest.  Note that according to the SCSI
7711c0
standard, the contents of the PAGE LENGTH field are not altered based
7711c0
on the allocation length.
7711c0
7711c0
The code was introduced by commit 6c219fc8a1 ("scsi-generic: keep VPD
7711c0
page list sorted", 2018-11-06) but the overflow was already possible before.
7711c0
7711c0
Reported-by: Kevin Wolf <kwolf@redhat.com>
7711c0
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
7711c0
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
7711c0
Message-id: 20190111164506.15971-1-pbonzini@redhat.com
7711c0
Fixes: a71c775b24ebc664129eb1d9b4c360590353efd5
7711c0
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
7711c0
Signed-off-by: John Snow <jsnow@redhat.com>
7711c0
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
7711c0
---
7711c0
 hw/scsi/scsi-generic.c | 18 ++++++++++--------
7711c0
 1 file changed, 10 insertions(+), 8 deletions(-)
7711c0
7711c0
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
7711c0
index 4ac53e4..e21adf9 100644
7711c0
--- a/hw/scsi/scsi-generic.c
7711c0
+++ b/hw/scsi/scsi-generic.c
7711c0
@@ -183,7 +183,7 @@ static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s)
7711c0
             /* Also take care of the opt xfer len. */
7711c0
             stl_be_p(&r->buf[12],
7711c0
                     MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12])));
7711c0
-        } else if (s->needs_vpd_bl_emulation && page == 0x00) {
7711c0
+        } else if (s->needs_vpd_bl_emulation && page == 0x00 && r->buflen >= 4) {
7711c0
             /*
7711c0
              * Now we're capable of supplying the VPD Block Limits
7711c0
              * response if the hardware can't. Add it in the INQUIRY
7711c0
@@ -194,18 +194,20 @@ static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s)
7711c0
              * and will use it to proper setup the SCSI device.
7711c0
              *
7711c0
              * VPD page numbers must be sorted, so insert 0xb0 at the
7711c0
-             * right place with an in-place insert.  After the initialization
7711c0
-             * part of the for loop is executed, the device response is
7711c0
-             * at r[0] to r[page_idx - 1].
7711c0
+             * right place with an in-place insert.  When the while loop
7711c0
+             * begins the device response is at r[0] to r[page_idx - 1].
7711c0
              */
7711c0
-            for (page_idx = lduw_be_p(r->buf + 2) + 4;
7711c0
-                 page_idx > 4 && r->buf[page_idx - 1] >= 0xb0;
7711c0
-                 page_idx--) {
7711c0
+            page_idx = lduw_be_p(r->buf + 2) + 4;
7711c0
+            page_idx = MIN(page_idx, r->buflen);
7711c0
+            while (page_idx > 4 && r->buf[page_idx - 1] >= 0xb0) {
7711c0
                 if (page_idx < r->buflen) {
7711c0
                     r->buf[page_idx] = r->buf[page_idx - 1];
7711c0
                 }
7711c0
+                page_idx--;
7711c0
+            }
7711c0
+            if (page_idx < r->buflen) {
7711c0
+                r->buf[page_idx] = 0xb0;
7711c0
             }
7711c0
-            r->buf[page_idx] = 0xb0;
7711c0
             stw_be_p(r->buf + 2, lduw_be_p(r->buf + 2) + 1);
7711c0
         }
7711c0
     }
7711c0
-- 
7711c0
1.8.3.1
7711c0