bhyve: avoid TOCTOU on iov_len in virtio_vq_recordon()

Avoid a race condition when accessing guest memory, by reading memory
contents only once.

This has also been applied to _vq_record() in
sys/dev/beri/virtio/virtio.c, as per markj@'s suggestion.

Reported by:	Synacktiv
Reviewed by:	markj
Security:	HYP-10
Sponsored by:	The Alpha-Omega Project
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D45735
This commit is contained in:
Pierre Pronchery 2024-08-27 15:57:32 +02:00 committed by Ed Maste
parent 94693ec7c8
commit 869d760cb9
2 changed files with 15 additions and 5 deletions

View file

@ -106,12 +106,17 @@ paddr_unmap(void *phys, uint32_t size)
static inline void
_vq_record(uint32_t offs, int i, volatile struct vring_desc *vd,
struct iovec *iov, int n_iov, uint16_t *flags) {
uint32_t len;
uint64_t addr;
if (i >= n_iov)
return;
iov[i].iov_base = paddr_map(offs, be64toh(vd->addr),
be32toh(vd->len));
iov[i].iov_len = be32toh(vd->len);
len = atomic_load_32(&vd->len);
addr = atomic_load_64(&vd->addr);
iov[i].iov_base = paddr_map(offs, be64toh(addr),
be32toh(len));
iov[i].iov_len = be32toh(len);
if (flags != NULL)
flags[i] = be16toh(vd->flags);
}

View file

@ -216,10 +216,15 @@ static inline void
_vq_record(int i, struct vring_desc *vd, struct vmctx *ctx, struct iovec *iov,
int n_iov, struct vi_req *reqp)
{
uint32_t len;
uint64_t addr;
if (i >= n_iov)
return;
iov[i].iov_base = paddr_guest2host(ctx, vd->addr, vd->len);
iov[i].iov_len = vd->len;
len = atomic_load_32(&vd->len);
addr = atomic_load_64(&vd->addr);
iov[i].iov_len = len;
iov[i].iov_base = paddr_guest2host(ctx, addr, len);
if ((vd->flags & VRING_DESC_F_WRITE) == 0)
reqp->readable++;
else