diff mbox

[3/3] virtio-blk: Treat read/write beyond end as invalid

Message ID 1401970536-18019-4-git-send-email-armbru@redhat.com
State New
Headers show

Commit Message

Markus Armbruster June 5, 2014, 12:15 p.m. UTC
The block layer fails such reads and writes just fine.  However, they
then get treated like valid operations that fail: the error action
gets executed.  Unwanted; reporting the error to the guest is the only
sensible action.

Reject them before passing them to the block layer.  This bypasses the
error action and I/O accounting.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 hw/block/virtio-blk.c | 7 +++++++
 1 file changed, 7 insertions(+)

Comments

Fam Zheng June 6, 2014, 3:21 a.m. UTC | #1
On Thu, 06/05 14:15, Markus Armbruster wrote:
> The block layer fails such reads and writes just fine.  However, they
> then get treated like valid operations that fail: the error action
> gets executed.  Unwanted; reporting the error to the guest is the only
> sensible action.
> 
> Reject them before passing them to the block layer.  This bypasses the
> error action and I/O accounting.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  hw/block/virtio-blk.c | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
> index 2c68d0d..0b38049 100644
> --- a/hw/block/virtio-blk.c
> +++ b/hw/block/virtio-blk.c
> @@ -284,12 +284,19 @@ static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb)
>  static bool virtio_blk_sect_range_ok(VirtIOBlock *dev,
>                                       uint64_t sector, size_t size)
>  {
> +    uint64_t nb_sectors = size >> BDRV_SECTOR_BITS;
> +    uint64_t total_sectors;
> +
>      if (sector & dev->sector_mask) {
>          return false;
>      }
>      if (size % dev->conf->logical_block_size) {
>          return false;
>      }
> +    bdrv_get_geometry(dev->bs, &total_sectors);
> +    if (sector > total_sectors || nb_sectors > total_sectors - sector) {
> +        return false;
> +    }
>      return true;
>  }
>  
> -- 
> 1.9.3
> 
> 

Reviewed-by: Fam Zheng <famz@redhat.com>
Stefan Hajnoczi June 20, 2014, 4:16 a.m. UTC | #2
On Thu, Jun 05, 2014 at 02:15:36PM +0200, Markus Armbruster wrote:
> +    if (sector > total_sectors || nb_sectors > total_sectors - sector) {
> +        return false;
> +    }

if (sector >= total_sectors || ...) {
Markus Armbruster June 23, 2014, 8:47 a.m. UTC | #3
Stefan Hajnoczi <stefanha@redhat.com> writes:

> On Thu, Jun 05, 2014 at 02:15:36PM +0200, Markus Armbruster wrote:
>> +    if (sector > total_sectors || nb_sectors > total_sectors - sector) {
>> +        return false;
>> +    }
>
> if (sector >= total_sectors || ...) {

I suspect reading bdrv_check_byte_request() put the '>' in my brain:

    if ((offset > len) || (len - offset < size))
        return -EIO;

Don't we need offset >= len here?
Markus Armbruster June 23, 2014, 12:57 p.m. UTC | #4
Markus Armbruster <armbru@redhat.com> writes:

> Stefan Hajnoczi <stefanha@redhat.com> writes:
>
>> On Thu, Jun 05, 2014 at 02:15:36PM +0200, Markus Armbruster wrote:
>>> +    if (sector > total_sectors || nb_sectors > total_sectors - sector) {
>>> +        return false;
>>> +    }
>>
>> if (sector >= total_sectors || ...) {
>
> I suspect reading bdrv_check_byte_request() put the '>' in my brain:
>
>     if ((offset > len) || (len - offset < size))
>         return -EIO;
>
> Don't we need offset >= len here?

Just remembered: we don't, because we allow I/O at offset len provided
size is zero.

Same reasoning applies to my patch.
Stefan Hajnoczi June 27, 2014, 9:56 a.m. UTC | #5
On Mon, Jun 23, 2014 at 02:57:36PM +0200, Markus Armbruster wrote:
> Markus Armbruster <armbru@redhat.com> writes:
> 
> > Stefan Hajnoczi <stefanha@redhat.com> writes:
> >
> >> On Thu, Jun 05, 2014 at 02:15:36PM +0200, Markus Armbruster wrote:
> >>> +    if (sector > total_sectors || nb_sectors > total_sectors - sector) {
> >>> +        return false;
> >>> +    }
> >>
> >> if (sector >= total_sectors || ...) {
> >
> > I suspect reading bdrv_check_byte_request() put the '>' in my brain:
> >
> >     if ((offset > len) || (len - offset < size))
> >         return -EIO;
> >
> > Don't we need offset >= len here?
> 
> Just remembered: we don't, because we allow I/O at offset len provided
> size is zero.
> 
> Same reasoning applies to my patch.

Okay.  I didn't remember the offset=eof length=0 thing.

Stefan
diff mbox

Patch

diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 2c68d0d..0b38049 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -284,12 +284,19 @@  static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb)
 static bool virtio_blk_sect_range_ok(VirtIOBlock *dev,
                                      uint64_t sector, size_t size)
 {
+    uint64_t nb_sectors = size >> BDRV_SECTOR_BITS;
+    uint64_t total_sectors;
+
     if (sector & dev->sector_mask) {
         return false;
     }
     if (size % dev->conf->logical_block_size) {
         return false;
     }
+    bdrv_get_geometry(dev->bs, &total_sectors);
+    if (sector > total_sectors || nb_sectors > total_sectors - sector) {
+        return false;
+    }
     return true;
 }