Skip to content

Commit cf29e0f

Browse files
Alexandra Iordachedianpopa
authored andcommitted
virtio blk: check descriptor valid addresses...
...when parsing an operation request. The `status` and `data` (if present) descriptors' addresses were not validated, relying on the assumption that the guest driver sends valid buffers in the virtq. An `unwrap` in the block device's `process_queue` function may have failed on invalid input. This commit adds an extra validation for the descriptors' addresses. The `data` descriptor must point to a valid address in the guest's physical memory space, with enough room to fit the data (specified by `data.len`). The `status` descriptor must also point at a valid address which fits the 4-byte status written there by the device after processing the request. Signed-off-by: Alexandra Iordache <[email protected]>
1 parent 263bc0c commit cf29e0f

File tree

1 file changed

+49
-4
lines changed

1 file changed

+49
-4
lines changed

src/devices/src/virtio/block/request.rs

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77

88
use std::convert::From;
99
use std::io::{self, Read, Seek, SeekFrom, Write};
10+
use std::mem;
1011
use std::result;
1112

1213
use logger::{Metric, METRICS};
1314
use virtio_gen::virtio_blk::*;
14-
use vm_memory::{ByteValued, Bytes, GuestAddress, GuestMemoryError, GuestMemoryMmap};
15+
use vm_memory::{ByteValued, Bytes, GuestAddress, GuestMemory, GuestMemoryError, GuestMemoryMmap};
1516

1617
use super::super::DescriptorChain;
1718
use super::{Error, SECTOR_SHIFT, SECTOR_SIZE};
@@ -157,6 +158,13 @@ impl Request {
157158
return Err(Error::UnexpectedReadOnlyDescriptor);
158159
}
159160

161+
// Check that the address of the data descriptor is valid in guest memory.
162+
let _ = mem
163+
.checked_offset(data_desc.addr, data_desc.len as usize)
164+
.ok_or(Error::GuestMemory(GuestMemoryError::InvalidGuestAddress(
165+
data_desc.addr,
166+
)))?;
167+
160168
req.data_addr = data_desc.addr;
161169
req.data_len = data_desc.len;
162170
}
@@ -170,6 +178,14 @@ impl Request {
170178
return Err(Error::DescriptorLengthTooSmall);
171179
}
172180

181+
// Check that the address of the status descriptor is valid in guest memory.
182+
// We will write an u32 status here after executing the request.
183+
let _ = mem
184+
.checked_offset(status_desc.addr, mem::size_of::<u32>())
185+
.ok_or(Error::GuestMemory(GuestMemoryError::InvalidGuestAddress(
186+
status_desc.addr,
187+
)))?;
188+
173189
req.status_addr = status_desc.addr;
174190

175191
Ok(req)
@@ -234,7 +250,7 @@ impl Request {
234250
mod tests {
235251
use super::*;
236252
use crate::virtio::queue::tests::*;
237-
use vm_memory::GuestAddress;
253+
use vm_memory::{Address, GuestAddress};
238254

239255
#[test]
240256
fn test_read_request_header() {
@@ -303,6 +319,7 @@ mod tests {
303319
}
304320

305321
#[test]
322+
#[allow(clippy::cognitive_complexity)]
306323
fn test_parse() {
307324
let m = &GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
308325
let vq = VirtQueue::new(GuestAddress(0), &m, 16);
@@ -413,10 +430,38 @@ mod tests {
413430

414431
{
415432
let mut q = vq.create_queue();
416-
// Should be OK now.
433+
// Fix status descriptor length.
417434
vq.dtable[status_descriptor].len.set(0x1000);
418-
let r = Request::parse(&q.pop(m).unwrap(), m).unwrap();
435+
// Invalid guest address for the status descriptor.
436+
vq.dtable[status_descriptor]
437+
.addr
438+
.set(m.last_addr().raw_value());
439+
assert!(match Request::parse(&q.pop(m).unwrap(), m) {
440+
Err(Error::GuestMemory(GuestMemoryError::InvalidGuestAddress(_))) => true,
441+
_ => false,
442+
});
443+
}
444+
445+
{
446+
let mut q = vq.create_queue();
447+
// Restore status descriptor.
448+
vq.dtable[status_descriptor].set(0x3000, 0x1000, VIRTQ_DESC_F_WRITE, 0);
449+
// Invalid guest address for the data descriptor.
450+
vq.dtable[data_descriptor]
451+
.addr
452+
.set(m.last_addr().raw_value());
453+
assert!(match Request::parse(&q.pop(m).unwrap(), m) {
454+
Err(Error::GuestMemory(GuestMemoryError::InvalidGuestAddress(_))) => true,
455+
_ => false,
456+
});
457+
}
419458

459+
{
460+
let mut q = vq.create_queue();
461+
// Restore data descriptor.
462+
vq.dtable[data_descriptor].addr.set(0x2000);
463+
// Should be OK now.
464+
let r = Request::parse(&q.pop(m).unwrap(), m).unwrap();
420465
assert_eq!(r.request_type, RequestType::In);
421466
assert_eq!(r.sector, 114);
422467
assert_eq!(r.data_addr, GuestAddress(0x2000));

0 commit comments

Comments
 (0)