Skip to content

Commit eccb86a

Browse files
committed
vhost: fix receiving reply payloads
The existing code confuses the length of the request with the length of the reply in recv_reply_with_payload. This makes it impossible to use for any requests where the reply differs in size. Fix this by determining payload size after reading the reply header. Signed-off-by: Alyssa Ross <hi@alyssa.is> Signed-off-by: Albert Esteve <aesteve@redhat.com>
1 parent 07762af commit eccb86a

File tree

3 files changed

+21
-38
lines changed

3 files changed

+21
-38
lines changed

vhost/src/vhost_user/connection.rs

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ impl<H: MsgHeader> Endpoint<H> {
546546
/// accepted and all other file descriptor will be discard silently.
547547
///
548548
/// # Return:
549-
/// * - (message header, message body, size of payload, [received files]) on success.
549+
/// * - (message header, message body, payload, [received files]) on success.
550550
/// * - SocketRetry: temporary error caused by signals or short of resources.
551551
/// * - SocketBroken: the underline socket is broken.
552552
/// * - SocketError: other socket related errors.
@@ -555,15 +555,13 @@ impl<H: MsgHeader> Endpoint<H> {
555555
#[allow(clippy::type_complexity)]
556556
pub fn recv_payload_into_buf<T: ByteValued + Sized + VhostUserMsgValidator + Default>(
557557
&mut self,
558-
buf: &mut [u8],
559-
) -> Result<(H, T, usize, Option<Vec<File>>)> {
560-
let mut hdr = H::default();
558+
) -> Result<(H, T, Vec<u8>, Option<Vec<File>>)> {
561559
let mut body: T = Default::default();
560+
let (hdr, files) = self.recv_header()?;
561+
562+
let payload_size = hdr.get_size() as usize - mem::size_of::<T>();
563+
let mut buf: Vec<u8> = vec![0; payload_size];
562564
let mut iovs = [
563-
iovec {
564-
iov_base: (&mut hdr as *mut H) as *mut c_void,
565-
iov_len: mem::size_of::<H>(),
566-
},
567565
iovec {
568566
iov_base: (&mut body as *mut T) as *mut c_void,
569567
iov_len: mem::size_of::<T>(),
@@ -573,19 +571,16 @@ impl<H: MsgHeader> Endpoint<H> {
573571
iov_len: buf.len(),
574572
},
575573
];
576-
// SAFETY: Safe because we own hdr and body and have a mutable borrow of buf, and
577-
// hdr and body are ByteValued, and it's safe to fill a byte slice with
578-
// arbitrary data.
579-
let (bytes, files) = unsafe { self.recv_into_iovec_all(&mut iovs[..])? };
580-
581-
let total = mem::size_of::<H>() + mem::size_of::<T>();
582-
if bytes < total {
574+
// SAFETY: Safe because we own body and buf, and body is ByteValued, and it's safe
575+
// to fill a byte slice with arbitrary data.
576+
let (bytes, more_files) = unsafe { self.recv_into_iovec_all(&mut iovs)? };
577+
if bytes < hdr.get_size() as usize {
583578
return Err(Error::PartialMessage);
584-
} else if !hdr.is_valid() || !body.is_valid() {
579+
} else if !body.is_valid() || more_files.is_some() {
585580
return Err(Error::InvalidMessage);
586581
}
587582

588-
Ok((hdr, body, bytes - total, files))
583+
Ok((hdr, body, buf, files))
589584
}
590585
}
591586

vhost/src/vhost_user/frontend.rs

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -769,23 +769,13 @@ impl FrontendInternal {
769769
&mut self,
770770
hdr: &VhostUserMsgHeader<FrontendReq>,
771771
) -> VhostUserResult<(T, Vec<u8>, Option<Vec<File>>)> {
772-
if mem::size_of::<T>() > MAX_MSG_SIZE
773-
|| hdr.get_size() as usize <= mem::size_of::<T>()
774-
|| hdr.get_size() as usize > MAX_MSG_SIZE
775-
|| hdr.is_reply()
776-
{
772+
if mem::size_of::<T>() > MAX_MSG_SIZE || hdr.is_reply() {
777773
return Err(VhostUserError::InvalidParam);
778774
}
779775
self.check_state()?;
780776

781-
let mut buf: Vec<u8> = vec![0; hdr.get_size() as usize - mem::size_of::<T>()];
782-
let (reply, body, bytes, files) = self.main_sock.recv_payload_into_buf::<T>(&mut buf)?;
783-
if !reply.is_reply_for(hdr)
784-
|| reply.get_size() as usize != mem::size_of::<T>() + bytes
785-
|| files.is_some()
786-
|| !body.is_valid()
787-
|| bytes != buf.len()
788-
{
777+
let (reply, body, buf, files) = self.main_sock.recv_payload_into_buf::<T>()?;
778+
if !reply.is_reply_for(hdr) || files.is_some() || !body.is_valid() {
789779
return Err(VhostUserError::InvalidMessage);
790780
}
791781

vhost/src/vhost_user/gpu_backend_req.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -437,9 +437,8 @@ mod tests {
437437
let _: () = backend.update_scanout(&request, &payload).unwrap();
438438
});
439439

440-
let mut recv_buf = [0u8; 4096];
441-
let (hdr, req_body, recv_buf_len, fds) = frontend
442-
.recv_payload_into_buf::<VhostUserGpuUpdate>(&mut recv_buf)
440+
let (hdr, req_body, recv_buf, fds) = frontend
441+
.recv_payload_into_buf::<VhostUserGpuUpdate>()
443442
.unwrap();
444443
assert!(fds.is_none());
445444
assert_hdr(
@@ -449,7 +448,7 @@ mod tests {
449448
);
450449
assert_eq!(req_body, request);
451450

452-
assert_eq!(&payload[..], &recv_buf[..recv_buf_len]);
451+
assert_eq!(&payload[..], recv_buf);
453452

454453
sender_thread.join().expect("Failed to send!");
455454
}
@@ -611,9 +610,8 @@ mod tests {
611610
let _: () = backend.cursor_update(&request, &payload).unwrap();
612611
});
613612

614-
let mut recv_buf = vec![0u8; 1 + size_of_val(&payload)];
615-
let (hdr, req_body, recv_buf_len, fds) = frontend
616-
.recv_payload_into_buf::<VhostUserGpuCursorUpdate>(&mut recv_buf)
613+
let (hdr, req_body, recv_buf, fds) = frontend
614+
.recv_payload_into_buf::<VhostUserGpuCursorUpdate>()
617615
.unwrap();
618616
assert!(fds.is_none());
619617
assert_hdr(
@@ -623,7 +621,7 @@ mod tests {
623621
);
624622
assert_eq!(req_body, request);
625623

626-
assert_eq!(&payload[..], &recv_buf[..recv_buf_len]);
624+
assert_eq!(&payload[..], recv_buf);
627625

628626
sender_thread.join().expect("Failed to send!");
629627
}

0 commit comments

Comments
 (0)