@@ -103,7 +103,7 @@ static void virtio_blk_complete_request(struct virtq *vq)
103103 struct vring_packed_desc * used_desc = desc ;
104104 ssize_t io_bytes = 0 ;
105105
106- void * hdr = vm_guest_to_host (v , desc -> addr );
106+ void * hdr = vm_guest_buf (v , desc -> addr , hdr_sz );
107107 if (!hdr || desc -> len < hdr_sz )
108108 return ;
109109 memcpy (& req , hdr , hdr_sz );
@@ -112,33 +112,48 @@ static void virtio_blk_complete_request(struct virtq *vq)
112112 return ;
113113 desc = virtq_get_avail (vq );
114114 req .data_size = desc -> len ;
115- req .data = vm_guest_to_host (v , desc -> addr );
116- if (!req .data )
117- return ;
118-
119- if (req .type == VIRTIO_BLK_T_IN )
120- io_bytes = virtio_blk_read (dev , req .data , req .sector << 9 ,
121- req .data_size );
122- else
123- io_bytes = virtio_blk_write (dev , req .data , req .sector << 9 ,
124- req .data_size );
125-
126- status = io_bytes < 0 ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK ;
115+ req .data = vm_guest_buf (v , desc -> addr , req .data_size );
116+
117+ /* Validate that the request fits in the backing store. Both the
118+ * shift (sector*512) and the addition (offset+data_size) must not
119+ * overflow, and the end must be within diskimg->size. Any failure
120+ * yields VIRTIO_BLK_S_IOERR with no data transferred. */
121+ uint64_t off , end ;
122+ bool io_ok = false;
123+ if (req .data && !__builtin_mul_overflow (req .sector , 512 , & off ) &&
124+ !__builtin_add_overflow (off , req .data_size , & end ) &&
125+ end <= (uint64_t ) dev -> diskimg -> size ) {
126+ if (req .type == VIRTIO_BLK_T_IN )
127+ io_bytes = virtio_blk_read (dev , req .data , (off_t ) off ,
128+ req .data_size );
129+ else
130+ io_bytes = virtio_blk_write (dev , req .data , (off_t ) off ,
131+ req .data_size );
132+ /* A short read/write leaves part of the guest buffer stale,
133+ * so treat anything less than the full request as IOERR. */
134+ io_ok = io_bytes >= 0 && (size_t ) io_bytes == req .data_size ;
135+ }
136+ status = io_ok ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR ;
127137 } else {
128138 status = VIRTIO_BLK_S_UNSUPP ;
129139 }
130140 if (!virtq_check_next (desc ))
131141 return ;
132142 desc = virtq_get_avail (vq );
133- req .status = vm_guest_to_host (v , desc -> addr );
143+ /* The status descriptor must advertise at least one device-writable
144+ * byte; otherwise we'd clobber memory the guest did not offer. */
145+ if (desc -> len < 1 )
146+ return ;
147+ req .status = vm_guest_buf (v , desc -> addr , 1 );
134148 if (!req .status )
135149 return ;
136150 * req .status = status ;
137151 /* used.len is total bytes the device wrote into device-writable
138152 * buffers across the chain: the 1-byte status is always written, plus
139- * io_bytes of data on a successful IN. */
153+ * the data buffer on a successful IN. On any error we report only the
154+ * status byte so the guest does not consume stale data. */
140155 size_t written = 1 ;
141- if (req . type == VIRTIO_BLK_T_IN && io_bytes > 0 )
156+ if (status == VIRTIO_BLK_S_OK && req . type == VIRTIO_BLK_T_IN )
142157 written += (size_t ) io_bytes ;
143158 used_desc -> len = (uint32_t ) written ;
144159 used_desc -> flags ^= (1ULL << VRING_PACKED_DESC_F_USED );
0 commit comments