|
|||||||||||
|
qemu unchecked block read/write vulnerability
From: Ian Jackson <Ian.Jackson(at)eu.citrix.com>
Date: Tue Feb 19 2008 - 10:23:30 EST
When a block device read or write request is made by the guest, nothing checks that the request is within the range supported by the backend, but the code in the backend typically assumes that the request is sensible. Depending on the backend, this can allow the guest to read and write arbitrary memory locations in qemu, and possibly gain control over the qemu process, escaping from the emulation/virtualisation. I have demonstrated to my own satisfaction that there is problem, using a modified Linux kernel as a guest with an instrumented CVS head qemu. I'm not much good as an exploit developer so I haven't done better than cause qemu to crash. I have also prepared a patch which I have checked prevents my test case but which I haven't subjected to anything resembling proper functional testing.
I contacted privately five of the main qemu developers but the only
response was from Andrzej Zaborowski who didn't consider the problem
serious, saying
As well as pure emulation, qemu is also used by various virtualisation systems as a device model or emulation harness. For example, at least Xen (with HVM guests) is affected and and kvm probably too. So I didn't agree with Andrzej. I'm going to go and try to do some more testing of my patch, which is attached, in the context of Xen. I expect that unless we discover that I'm wrong, we'll be publishing a fix for this bug in Xen's xen-unstable and backporting it to xen-3.2 and xen-3.1, in perhaps a week or two. I'll post to the qemu list at that time too. There is not yet a CVE reference for this vulnerability. Ian.
diff --git a/block.c b/block.c
}
+static int bdrv_rw_badreq_sectors(BlockDriverState *bs,
+ int64_t sector_num, int nb_sectors)
+{
+ return
+ nb_sectors < 0 ||
+ nb_sectors > bs->total_sectors ||
+ sector_num > bs->total_sectors - nb_sectors;
+}
+
+static int bdrv_rw_badreq_bytes(BlockDriverState *bs,
+ int64_t offset, int count)
+{
+ int64_t size = bs->total_sectors << SECTOR_BITS;
+ return
+ count < 0 ||
+ count > size ||
+ offset > size - count;
+}
static void bdrv_register(BlockDriver *bdrv)
{
}
bs->drv = drv;
bs->opaque = qemu_mallocz(drv->instance_size);
+ bs->total_sectors = 0; /* driver will set if it does not do getlength */
if (bs->opaque == NULL && drv->instance_size > 0)
return -1;
/* Note: for compatibility, we open disk image files as RDWR, and
}
@@ -685,6 +711,8 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
return -ENOMEDIUM;
if (!drv->bdrv_pwrite)
return bdrv_pwrite_em(bs, offset, buf1, count1);
+ if (bdrv_rw_badreq_bytes(bs, offset, count1))
+ return -EDOM;
return drv->bdrv_pwrite(bs, offset, buf1, count1);
}
@@ -951,6 +979,8 @@ int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
return -ENOMEDIUM;
if (!drv->bdrv_write_compressed)
return -ENOTSUP;
+ if (bdrv_rw_badreq_sectors(bs, sector_num, nb_sectors))
+ return -EDOM;
return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors);
}
@@ -1097,6 +1127,8 @@ BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num,
if (!drv)
return NULL;
+ if (bdrv_rw_badreq_sectors(bs, sector_num, nb_sectors))
+ return NULL;
/* XXX: we assume that nb_sectors == 0 is suppored by the async read */
if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
-- To UNSUBSCRIBE, email to debian-security-REQUEST@lists.debian.org with a subject of "unsubscribe". Trouble? Contact listmaster@lists.debian.orgReceived on Tue Feb 19 10:49:16 2008 This archive was generated by hypermail 2.1.8 : Wed Mar 19 2008 - 06:56:02 EDT |
||||||||||
|
|||||||||||