Commit 902b27d0b8d5bfa840eaf389d7cbcc28b57e3fbe

Authored by aurel32
1 parent b94ed577

Fix CVE-2008-0928 - insufficient block device address range checking

Qemu 0.9.1 and earlier does not perform range checks for block device
read or write requests, which allows guest host users with root
privileges to access arbitrary memory and escape the virtual machine.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4037 c046a42c-6fe2-441c-8c8c-71466251a162
block-qcow.c
@@ -95,7 +95,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) @@ -95,7 +95,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
95 int len, i, shift, ret; 95 int len, i, shift, ret;
96 QCowHeader header; 96 QCowHeader header;
97 97
98 - ret = bdrv_file_open(&s->hd, filename, flags); 98 + ret = bdrv_file_open(&s->hd, filename, flags | BDRV_O_AUTOGROW);
99 if (ret < 0) 99 if (ret < 0)
100 return ret; 100 return ret;
101 if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header)) 101 if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header))
block-qcow2.c
@@ -191,7 +191,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) @@ -191,7 +191,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
191 int len, i, shift, ret; 191 int len, i, shift, ret;
192 QCowHeader header; 192 QCowHeader header;
193 193
194 - ret = bdrv_file_open(&s->hd, filename, flags); 194 + ret = bdrv_file_open(&s->hd, filename, flags | BDRV_O_AUTOGROW);
195 if (ret < 0) 195 if (ret < 0)
196 return ret; 196 return ret;
197 if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header)) 197 if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header))
block-vmdk.c
@@ -378,7 +378,7 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags) @@ -378,7 +378,7 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
378 flags = BDRV_O_RDONLY; 378 flags = BDRV_O_RDONLY;
379 fprintf(stderr, "(VMDK) image open: flags=0x%x filename=%s\n", flags, bs->filename); 379 fprintf(stderr, "(VMDK) image open: flags=0x%x filename=%s\n", flags, bs->filename);
380 380
381 - ret = bdrv_file_open(&s->hd, filename, flags); 381 + ret = bdrv_file_open(&s->hd, filename, flags | BDRV_O_AUTOGROW);
382 if (ret < 0) 382 if (ret < 0)
383 return ret; 383 return ret;
384 if (bdrv_pread(s->hd, 0, &magic, sizeof(magic)) != sizeof(magic)) 384 if (bdrv_pread(s->hd, 0, &magic, sizeof(magic)) != sizeof(magic))
@@ -123,6 +123,60 @@ void path_combine(char *dest, int dest_size, @@ -123,6 +123,60 @@ void path_combine(char *dest, int dest_size,
123 } 123 }
124 } 124 }
125 125
  126 +static int bdrv_rd_badreq_sectors(BlockDriverState *bs,
  127 + int64_t sector_num, int nb_sectors)
  128 +{
  129 + return
  130 + nb_sectors < 0 ||
  131 + sector_num < 0 ||
  132 + nb_sectors > bs->total_sectors ||
  133 + sector_num > bs->total_sectors - nb_sectors;
  134 +}
  135 +
  136 +static int bdrv_rd_badreq_bytes(BlockDriverState *bs,
  137 + int64_t offset, int count)
  138 +{
  139 + int64_t size = bs->total_sectors << SECTOR_BITS;
  140 + return
  141 + count < 0 ||
  142 + size < 0 ||
  143 + count > size ||
  144 + offset > size - count;
  145 +}
  146 +
  147 +static int bdrv_wr_badreq_sectors(BlockDriverState *bs,
  148 + int64_t sector_num, int nb_sectors)
  149 +{
  150 + if (sector_num < 0 ||
  151 + nb_sectors < 0)
  152 + return 1;
  153 +
  154 + if (sector_num > bs->total_sectors - nb_sectors) {
  155 + if (bs->autogrow)
  156 + bs->total_sectors = sector_num + nb_sectors;
  157 + else
  158 + return 1;
  159 + }
  160 + return 0;
  161 +}
  162 +
  163 +static int bdrv_wr_badreq_bytes(BlockDriverState *bs,
  164 + int64_t offset, int count)
  165 +{
  166 + int64_t size = bs->total_sectors << SECTOR_BITS;
  167 + if (count < 0 ||
  168 + offset < 0)
  169 + return 1;
  170 +
  171 + if (offset > size - count) {
  172 + if (bs->autogrow)
  173 + bs->total_sectors = (offset + count + SECTOR_SIZE - 1) >> SECTOR_BITS;
  174 + else
  175 + return 1;
  176 + }
  177 + return 0;
  178 +}
  179 +
126 180
127 static void bdrv_register(BlockDriver *bdrv) 181 static void bdrv_register(BlockDriver *bdrv)
128 { 182 {
@@ -335,6 +389,10 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, @@ -335,6 +389,10 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
335 bs->read_only = 0; 389 bs->read_only = 0;
336 bs->is_temporary = 0; 390 bs->is_temporary = 0;
337 bs->encrypted = 0; 391 bs->encrypted = 0;
  392 + bs->autogrow = 0;
  393 +
  394 + if (flags & BDRV_O_AUTOGROW)
  395 + bs->autogrow = 1;
338 396
339 if (flags & BDRV_O_SNAPSHOT) { 397 if (flags & BDRV_O_SNAPSHOT) {
340 BlockDriverState *bs1; 398 BlockDriverState *bs1;
@@ -379,6 +437,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, @@ -379,6 +437,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
379 } 437 }
380 bs->drv = drv; 438 bs->drv = drv;
381 bs->opaque = qemu_mallocz(drv->instance_size); 439 bs->opaque = qemu_mallocz(drv->instance_size);
  440 + bs->total_sectors = 0; /* driver will set if it does not do getlength */
382 if (bs->opaque == NULL && drv->instance_size > 0) 441 if (bs->opaque == NULL && drv->instance_size > 0)
383 return -1; 442 return -1;
384 /* Note: for compatibility, we open disk image files as RDWR, and 443 /* Note: for compatibility, we open disk image files as RDWR, and
@@ -444,6 +503,7 @@ void bdrv_close(BlockDriverState *bs) @@ -444,6 +503,7 @@ void bdrv_close(BlockDriverState *bs)
444 bs->drv = NULL; 503 bs->drv = NULL;
445 504
446 /* call the change callback */ 505 /* call the change callback */
  506 + bs->total_sectors = 0;
447 bs->media_changed = 1; 507 bs->media_changed = 1;
448 if (bs->change_cb) 508 if (bs->change_cb)
449 bs->change_cb(bs->change_opaque); 509 bs->change_cb(bs->change_opaque);
@@ -509,6 +569,8 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num, @@ -509,6 +569,8 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
509 if (!drv) 569 if (!drv)
510 return -ENOMEDIUM; 570 return -ENOMEDIUM;
511 571
  572 + if (bdrv_rd_badreq_sectors(bs, sector_num, nb_sectors))
  573 + return -EDOM;
512 if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { 574 if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
513 memcpy(buf, bs->boot_sector_data, 512); 575 memcpy(buf, bs->boot_sector_data, 512);
514 sector_num++; 576 sector_num++;
@@ -549,6 +611,8 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, @@ -549,6 +611,8 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num,
549 return -ENOMEDIUM; 611 return -ENOMEDIUM;
550 if (bs->read_only) 612 if (bs->read_only)
551 return -EACCES; 613 return -EACCES;
  614 + if (bdrv_wr_badreq_sectors(bs, sector_num, nb_sectors))
  615 + return -EDOM;
552 if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { 616 if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
553 memcpy(bs->boot_sector_data, buf, 512); 617 memcpy(bs->boot_sector_data, buf, 512);
554 } 618 }
@@ -674,6 +738,8 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset, @@ -674,6 +738,8 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
674 return -ENOMEDIUM; 738 return -ENOMEDIUM;
675 if (!drv->bdrv_pread) 739 if (!drv->bdrv_pread)
676 return bdrv_pread_em(bs, offset, buf1, count1); 740 return bdrv_pread_em(bs, offset, buf1, count1);
  741 + if (bdrv_rd_badreq_bytes(bs, offset, count1))
  742 + return -EDOM;
677 return drv->bdrv_pread(bs, offset, buf1, count1); 743 return drv->bdrv_pread(bs, offset, buf1, count1);
678 } 744 }
679 745
@@ -689,6 +755,8 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset, @@ -689,6 +755,8 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
689 return -ENOMEDIUM; 755 return -ENOMEDIUM;
690 if (!drv->bdrv_pwrite) 756 if (!drv->bdrv_pwrite)
691 return bdrv_pwrite_em(bs, offset, buf1, count1); 757 return bdrv_pwrite_em(bs, offset, buf1, count1);
  758 + if (bdrv_wr_badreq_bytes(bs, offset, count1))
  759 + return -EDOM;
692 return drv->bdrv_pwrite(bs, offset, buf1, count1); 760 return drv->bdrv_pwrite(bs, offset, buf1, count1);
693 } 761 }
694 762
@@ -955,6 +1023,8 @@ int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, @@ -955,6 +1023,8 @@ int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
955 return -ENOMEDIUM; 1023 return -ENOMEDIUM;
956 if (!drv->bdrv_write_compressed) 1024 if (!drv->bdrv_write_compressed)
957 return -ENOTSUP; 1025 return -ENOTSUP;
  1026 + if (bdrv_wr_badreq_sectors(bs, sector_num, nb_sectors))
  1027 + return -EDOM;
958 return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors); 1028 return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors);
959 } 1029 }
960 1030
@@ -1101,6 +1171,8 @@ BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num, @@ -1101,6 +1171,8 @@ BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num,
1101 1171
1102 if (!drv) 1172 if (!drv)
1103 return NULL; 1173 return NULL;
  1174 + if (bdrv_rd_badreq_sectors(bs, sector_num, nb_sectors))
  1175 + return NULL;
1104 1176
1105 /* XXX: we assume that nb_sectors == 0 is suppored by the async read */ 1177 /* XXX: we assume that nb_sectors == 0 is suppored by the async read */
1106 if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { 1178 if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
@@ -1132,6 +1204,8 @@ BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num, @@ -1132,6 +1204,8 @@ BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num,
1132 return NULL; 1204 return NULL;
1133 if (bs->read_only) 1205 if (bs->read_only)
1134 return NULL; 1206 return NULL;
  1207 + if (bdrv_wr_badreq_sectors(bs, sector_num, nb_sectors))
  1208 + return NULL;
1135 if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { 1209 if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
1136 memcpy(bs->boot_sector_data, buf, 512); 1210 memcpy(bs->boot_sector_data, buf, 512);
1137 } 1211 }
@@ -45,6 +45,7 @@ typedef struct QEMUSnapshotInfo { @@ -45,6 +45,7 @@ typedef struct QEMUSnapshotInfo {
45 it (default for 45 it (default for
46 bdrv_file_open()) */ 46 bdrv_file_open()) */
47 #define BDRV_O_DIRECT 0x0020 47 #define BDRV_O_DIRECT 0x0020
  48 +#define BDRV_O_AUTOGROW 0x0040 /* Allow backing file to extend when writing past end of file */
48 49
49 #ifndef QEMU_IMG 50 #ifndef QEMU_IMG
50 void bdrv_info(void); 51 void bdrv_info(void);
block_int.h
@@ -97,6 +97,7 @@ struct BlockDriverState { @@ -97,6 +97,7 @@ struct BlockDriverState {
97 int locked; /* if true, the media cannot temporarily be ejected */ 97 int locked; /* if true, the media cannot temporarily be ejected */
98 int encrypted; /* if true, the media is encrypted */ 98 int encrypted; /* if true, the media is encrypted */
99 int sg; /* if true, the device is a /dev/sg* */ 99 int sg; /* if true, the device is a /dev/sg* */
  100 + int autogrow; /* if true, the backing store can auto-extend to allocate new extents */
100 /* event callback when inserting/removing */ 101 /* event callback when inserting/removing */
101 void (*change_cb)(void *opaque); 102 void (*change_cb)(void *opaque);
102 void *change_opaque; 103 void *change_opaque;