qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Anthony Liguori <anthony@codemonkey.ws>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [6475] check SCSI read/write requests against max LBA (Rik van Riel)
Date: Thu, 29 Jan 2009 19:59:04 +0000	[thread overview]
Message-ID: <E1LSd2W-0005Sa-KA@cvs.savannah.gnu.org> (raw)

Revision: 6475
          http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=6475
Author:   aliguori
Date:     2009-01-29 19:59:04 +0000 (Thu, 29 Jan 2009)

Log Message:
-----------
check SCSI read/write requests against max LBA (Rik van Riel)

The bdrv layer uses a signed offset. Furthermore, block-raw-posix
only seeks when that offset is positive. Passing a negative offset
to block-raw-posix can result in data being written at the current
seek cursor's position.

It may be possible to exploit this to seek to the end of the disk
and extend the virtual disk by writing data to a negative sector
offset.  After a reboot, this could lead to the guest having a
larger disk than it had before.

Close the hole by sanity checking the lba against the size of the
disk.

Signed-off-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>

Modified Paths:
--------------
    trunk/hw/scsi-disk.c

Modified: trunk/hw/scsi-disk.c
===================================================================
--- trunk/hw/scsi-disk.c	2009-01-29 19:45:28 UTC (rev 6474)
+++ trunk/hw/scsi-disk.c	2009-01-29 19:59:04 UTC (rev 6475)
@@ -67,6 +67,7 @@
     /* The qemu block layer uses a fixed 512 byte sector size.
        This is the number of 512 byte blocks in a single scsi sector.  */
     int cluster_size;
+    uint64_t max_lba;
     int sense;
     int tcq;
     /* Completion functions may be called from either scsi_{read,write}_data
@@ -738,6 +739,8 @@
         /* Returned value is the address of the last sector.  */
         if (nb_sectors) {
             nb_sectors--;
+            /* Remember the new size for read/write sanity checking. */
+            s->max_lba = nb_sectors;
             /* Clip to 2TB, instead of returning capacity modulo 2TB. */
             if (nb_sectors > UINT32_MAX)
                 nb_sectors = UINT32_MAX;
@@ -759,6 +762,8 @@
     case 0x28:
     case 0x88:
         DPRINTF("Read (sector %lld, count %d)\n", lba, len);
+        if (lba > s->max_lba)
+            goto illegal_lba;
         r->sector = lba * s->cluster_size;
         r->sector_count = len * s->cluster_size;
         break;
@@ -766,6 +771,8 @@
     case 0x2a:
     case 0x8a:
         DPRINTF("Write (sector %lld, count %d)\n", lba, len);
+        if (lba > s->max_lba)
+            goto illegal_lba;
         r->sector = lba * s->cluster_size;
         r->sector_count = len * s->cluster_size;
         is_write = 1;
@@ -839,6 +846,8 @@
             /* Returned value is the address of the last sector.  */
             if (nb_sectors) {
                 nb_sectors--;
+                /* Remember the new size for read/write sanity checking. */
+                s->max_lba = nb_sectors;
                 outbuf[0] = (nb_sectors >> 56) & 0xff;
                 outbuf[1] = (nb_sectors >> 48) & 0xff;
                 outbuf[2] = (nb_sectors >> 40) & 0xff;
@@ -877,6 +886,9 @@
     fail:
         scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_ILLEGAL_REQUEST);
 	return 0;
+    illegal_lba:
+        scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
+        return 0;
     }
     if (r->sector_count == 0 && r->buf_len == 0) {
         scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE);
@@ -902,6 +914,7 @@
 {
     SCSIDevice *d;
     SCSIDeviceState *s;
+    uint64_t nb_sectors;
 
     s = (SCSIDeviceState *)qemu_mallocz(sizeof(SCSIDeviceState));
     s->bdrv = bdrv;
@@ -913,6 +926,11 @@
     } else {
         s->cluster_size = 1;
     }
+    bdrv_get_geometry(s->bdrv, &nb_sectors);
+    nb_sectors /= s->cluster_size;
+    if (nb_sectors)
+        nb_sectors--;
+    s->max_lba = nb_sectors;
     strncpy(s->drive_serial_str, drive_get_serial(s->bdrv),
             sizeof(s->drive_serial_str));
     if (strlen(s->drive_serial_str) == 0)

                 reply	other threads:[~2009-01-29 19:59 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=E1LSd2W-0005Sa-KA@cvs.savannah.gnu.org \
    --to=anthony@codemonkey.ws \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).