diff -u kvm-62+dfsg/debian/patches/series kvm-62+dfsg/debian/patches/series --- kvm-62+dfsg/debian/patches/series +++ kvm-62+dfsg/debian/patches/series @@ -10,0 +11,2 @@ +SECURITY_CVE-2007-1320+1321+1322+1366+2893.patch +SECURITY_CVE-2008-0928.patch diff -u kvm-62+dfsg/debian/changelog kvm-62+dfsg/debian/changelog --- kvm-62+dfsg/debian/changelog +++ kvm-62+dfsg/debian/changelog @@ -1,3 +1,33 @@ +kvm (1:62+dfsg-0ubuntu3) hardy; urgency=low + + * debian/patches/SECURITY_CVE-2007-1320+1321+1322+1366+2893.patch + based on 90_security.patch from qemu 0.9.1-1ubuntu1. Please note that + CVE-2007-2893 is also known as CVE-2007-1323, and CVE-2007-5729 and + CVE-2007-5730 are known as CVE-2007-1321 in Debian. This patch addresses + the following: + - Cirrus LGD-54XX "bitblt" heap overflow. + - NE2000 "mtu" heap overflow. + - QEMU "net socket" heap overflow. + - QEMU NE2000 "receive" integer signedness error. + - Infinite loop in the emulated SB16 device. + - Unprivileged "aam" instruction does not correctly handle the + undocumented divisor operand. + - Unprivileged "icebp" instruction will halt emulation. + * debian/patches/SECURITY_CVE-2008-0928.patch: perform range checks on + block device read and write requests + * References + CVE-2007-1320 + CVE-2007-1321 + CVE-2007-1322 + CVE-2007-1323 + CVE-2007-1366 + CVE-2007-2893 + CVE-2007-5729 + CVE-2007-5730 + CVE-2008-0928 + + -- Jamie Strandboge Mon, 07 Apr 2008 11:26:45 -0400 + kvm (1:62+dfsg-0ubuntu2) hardy; urgency=low * Re-disable unaccelerated execution (thus re-removing gcc-3.4 build- only in patch2: unchanged: --- kvm-62+dfsg.orig/debian/patches/SECURITY_CVE-2007-1320+1321+1322+1366+2893.patch +++ kvm-62+dfsg/debian/patches/SECURITY_CVE-2007-1320+1321+1322+1366+2893.patch @@ -0,0 +1,321 @@ +diff -Nur kvm-62+dfsg/qemu/block.c kvm-62+dfsg.new/qemu/block.c +--- kvm-62+dfsg/qemu/block.c 2008-02-25 04:30:14.000000000 -0500 ++++ kvm-62+dfsg.new/qemu/block.c 2008-04-07 11:13:03.000000000 -0400 +@@ -546,13 +546,21 @@ + return -ENOMEDIUM; + if (bs->read_only) + return -EACCES; ++ if (sector_num < 0) ++ return -EINVAL; + if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { + memcpy(bs->boot_sector_data, buf, 512); + } + if (drv->bdrv_pwrite) { + int ret, len; ++ int64_t ns; ++ + len = nb_sectors * 512; +- ret = drv->bdrv_pwrite(bs, sector_num * 512, buf, len); ++ ns = sector_num * 512; ++ if (ns < 0) ++ return -EINVAL; ++ ++ ret = drv->bdrv_pwrite(bs, ns, buf, len); + if (ret < 0) + return ret; + else if (ret != len) +diff -Nur kvm-62+dfsg/qemu/hw/cirrus_vga.c kvm-62+dfsg.new/qemu/hw/cirrus_vga.c +--- kvm-62+dfsg/qemu/hw/cirrus_vga.c 2008-02-25 04:30:14.000000000 -0500 ++++ kvm-62+dfsg.new/qemu/hw/cirrus_vga.c 2008-04-07 11:13:03.000000000 -0400 +@@ -224,6 +224,20 @@ + #define CIRRUS_HOOK_NOT_HANDLED 0 + #define CIRRUS_HOOK_HANDLED 1 + ++#define BLTUNSAFE(s) \ ++ ( \ ++ ( /* check dst is within bounds */ \ ++ (s)->cirrus_blt_height * (s)->cirrus_blt_dstpitch \ ++ + ((s)->cirrus_blt_dstaddr & (s)->cirrus_addr_mask) > \ ++ (s)->vram_size \ ++ ) || \ ++ ( /* check src is within bounds */ \ ++ (s)->cirrus_blt_height * (s)->cirrus_blt_srcpitch \ ++ + ((s)->cirrus_blt_srcaddr & (s)->cirrus_addr_mask) > \ ++ (s)->vram_size \ ++ ) \ ++ ) ++ + struct CirrusVGAState; + typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s, + uint8_t * dst, const uint8_t * src, +@@ -645,7 +659,7 @@ + + for (y = 0; y < lines; y++) { + off_cur = off_begin; +- off_cur_end = off_cur + bytesperline; ++ off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask; + off_cur &= TARGET_PAGE_MASK; + while (off_cur < off_cur_end) { + cpu_physical_memory_set_dirty(s->vram_offset + off_cur); +@@ -660,7 +674,11 @@ + { + uint8_t *dst; + +- dst = s->vram_ptr + s->cirrus_blt_dstaddr; ++ dst = s->vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask); ++ ++ if (BLTUNSAFE(s)) ++ return 0; ++ + (*s->cirrus_rop) (s, dst, src, + s->cirrus_blt_dstpitch, 0, + s->cirrus_blt_width, s->cirrus_blt_height); +@@ -676,8 +694,10 @@ + { + cirrus_fill_t rop_func; + ++ if (BLTUNSAFE(s)) ++ return 0; + rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; +- rop_func(s, s->vram_ptr + s->cirrus_blt_dstaddr, ++ rop_func(s, s->vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), + s->cirrus_blt_dstpitch, + s->cirrus_blt_width, s->cirrus_blt_height); + cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, +@@ -696,8 +716,8 @@ + static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s) + { + return cirrus_bitblt_common_patterncopy(s, +- s->vram_ptr + +- (s->cirrus_blt_srcaddr & ~7)); ++ s->vram_ptr + ((s->cirrus_blt_srcaddr & ~7) & ++ s->cirrus_addr_mask)); + } + + static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) +@@ -747,8 +767,10 @@ + if (notify) + vga_hw_update(); + +- (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr, +- s->vram_ptr + s->cirrus_blt_srcaddr, ++ (*s->cirrus_rop) (s, s->vram_ptr + ++ (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), ++ s->vram_ptr + ++ (s->cirrus_blt_srcaddr & s->cirrus_addr_mask), + s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, + s->cirrus_blt_width, s->cirrus_blt_height); + +@@ -774,8 +796,14 @@ + s->cirrus_blt_srcaddr - s->start_addr, + s->cirrus_blt_width, s->cirrus_blt_height); + } else { +- (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr, +- s->vram_ptr + s->cirrus_blt_srcaddr, ++ ++ if (BLTUNSAFE(s)) ++ return 0; ++ ++ (*s->cirrus_rop) (s, s->vram_ptr + ++ (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), ++ s->vram_ptr + ++ (s->cirrus_blt_srcaddr & s->cirrus_addr_mask), + s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, + s->cirrus_blt_width, s->cirrus_blt_height); + +@@ -807,8 +835,9 @@ + } else { + /* at least one scan line */ + do { +- (*s->cirrus_rop)(s, s->vram_ptr + s->cirrus_blt_dstaddr, +- s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1); ++ (*s->cirrus_rop)(s, s->vram_ptr + ++ (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), ++ s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1); + cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0, + s->cirrus_blt_width, 1); + s->cirrus_blt_dstaddr += s->cirrus_blt_dstpitch; +@@ -1929,7 +1958,7 @@ + unsigned val = mem_value; + uint8_t *dst; + +- dst = s->vram_ptr + offset; ++ dst = s->vram_ptr + (offset &= s->cirrus_addr_mask); + for (x = 0; x < 8; x++) { + if (val & 0x80) { + *dst = s->cirrus_shadow_gr1; +@@ -1952,7 +1981,7 @@ + unsigned val = mem_value; + uint8_t *dst; + +- dst = s->vram_ptr + offset; ++ dst = s->vram_ptr + (offset &= s->cirrus_addr_mask); + for (x = 0; x < 8; x++) { + if (val & 0x80) { + *dst = s->cirrus_shadow_gr1; +diff -Nur kvm-62+dfsg/qemu/hw/cirrus_vga_rop.h kvm-62+dfsg.new/qemu/hw/cirrus_vga_rop.h +--- kvm-62+dfsg/qemu/hw/cirrus_vga_rop.h 2008-02-25 04:30:14.000000000 -0500 ++++ kvm-62+dfsg.new/qemu/hw/cirrus_vga_rop.h 2008-04-07 11:13:03.000000000 -0400 +@@ -31,6 +31,12 @@ + int x,y; + dstpitch -= bltwidth; + srcpitch -= bltwidth; ++ ++ if (dstpitch < 0 || srcpitch < 0) { ++ /* is 0 valid? srcpitch == 0 could be useful */ ++ return; ++ } ++ + for (y = 0; y < bltheight; y++) { + for (x = 0; x < bltwidth; x++) { + ROP_OP(*dst, *src); +diff -Nur kvm-62+dfsg/qemu/hw/dma.c kvm-62+dfsg.new/qemu/hw/dma.c +--- kvm-62+dfsg/qemu/hw/dma.c 2008-02-25 04:30:14.000000000 -0500 ++++ kvm-62+dfsg.new/qemu/hw/dma.c 2008-04-07 11:13:03.000000000 -0400 +@@ -341,9 +341,11 @@ + #endif + + r = dma_controllers[ncont].regs + ichan; +- n = r->transfer_handler (r->opaque, ichan + (ncont << 2), +- r->now[COUNT], (r->base[COUNT] + 1) << ncont); +- r->now[COUNT] = n; ++ if (r->transfer_handler) { ++ n = r->transfer_handler (r->opaque, ichan + (ncont << 2), ++ r->now[COUNT], (r->base[COUNT] + 1) << ncont); ++ r->now[COUNT] = n; ++ } + ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont); + } + +diff -Nur kvm-62+dfsg/qemu/hw/fdc.c kvm-62+dfsg.new/qemu/hw/fdc.c +--- kvm-62+dfsg/qemu/hw/fdc.c 2008-02-25 04:30:14.000000000 -0500 ++++ kvm-62+dfsg.new/qemu/hw/fdc.c 2008-04-07 11:13:03.000000000 -0400 +@@ -1247,7 +1247,13 @@ + len = fdctrl->data_len - fdctrl->data_pos; + if (len > FD_SECTOR_LEN) + len = FD_SECTOR_LEN; +- bdrv_read(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1); ++ if (cur_drv->bs) { ++ bdrv_read(cur_drv->bs, fd_sector(cur_drv), ++ fdctrl->fifo, 1); ++ } else { ++ FLOPPY_ERROR("can't read data from drive\n"); ++ return 0; ++ } + } + } + retval = fdctrl->fifo[pos]; +diff -Nur kvm-62+dfsg/qemu/hw/pc.c kvm-62+dfsg.new/qemu/hw/pc.c +--- kvm-62+dfsg/qemu/hw/pc.c 2008-02-25 04:30:14.000000000 -0500 ++++ kvm-62+dfsg.new/qemu/hw/pc.c 2008-04-07 11:13:03.000000000 -0400 +@@ -341,7 +341,8 @@ + case 0x400: + case 0x401: + fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val); +- exit(1); ++ /* according to documentation, these can be safely ignored */ ++ break; + case 0x402: + case 0x403: + #ifdef DEBUG_BIOS +@@ -364,8 +365,9 @@ + /* LGPL'ed VGA BIOS messages */ + case 0x501: + case 0x502: ++ /* according to documentation, these can be safely ignored */ + fprintf(stderr, "VGA BIOS panic, line %d\n", val); +- exit(1); ++ break; + case 0x500: + case 0x503: + #ifdef DEBUG_BIOS +diff -Nur kvm-62+dfsg/qemu/hw/sb16.c kvm-62+dfsg.new/qemu/hw/sb16.c +--- kvm-62+dfsg/qemu/hw/sb16.c 2008-02-25 04:30:14.000000000 -0500 ++++ kvm-62+dfsg.new/qemu/hw/sb16.c 2008-04-07 11:13:03.000000000 -0400 +@@ -1246,8 +1246,10 @@ + s->block_size); + #endif + +- while (s->left_till_irq <= 0) { +- s->left_till_irq = s->block_size + s->left_till_irq; ++ if (s->block_size) { ++ while (s->left_till_irq <= 0) { ++ s->left_till_irq = s->block_size + s->left_till_irq; ++ } + } + + return dma_pos; +diff -Nur kvm-62+dfsg/qemu/slirp/slirp.c kvm-62+dfsg.new/qemu/slirp/slirp.c +--- kvm-62+dfsg/qemu/slirp/slirp.c 2008-02-25 04:30:14.000000000 -0500 ++++ kvm-62+dfsg.new/qemu/slirp/slirp.c 2008-04-07 11:13:03.000000000 -0400 +@@ -620,6 +620,10 @@ + if (!m) + return; + /* Note: we add to align the IP header */ ++ /* taviso: large values in ne2k TCNT register may exceed msize on transmit */ ++ if (M_FREEROOM(m) < pkt_len + 2) { ++ m_inc(m, pkt_len + 2); ++ } + m->m_len = pkt_len + 2; + memcpy(m->m_data + 2, pkt, pkt_len); + +diff -Nur kvm-62+dfsg/qemu/target-i386/translate.c kvm-62+dfsg.new/qemu/target-i386/translate.c +--- kvm-62+dfsg/qemu/target-i386/translate.c 2008-02-25 04:30:14.000000000 -0500 ++++ kvm-62+dfsg.new/qemu/target-i386/translate.c 2008-04-07 11:13:03.000000000 -0400 +@@ -5516,6 +5516,7 @@ + gen_jmp_im(pc_start - s->cs_base); + gen_op_into(s->pc - pc_start); + break; ++#ifdef WANT_ICEBP + case 0xf1: /* icebp (undocumented, exits to external debugger) */ + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_ICEBP)) + break; +@@ -5527,6 +5528,7 @@ + cpu_set_log(CPU_LOG_INT | CPU_LOG_TB_IN_ASM); + #endif + break; ++#endif /* icebp */ + case 0xfa: /* cli */ + if (!s->vm86) { + if (s->cpl <= s->iopl) { +diff -Nur kvm-62+dfsg/qemu/vl.c kvm-62+dfsg.new/qemu/vl.c +--- kvm-62+dfsg/qemu/vl.c 2008-04-07 11:12:57.000000000 -0400 ++++ kvm-62+dfsg.new/qemu/vl.c 2008-04-07 11:13:03.000000000 -0400 +@@ -4258,8 +4258,8 @@ + VLANClientState *vc; + int fd; + int state; /* 0 = getting length, 1 = getting data */ +- int index; +- int packet_len; ++ unsigned int index; ++ unsigned int packet_len; + uint8_t buf[4096]; + struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */ + } NetSocketState; +@@ -4290,7 +4290,8 @@ + static void net_socket_send(void *opaque) + { + NetSocketState *s = opaque; +- int l, size, err; ++ int size, err; ++ unsigned l; + uint8_t buf1[4096]; + const uint8_t *buf; + +@@ -4329,7 +4330,15 @@ + l = s->packet_len - s->index; + if (l > size) + l = size; +- memcpy(s->buf + s->index, buf, l); ++ if (s->index + l <= sizeof(s->buf)) { ++ memcpy(s->buf + s->index, buf, l); ++ } else { ++ fprintf(stderr, "serious error: oversized packet received," ++ "connection terminated.\n"); ++ s->state = 0; ++ goto eoc; ++ } ++ + s->index += l; + buf += l; + size -= l; only in patch2: unchanged: --- kvm-62+dfsg.orig/debian/patches/SECURITY_CVE-2008-0928.patch +++ kvm-62+dfsg/debian/patches/SECURITY_CVE-2008-0928.patch @@ -0,0 +1,212 @@ +diff -Nur kvm-62+dfsg/qemu/block-qcow.c kvm-62+dfsg.new/qemu/block-qcow.c +--- kvm-62+dfsg/qemu/block-qcow.c 2008-02-25 04:30:14.000000000 -0500 ++++ kvm-62+dfsg.new/qemu/block-qcow.c 2008-04-07 11:23:30.000000000 -0400 +@@ -95,7 +95,7 @@ + int len, i, shift, ret; + QCowHeader header; + +- ret = bdrv_file_open(&s->hd, filename, flags); ++ ret = bdrv_file_open(&s->hd, filename, flags | BDRV_O_AUTOGROW); + if (ret < 0) + return ret; + if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header)) +diff -Nur kvm-62+dfsg/qemu/block-qcow2.c kvm-62+dfsg.new/qemu/block-qcow2.c +--- kvm-62+dfsg/qemu/block-qcow2.c 2008-02-25 04:30:14.000000000 -0500 ++++ kvm-62+dfsg.new/qemu/block-qcow2.c 2008-04-07 11:23:30.000000000 -0400 +@@ -191,7 +191,7 @@ + int len, i, shift, ret; + QCowHeader header; + +- ret = bdrv_file_open(&s->hd, filename, flags); ++ ret = bdrv_file_open(&s->hd, filename, flags | BDRV_O_AUTOGROW); + if (ret < 0) + return ret; + if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header)) +diff -Nur kvm-62+dfsg/qemu/block-vmdk.c kvm-62+dfsg.new/qemu/block-vmdk.c +--- kvm-62+dfsg/qemu/block-vmdk.c 2008-02-25 04:30:14.000000000 -0500 ++++ kvm-62+dfsg.new/qemu/block-vmdk.c 2008-04-07 11:23:30.000000000 -0400 +@@ -377,7 +377,7 @@ + flags = BDRV_O_RDONLY; + fprintf(stderr, "(VMDK) image open: flags=0x%x filename=%s\n", flags, bs->filename); + +- ret = bdrv_file_open(&s->hd, filename, flags); ++ ret = bdrv_file_open(&s->hd, filename, flags | BDRV_O_AUTOGROW); + if (ret < 0) + return ret; + if (bdrv_pread(s->hd, 0, &magic, sizeof(magic)) != sizeof(magic)) +diff -Nur kvm-62+dfsg/qemu/block.c kvm-62+dfsg.new/qemu/block.c +--- kvm-62+dfsg/qemu/block.c 2008-04-07 11:23:22.000000000 -0400 ++++ kvm-62+dfsg.new/qemu/block.c 2008-04-07 11:23:30.000000000 -0400 +@@ -124,6 +124,60 @@ + } + } + ++static int bdrv_rd_badreq_sectors(BlockDriverState *bs, ++ int64_t sector_num, int nb_sectors) ++{ ++ return ++ nb_sectors < 0 || ++ sector_num < 0 || ++ nb_sectors > bs->total_sectors || ++ sector_num > bs->total_sectors - nb_sectors; ++} ++ ++static int bdrv_rd_badreq_bytes(BlockDriverState *bs, ++ int64_t offset, int count) ++{ ++ int64_t size = bs->total_sectors << SECTOR_BITS; ++ return ++ count < 0 || ++ size < 0 || ++ count > size || ++ offset > size - count; ++} ++ ++static int bdrv_wr_badreq_sectors(BlockDriverState *bs, ++ int64_t sector_num, int nb_sectors) ++{ ++ if (sector_num < 0 || ++ nb_sectors < 0) ++ return 1; ++ ++ if (sector_num > bs->total_sectors - nb_sectors) { ++ if (bs->autogrow) ++ bs->total_sectors = sector_num + nb_sectors; ++ else ++ return 1; ++ } ++ return 0; ++} ++ ++static int bdrv_wr_badreq_bytes(BlockDriverState *bs, ++ int64_t offset, int count) ++{ ++ int64_t size = bs->total_sectors << SECTOR_BITS; ++ if (count < 0 || ++ offset < 0) ++ return 1; ++ ++ if (offset > size - count) { ++ if (bs->autogrow) ++ bs->total_sectors = (offset + count + SECTOR_SIZE - 1) >> SECTOR_BITS; ++ else ++ return 1; ++ } ++ return 0; ++} ++ + + static void bdrv_register(BlockDriver *bdrv) + { +@@ -332,6 +386,10 @@ + bs->read_only = 0; + bs->is_temporary = 0; + bs->encrypted = 0; ++ bs->autogrow = 0; ++ ++ if (flags & BDRV_O_AUTOGROW) ++ bs->autogrow = 1; + + if (flags & BDRV_O_SNAPSHOT) { + BlockDriverState *bs1; +@@ -376,6 +434,7 @@ + } + 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 +@@ -441,6 +500,7 @@ + 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); +@@ -506,6 +566,8 @@ + if (!drv) + return -ENOMEDIUM; + ++ if (bdrv_rd_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++; +@@ -548,6 +610,8 @@ + return -EACCES; + if (sector_num < 0) + return -EINVAL; ++ if (bdrv_wr_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); + } +@@ -679,6 +743,8 @@ + return -ENOMEDIUM; + if (!drv->bdrv_pread) + return bdrv_pread_em(bs, offset, buf1, count1); ++ if (bdrv_rd_badreq_bytes(bs, offset, count1)) ++ return -EDOM; + return drv->bdrv_pread(bs, offset, buf1, count1); + } + +@@ -694,6 +760,8 @@ + return -ENOMEDIUM; + if (!drv->bdrv_pwrite) + return bdrv_pwrite_em(bs, offset, buf1, count1); ++ if (bdrv_wr_badreq_bytes(bs, offset, count1)) ++ return -EDOM; + return drv->bdrv_pwrite(bs, offset, buf1, count1); + } + +@@ -1099,6 +1167,8 @@ + return -ENOMEDIUM; + if (!drv->bdrv_write_compressed) + return -ENOTSUP; ++ if (bdrv_wr_badreq_sectors(bs, sector_num, nb_sectors)) ++ return -EDOM; + return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors); + } + +@@ -1245,6 +1315,8 @@ + + if (!drv) + return NULL; ++ if (bdrv_rd_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) { +@@ -1276,6 +1348,8 @@ + return NULL; + if (bs->read_only) + return NULL; ++ if (bdrv_wr_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); + } +diff -Nur kvm-62+dfsg/qemu/block.h kvm-62+dfsg.new/qemu/block.h +--- kvm-62+dfsg/qemu/block.h 2008-02-25 04:30:14.000000000 -0500 ++++ kvm-62+dfsg.new/qemu/block.h 2008-04-07 11:23:30.000000000 -0400 +@@ -45,6 +45,7 @@ + it (default for + bdrv_file_open()) */ + #define BDRV_O_DIRECT 0x0020 ++#define BDRV_O_AUTOGROW 0x0040 /* Allow backing file to extend when writing past end of file */ + + #ifndef QEMU_IMG + void bdrv_info(void); +diff -Nur kvm-62+dfsg/qemu/block_int.h kvm-62+dfsg.new/qemu/block_int.h +--- kvm-62+dfsg/qemu/block_int.h 2008-02-25 04:30:14.000000000 -0500 ++++ kvm-62+dfsg.new/qemu/block_int.h 2008-04-07 11:23:30.000000000 -0400 +@@ -97,6 +97,7 @@ + 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 autogrow; /* if true, the backing store can auto-extend to allocate new extents */ + /* event callback when inserting/removing */ + void (*change_cb)(void *opaque); + void *change_opaque;