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 95 int len, i, shift, ret;
96 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 99 if (ret < 0)
100 100 return ret;
101 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 191 int len, i, shift, ret;
192 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 195 if (ret < 0)
196 196 return ret;
197 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 378 flags = BDRV_O_RDONLY;
379 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 382 if (ret < 0)
383 383 return ret;
384 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 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 181 static void bdrv_register(BlockDriver *bdrv)
128 182 {
... ... @@ -335,6 +389,10 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
335 389 bs->read_only = 0;
336 390 bs->is_temporary = 0;
337 391 bs->encrypted = 0;
  392 + bs->autogrow = 0;
  393 +
  394 + if (flags & BDRV_O_AUTOGROW)
  395 + bs->autogrow = 1;
338 396  
339 397 if (flags & BDRV_O_SNAPSHOT) {
340 398 BlockDriverState *bs1;
... ... @@ -379,6 +437,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
379 437 }
380 438 bs->drv = drv;
381 439 bs->opaque = qemu_mallocz(drv->instance_size);
  440 + bs->total_sectors = 0; /* driver will set if it does not do getlength */
382 441 if (bs->opaque == NULL && drv->instance_size > 0)
383 442 return -1;
384 443 /* Note: for compatibility, we open disk image files as RDWR, and
... ... @@ -444,6 +503,7 @@ void bdrv_close(BlockDriverState *bs)
444 503 bs->drv = NULL;
445 504  
446 505 /* call the change callback */
  506 + bs->total_sectors = 0;
447 507 bs->media_changed = 1;
448 508 if (bs->change_cb)
449 509 bs->change_cb(bs->change_opaque);
... ... @@ -509,6 +569,8 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
509 569 if (!drv)
510 570 return -ENOMEDIUM;
511 571  
  572 + if (bdrv_rd_badreq_sectors(bs, sector_num, nb_sectors))
  573 + return -EDOM;
512 574 if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
513 575 memcpy(buf, bs->boot_sector_data, 512);
514 576 sector_num++;
... ... @@ -549,6 +611,8 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num,
549 611 return -ENOMEDIUM;
550 612 if (bs->read_only)
551 613 return -EACCES;
  614 + if (bdrv_wr_badreq_sectors(bs, sector_num, nb_sectors))
  615 + return -EDOM;
552 616 if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
553 617 memcpy(bs->boot_sector_data, buf, 512);
554 618 }
... ... @@ -674,6 +738,8 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
674 738 return -ENOMEDIUM;
675 739 if (!drv->bdrv_pread)
676 740 return bdrv_pread_em(bs, offset, buf1, count1);
  741 + if (bdrv_rd_badreq_bytes(bs, offset, count1))
  742 + return -EDOM;
677 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 755 return -ENOMEDIUM;
690 756 if (!drv->bdrv_pwrite)
691 757 return bdrv_pwrite_em(bs, offset, buf1, count1);
  758 + if (bdrv_wr_badreq_bytes(bs, offset, count1))
  759 + return -EDOM;
692 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 1023 return -ENOMEDIUM;
956 1024 if (!drv->bdrv_write_compressed)
957 1025 return -ENOTSUP;
  1026 + if (bdrv_wr_badreq_sectors(bs, sector_num, nb_sectors))
  1027 + return -EDOM;
958 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 1171  
1102 1172 if (!drv)
1103 1173 return NULL;
  1174 + if (bdrv_rd_badreq_sectors(bs, sector_num, nb_sectors))
  1175 + return NULL;
1104 1176  
1105 1177 /* XXX: we assume that nb_sectors == 0 is suppored by the async read */
1106 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 1204 return NULL;
1133 1205 if (bs->read_only)
1134 1206 return NULL;
  1207 + if (bdrv_wr_badreq_sectors(bs, sector_num, nb_sectors))
  1208 + return NULL;
1135 1209 if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
1136 1210 memcpy(bs->boot_sector_data, buf, 512);
1137 1211 }
... ...
... ... @@ -45,6 +45,7 @@ typedef struct QEMUSnapshotInfo {
45 45 it (default for
46 46 bdrv_file_open()) */
47 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 50 #ifndef QEMU_IMG
50 51 void bdrv_info(void);
... ...
block_int.h
... ... @@ -97,6 +97,7 @@ struct BlockDriverState {
97 97 int locked; /* if true, the media cannot temporarily be ejected */
98 98 int encrypted; /* if true, the media is encrypted */
99 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 101 /* event callback when inserting/removing */
101 102 void (*change_cb)(void *opaque);
102 103 void *change_opaque;
... ...