qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] check SCSI read/write requests against max LBA
@ 2009-01-29 16:54 Rik van Riel
  2009-01-29 19:59 ` Anthony Liguori
  0 siblings, 1 reply; 2+ messages in thread
From: Rik van Riel @ 2009-01-29 16:54 UTC (permalink / raw)
  To: qemu-devel

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>

Index: qemu/hw/scsi-disk.c
===================================================================
--- qemu.orig/hw/scsi-disk.c
+++ qemu/hw/scsi-disk.c
@@ -67,6 +67,7 @@ struct SCSIDeviceState
     /* 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 @@ static int32_t scsi_send_command(SCSIDev
         /* 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 @@ static int32_t scsi_send_command(SCSIDev
     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 @@ static int32_t scsi_send_command(SCSIDev
     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 +847,8 @@ static int32_t scsi_send_command(SCSIDev
             /* 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 +887,9 @@ static int32_t scsi_send_command(SCSIDev
     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 +915,7 @@ SCSIDevice *scsi_disk_init(BlockDriverSt
 {
     SCSIDevice *d;
     SCSIDeviceState *s;
+    uint64_t nb_sectors;
 
     s = (SCSIDeviceState *)qemu_mallocz(sizeof(SCSIDeviceState));
     s->bdrv = bdrv;
@@ -913,6 +927,11 @@ SCSIDevice *scsi_disk_init(BlockDriverSt
     } 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)

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [Qemu-devel] [PATCH] check SCSI read/write requests against max LBA
  2009-01-29 16:54 [Qemu-devel] [PATCH] check SCSI read/write requests against max LBA Rik van Riel
@ 2009-01-29 19:59 ` Anthony Liguori
  0 siblings, 0 replies; 2+ messages in thread
From: Anthony Liguori @ 2009-01-29 19:59 UTC (permalink / raw)
  To: qemu-devel

Rik van Riel wrote:
> 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>
>   
Applied.  Thanks.

Regards,

Anthony Liguori

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2009-01-29 19:59 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-01-29 16:54 [Qemu-devel] [PATCH] check SCSI read/write requests against max LBA Rik van Riel
2009-01-29 19:59 ` Anthony Liguori

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).