Commit 274fb0e1ed962e9ae43ab05e7939499cebb39d26

Authored by aliguori
1 parent 33049de7

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>


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6475 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 18 additions and 0 deletions
hw/scsi-disk.c
@@ -67,6 +67,7 @@ struct SCSIDeviceState @@ -67,6 +67,7 @@ struct SCSIDeviceState
67 /* The qemu block layer uses a fixed 512 byte sector size. 67 /* The qemu block layer uses a fixed 512 byte sector size.
68 This is the number of 512 byte blocks in a single scsi sector. */ 68 This is the number of 512 byte blocks in a single scsi sector. */
69 int cluster_size; 69 int cluster_size;
  70 + uint64_t max_lba;
70 int sense; 71 int sense;
71 int tcq; 72 int tcq;
72 /* Completion functions may be called from either scsi_{read,write}_data 73 /* Completion functions may be called from either scsi_{read,write}_data
@@ -738,6 +739,8 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, @@ -738,6 +739,8 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
738 /* Returned value is the address of the last sector. */ 739 /* Returned value is the address of the last sector. */
739 if (nb_sectors) { 740 if (nb_sectors) {
740 nb_sectors--; 741 nb_sectors--;
  742 + /* Remember the new size for read/write sanity checking. */
  743 + s->max_lba = nb_sectors;
741 /* Clip to 2TB, instead of returning capacity modulo 2TB. */ 744 /* Clip to 2TB, instead of returning capacity modulo 2TB. */
742 if (nb_sectors > UINT32_MAX) 745 if (nb_sectors > UINT32_MAX)
743 nb_sectors = UINT32_MAX; 746 nb_sectors = UINT32_MAX;
@@ -759,6 +762,8 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, @@ -759,6 +762,8 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
759 case 0x28: 762 case 0x28:
760 case 0x88: 763 case 0x88:
761 DPRINTF("Read (sector %lld, count %d)\n", lba, len); 764 DPRINTF("Read (sector %lld, count %d)\n", lba, len);
  765 + if (lba > s->max_lba)
  766 + goto illegal_lba;
762 r->sector = lba * s->cluster_size; 767 r->sector = lba * s->cluster_size;
763 r->sector_count = len * s->cluster_size; 768 r->sector_count = len * s->cluster_size;
764 break; 769 break;
@@ -766,6 +771,8 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, @@ -766,6 +771,8 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
766 case 0x2a: 771 case 0x2a:
767 case 0x8a: 772 case 0x8a:
768 DPRINTF("Write (sector %lld, count %d)\n", lba, len); 773 DPRINTF("Write (sector %lld, count %d)\n", lba, len);
  774 + if (lba > s->max_lba)
  775 + goto illegal_lba;
769 r->sector = lba * s->cluster_size; 776 r->sector = lba * s->cluster_size;
770 r->sector_count = len * s->cluster_size; 777 r->sector_count = len * s->cluster_size;
771 is_write = 1; 778 is_write = 1;
@@ -839,6 +846,8 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, @@ -839,6 +846,8 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
839 /* Returned value is the address of the last sector. */ 846 /* Returned value is the address of the last sector. */
840 if (nb_sectors) { 847 if (nb_sectors) {
841 nb_sectors--; 848 nb_sectors--;
  849 + /* Remember the new size for read/write sanity checking. */
  850 + s->max_lba = nb_sectors;
842 outbuf[0] = (nb_sectors >> 56) & 0xff; 851 outbuf[0] = (nb_sectors >> 56) & 0xff;
843 outbuf[1] = (nb_sectors >> 48) & 0xff; 852 outbuf[1] = (nb_sectors >> 48) & 0xff;
844 outbuf[2] = (nb_sectors >> 40) & 0xff; 853 outbuf[2] = (nb_sectors >> 40) & 0xff;
@@ -877,6 +886,9 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, @@ -877,6 +886,9 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
877 fail: 886 fail:
878 scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_ILLEGAL_REQUEST); 887 scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_ILLEGAL_REQUEST);
879 return 0; 888 return 0;
  889 + illegal_lba:
  890 + scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
  891 + return 0;
880 } 892 }
881 if (r->sector_count == 0 && r->buf_len == 0) { 893 if (r->sector_count == 0 && r->buf_len == 0) {
882 scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE); 894 scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE);
@@ -902,6 +914,7 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq, @@ -902,6 +914,7 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq,
902 { 914 {
903 SCSIDevice *d; 915 SCSIDevice *d;
904 SCSIDeviceState *s; 916 SCSIDeviceState *s;
  917 + uint64_t nb_sectors;
905 918
906 s = (SCSIDeviceState *)qemu_mallocz(sizeof(SCSIDeviceState)); 919 s = (SCSIDeviceState *)qemu_mallocz(sizeof(SCSIDeviceState));
907 s->bdrv = bdrv; 920 s->bdrv = bdrv;
@@ -913,6 +926,11 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq, @@ -913,6 +926,11 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq,
913 } else { 926 } else {
914 s->cluster_size = 1; 927 s->cluster_size = 1;
915 } 928 }
  929 + bdrv_get_geometry(s->bdrv, &nb_sectors);
  930 + nb_sectors /= s->cluster_size;
  931 + if (nb_sectors)
  932 + nb_sectors--;
  933 + s->max_lba = nb_sectors;
916 strncpy(s->drive_serial_str, drive_get_serial(s->bdrv), 934 strncpy(s->drive_serial_str, drive_get_serial(s->bdrv),
917 sizeof(s->drive_serial_str)); 935 sizeof(s->drive_serial_str));
918 if (strlen(s->drive_serial_str) == 0) 936 if (strlen(s->drive_serial_str) == 0)