From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1LSd2a-0006vc-Ak for qemu-devel@nongnu.org; Thu, 29 Jan 2009 14:59:08 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1LSd2Z-0006t4-AX for qemu-devel@nongnu.org; Thu, 29 Jan 2009 14:59:07 -0500 Received: from [199.232.76.173] (port=54745 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1LSd2Y-0006sg-QI for qemu-devel@nongnu.org; Thu, 29 Jan 2009 14:59:06 -0500 Received: from savannah.gnu.org ([199.232.41.3]:38186 helo=sv.gnu.org) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1LSd2X-0008At-RW for qemu-devel@nongnu.org; Thu, 29 Jan 2009 14:59:06 -0500 Received: from cvs.savannah.gnu.org ([199.232.41.69]) by sv.gnu.org with esmtp (Exim 4.63) (envelope-from ) id 1LSd2W-0005Se-Rn for qemu-devel@nongnu.org; Thu, 29 Jan 2009 19:59:04 +0000 Received: from aliguori by cvs.savannah.gnu.org with local (Exim 4.63) (envelope-from ) id 1LSd2W-0005Sa-KA for qemu-devel@nongnu.org; Thu, 29 Jan 2009 19:59:04 +0000 MIME-Version: 1.0 Errors-To: aliguori Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Anthony Liguori Message-Id: Date: Thu, 29 Jan 2009 19:59:04 +0000 Subject: [Qemu-devel] [6475] check SCSI read/write requests against max LBA (Rik van Riel) Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org 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 Signed-off-by: Anthony Liguori 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)