@@ -19,7 +19,7 @@ use logger::{Metric, METRICS};
1919use rate_limiter:: { RateLimiter , TokenType } ;
2020use utils:: eventfd:: EventFd ;
2121use virtio_gen:: virtio_blk:: * ;
22- use vm_memory:: { Bytes , GuestMemoryMmap } ;
22+ use vm_memory:: { Bytes , GuestMemoryError , GuestMemoryMmap } ;
2323
2424use super :: {
2525 super :: { ActivateResult , DeviceState , Queue , VirtioDevice , TYPE_BLOCK , VIRTIO_MMIO_INT_VRING } ,
@@ -220,13 +220,43 @@ impl Block {
220220 & self . disk_image_id ,
221221 ) {
222222 Ok ( l) => {
223- len = l;
224- VIRTIO_BLK_S_OK
223+ // Account for the status byte as well.
224+ // With a non-faulty driver, we shouldn't get to the point where we
225+ // overflow here (since data len must be a multiple of 512 bytes, so
226+ // it can't be u32::MAX). In the future, this should be fixed at the
227+ // request parsing level, so no data will actually be transferred in
228+ // scenarios like this one.
229+ if let Some ( l) = l. checked_add ( 1 ) {
230+ len = l;
231+ VIRTIO_BLK_S_OK
232+ } else {
233+ len = l;
234+ VIRTIO_BLK_S_IOERR
235+ }
225236 }
226237 Err ( e) => {
227- error ! ( "Failed to execute request: {:?}" , e) ;
228238 METRICS . block . invalid_reqs_count . inc ( ) ;
229- len = 1 ; // We need at least 1 byte for the status.
239+ match e {
240+ ExecuteError :: Read ( GuestMemoryError :: PartialBuffer {
241+ completed,
242+ expected,
243+ } ) => {
244+ error ! (
245+ "Failed to execute virtio block read request: can only \
246+ write {} of {} bytes.",
247+ completed, expected
248+ ) ;
249+ METRICS . block . read_bytes . add ( completed) ;
250+ // This can not overflow since `completed` < data len which is
251+ // an u32.
252+ len = completed as u32 + 1 ;
253+ }
254+ _ => {
255+ error ! ( "Failed to execute virtio block request: {:?}" , e) ;
256+ // Status byte only.
257+ len = 1 ;
258+ }
259+ } ;
230260 e. status ( )
231261 }
232262 } ;
@@ -702,7 +732,7 @@ pub(crate) mod tests {
702732
703733 assert_eq ! ( vq. used. idx. get( ) , 1 ) ;
704734 assert_eq ! ( vq. used. ring[ 0 ] . get( ) . id, 0 ) ;
705- assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 0 ) ;
735+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 1 ) ;
706736 assert_eq ! ( mem. read_obj:: <u32 >( status_addr) . unwrap( ) , VIRTIO_BLK_S_OK ) ;
707737 }
708738
@@ -725,10 +755,100 @@ pub(crate) mod tests {
725755
726756 assert_eq ! ( vq. used. idx. get( ) , 1 ) ;
727757 assert_eq ! ( vq. used. ring[ 0 ] . get( ) . id, 0 ) ;
728- assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, vq. dtable[ 1 ] . len. get( ) ) ;
758+ // Added status byte length.
759+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, vq. dtable[ 1 ] . len. get( ) + 1 ) ;
729760 assert_eq ! ( mem. read_obj:: <u32 >( status_addr) . unwrap( ) , VIRTIO_BLK_S_OK ) ;
761+ }
762+
763+ // Read with error.
764+ {
765+ vq. used . idx . set ( 0 ) ;
766+ block. set_queue ( 0 , vq. create_queue ( ) ) ;
767+
768+ mem. write_obj :: < u32 > ( VIRTIO_BLK_T_IN , request_type_addr)
769+ . unwrap ( ) ;
770+ vq. dtable [ 1 ]
771+ . flags
772+ . set ( VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE ) ;
773+
774+ let size = block. disk_image . seek ( SeekFrom :: End ( 0 ) ) . unwrap ( ) ;
775+ block. disk_image . set_len ( size / 2 ) . unwrap ( ) ;
776+ mem. write_obj ( 10 , GuestAddress ( request_type_addr. 0 + 8 ) )
777+ . unwrap ( ) ;
778+
779+ invoke_handler_for_queue_event ( & mut block) ;
780+
781+ assert_eq ! ( vq. used. idx. get( ) , 1 ) ;
782+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . id, 0 ) ;
783+
784+ // Only status byte length.
785+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 1 ) ;
786+ assert_eq ! (
787+ mem. read_obj:: <u32 >( status_addr) . unwrap( ) ,
788+ VIRTIO_BLK_S_IOERR
789+ ) ;
730790 assert_eq ! ( mem. read_obj:: <u64 >( data_addr) . unwrap( ) , 123_456_789 ) ;
731791 }
792+
793+ // Partial buffer error on read.
794+ {
795+ vq. used . idx . set ( 0 ) ;
796+ block. set_queue ( 0 , vq. create_queue ( ) ) ;
797+
798+ mem. write_obj :: < u32 > ( VIRTIO_BLK_T_IN , request_type_addr)
799+ . unwrap ( ) ;
800+ vq. dtable [ 1 ]
801+ . flags
802+ . set ( VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE ) ;
803+
804+ let size = block. disk_image . seek ( SeekFrom :: End ( 0 ) ) . unwrap ( ) ;
805+ block. disk_image . set_len ( size / 2 ) . unwrap ( ) ;
806+ // Update sector number: stored at `request_type_addr.0 + 8`
807+ mem. write_obj ( 5 , GuestAddress ( request_type_addr. 0 + 8 ) )
808+ . unwrap ( ) ;
809+
810+ // This will attempt to read past end of file.
811+ invoke_handler_for_queue_event ( & mut block) ;
812+
813+ assert_eq ! ( vq. used. idx. get( ) , 1 ) ;
814+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . id, 0 ) ;
815+
816+ // No data since can't read past end of file, only status byte length.
817+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 1 ) ;
818+ assert_eq ! (
819+ mem. read_obj:: <u32 >( status_addr) . unwrap( ) ,
820+ VIRTIO_BLK_S_IOERR
821+ ) ;
822+ assert_eq ! ( mem. read_obj:: <u64 >( data_addr) . unwrap( ) , 123_456_789 ) ;
823+ }
824+
825+ {
826+ vq. used . idx . set ( 0 ) ;
827+ block. set_queue ( 0 , vq. create_queue ( ) ) ;
828+
829+ mem. write_obj :: < u32 > ( VIRTIO_BLK_T_IN , request_type_addr)
830+ . unwrap ( ) ;
831+ vq. dtable [ 1 ]
832+ . flags
833+ . set ( VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE ) ;
834+ vq. dtable [ 1 ] . len . set ( 1024 ) ;
835+
836+ mem. write_obj ( 1 , GuestAddress ( request_type_addr. 0 + 8 ) )
837+ . unwrap ( ) ;
838+
839+ invoke_handler_for_queue_event ( & mut block) ;
840+
841+ assert_eq ! ( vq. used. idx. get( ) , 1 ) ;
842+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . id, 0 ) ;
843+
844+ // File has 2 sectors and we try to read from the second sector, which means we will
845+ // read 512 bytes (instead of 1024).
846+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 513 ) ;
847+ assert_eq ! (
848+ mem. read_obj:: <u32 >( status_addr) . unwrap( ) ,
849+ VIRTIO_BLK_S_IOERR
850+ ) ;
851+ }
732852 }
733853
734854 #[ test]
@@ -753,7 +873,7 @@ pub(crate) mod tests {
753873 invoke_handler_for_queue_event ( & mut block) ;
754874 assert_eq ! ( vq. used. idx. get( ) , 1 ) ;
755875 assert_eq ! ( vq. used. ring[ 0 ] . get( ) . id, 0 ) ;
756- assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 0 ) ;
876+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 1 ) ;
757877 assert_eq ! ( mem. read_obj:: <u32 >( status_addr) . unwrap( ) , VIRTIO_BLK_S_OK ) ;
758878 }
759879
@@ -769,7 +889,8 @@ pub(crate) mod tests {
769889 invoke_handler_for_queue_event ( & mut block) ;
770890 assert_eq ! ( vq. used. idx. get( ) , 1 ) ;
771891 assert_eq ! ( vq. used. ring[ 0 ] . get( ) . id, 0 ) ;
772- assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 0 ) ;
892+ // status byte length.
893+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 1 ) ;
773894 assert_eq ! ( mem. read_obj:: <u32 >( status_addr) . unwrap( ) , VIRTIO_BLK_S_OK ) ;
774895 }
775896 }
@@ -798,7 +919,7 @@ pub(crate) mod tests {
798919 invoke_handler_for_queue_event ( & mut block) ;
799920 assert_eq ! ( vq. used. idx. get( ) , 1 ) ;
800921 assert_eq ! ( vq. used. ring[ 0 ] . get( ) . id, 0 ) ;
801- assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 0 ) ;
922+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 21 ) ;
802923 assert_eq ! ( mem. read_obj:: <u32 >( status_addr) . unwrap( ) , VIRTIO_BLK_S_OK ) ;
803924
804925 assert ! ( blk_metadata. is_ok( ) ) ;
@@ -900,7 +1021,7 @@ pub(crate) mod tests {
9001021 // Make sure the data queue advanced.
9011022 assert_eq ! ( vq. used. idx. get( ) , 1 ) ;
9021023 assert_eq ! ( vq. used. ring[ 0 ] . get( ) . id, 0 ) ;
903- assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 0 ) ;
1024+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 1 ) ;
9041025 assert_eq ! ( mem. read_obj:: <u32 >( status_addr) . unwrap( ) , VIRTIO_BLK_S_OK ) ;
9051026 }
9061027 }
@@ -979,7 +1100,7 @@ pub(crate) mod tests {
9791100 // Make sure the data queue advanced.
9801101 assert_eq ! ( vq. used. idx. get( ) , 1 ) ;
9811102 assert_eq ! ( vq. used. ring[ 0 ] . get( ) . id, 0 ) ;
982- assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 0 ) ;
1103+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 1 ) ;
9831104 assert_eq ! ( mem. read_obj:: <u32 >( status_addr) . unwrap( ) , VIRTIO_BLK_S_OK ) ;
9841105 }
9851106 }
0 commit comments