}
}
+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
+ ) && !bs->extendable;
+}
+
+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
+ ) && !bs->extendable;
+
+}
static void bdrv_register(BlockDriver *bdrv)
{
bs->is_temporary = 0;
bs->encrypted = 0;
+ if (flags & BDRV_O_EXTENDABLE) {
+ if (!(drv->bdrv_flags & BLOCK_DRIVER_FLAG_EXTENDABLE))
+ return -ENOSYS;
+ bs->extendable = 1;
+ }
+
if (flags & BDRV_O_SNAPSHOT) {
BlockDriverState *bs1;
int64_t total_size;
}
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
bs->drv = NULL;
/* call the change callback */
+ bs->total_sectors = 0;
bs->media_changed = 1;
if (bs->change_cb)
bs->change_cb(bs->change_opaque);
if (!drv)
return -ENOMEDIUM;
+ if (bdrv_rw_badreq_sectors(bs, sector_num, nb_sectors))
+ return -EDOM;
if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
memcpy(buf, bs->boot_sector_data, 512);
sector_num++;
return -ENOMEDIUM;
if (bs->read_only)
return -EACCES;
+ if (bdrv_rw_badreq_sectors(bs, sector_num, nb_sectors))
+ return -EDOM;
if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
memcpy(bs->boot_sector_data, buf, 512);
}
return -ENOMEDIUM;
if (!drv->bdrv_pread)
return bdrv_pread_em(bs, offset, buf1, count1);
+ if (bdrv_rw_badreq_bytes(bs, offset, count1))
+ return -EDOM;
return drv->bdrv_pread(bs, offset, buf1, count1);
}
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);
}
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);
}
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) {
return NULL;
if (bs->read_only)
return NULL;
+ if (bdrv_rw_badreq_sectors(bs, sector_num, nb_sectors))
+ return NULL;
if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
memcpy(bs->boot_sector_data, buf, 512);
}
#define BLOCK_FLAG_COMPRESS 2
#define BLOCK_FLAG_COMPAT6 4
+#define BLOCK_DRIVER_FLAG_EXTENDABLE 0x0001u
+
struct BlockDriver {
const char *format_name;
int instance_size;
/* to control generic scsi devices */
int (*bdrv_ioctl)(BlockDriverState *bs, unsigned long int req, void *buf);
+ unsigned bdrv_flags;
BlockDriverAIOCB *free_aiocb;
struct BlockDriver *next;
};
int locked; /* if true, the media cannot temporarily be ejected */
int encrypted; /* if true, the media is encrypted */
int sg; /* if true, the device is a /dev/sg* */
+ int extendable;/* if true, we may write out of original range */
/* event callback when inserting/removing */
void (*change_cb)(void *opaque);
void *change_opaque;