vhost: fix potential use-after-free for memory region
Reclaim outstanding zmbufs first before freeing memory regions,
otherwise there could be use-after-free.
Fixes: b0a985d1f3
("vhost: add dequeue zero copy")
Cc: stable@dpdk.org
Signed-off-by: Tiwei Bie <tiwei.bie@intel.com>
Reviewed-by: Maxime Coquelin <maxime.coquelin@redhat.com>
This commit is contained in:
parent
d767436ee5
commit
2a2904fa9c
@ -769,4 +769,10 @@ mbuf_is_consumed(struct rte_mbuf *m)
|
||||
return true;
|
||||
}
|
||||
|
||||
static __rte_always_inline void
|
||||
put_zmbuf(struct zcopy_mbuf *zmbuf)
|
||||
{
|
||||
zmbuf->in_use = 0;
|
||||
}
|
||||
|
||||
#endif /* _VHOST_NET_CDEV_H_ */
|
||||
|
@ -93,15 +93,47 @@ get_blk_size(int fd)
|
||||
return ret == -1 ? (uint64_t)-1 : (uint64_t)stat.st_blksize;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reclaim all the outstanding zmbufs for a virtqueue.
|
||||
*/
|
||||
static void
|
||||
drain_zmbuf_list(struct vhost_virtqueue *vq)
|
||||
{
|
||||
struct zcopy_mbuf *zmbuf, *next;
|
||||
|
||||
for (zmbuf = TAILQ_FIRST(&vq->zmbuf_list);
|
||||
zmbuf != NULL; zmbuf = next) {
|
||||
next = TAILQ_NEXT(zmbuf, next);
|
||||
|
||||
while (!mbuf_is_consumed(zmbuf->mbuf))
|
||||
usleep(1000);
|
||||
|
||||
TAILQ_REMOVE(&vq->zmbuf_list, zmbuf, next);
|
||||
restore_mbuf(zmbuf->mbuf);
|
||||
rte_pktmbuf_free(zmbuf->mbuf);
|
||||
put_zmbuf(zmbuf);
|
||||
vq->nr_zmbuf -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
free_mem_region(struct virtio_net *dev)
|
||||
{
|
||||
uint32_t i;
|
||||
struct rte_vhost_mem_region *reg;
|
||||
struct vhost_virtqueue *vq;
|
||||
|
||||
if (!dev || !dev->mem)
|
||||
return;
|
||||
|
||||
if (dev->dequeue_zero_copy) {
|
||||
for (i = 0; i < dev->nr_vring; i++) {
|
||||
vq = dev->virtqueue[i];
|
||||
if (vq)
|
||||
drain_zmbuf_list(vq);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < dev->mem->nregions; i++) {
|
||||
reg = &dev->mem->regions[i];
|
||||
if (reg->host_user_addr) {
|
||||
@ -1212,19 +1244,7 @@ vhost_user_set_vring_kick(struct virtio_net **pdev, struct VhostUserMsg *msg,
|
||||
static void
|
||||
free_zmbufs(struct vhost_virtqueue *vq)
|
||||
{
|
||||
struct zcopy_mbuf *zmbuf, *next;
|
||||
|
||||
for (zmbuf = TAILQ_FIRST(&vq->zmbuf_list);
|
||||
zmbuf != NULL; zmbuf = next) {
|
||||
next = TAILQ_NEXT(zmbuf, next);
|
||||
|
||||
while (!mbuf_is_consumed(zmbuf->mbuf))
|
||||
usleep(1000);
|
||||
|
||||
restore_mbuf(zmbuf->mbuf);
|
||||
rte_pktmbuf_free(zmbuf->mbuf);
|
||||
TAILQ_REMOVE(&vq->zmbuf_list, zmbuf, next);
|
||||
}
|
||||
drain_zmbuf_list(vq);
|
||||
|
||||
rte_free(vq->zmbufs);
|
||||
}
|
||||
|
@ -1063,12 +1063,6 @@ vhost_dequeue_offload(struct virtio_net_hdr *hdr, struct rte_mbuf *m)
|
||||
}
|
||||
}
|
||||
|
||||
static __rte_always_inline void
|
||||
put_zmbuf(struct zcopy_mbuf *zmbuf)
|
||||
{
|
||||
zmbuf->in_use = 0;
|
||||
}
|
||||
|
||||
static __rte_always_inline int
|
||||
copy_desc_to_mbuf(struct virtio_net *dev, struct vhost_virtqueue *vq,
|
||||
struct buf_vector *buf_vec, uint16_t nr_vec,
|
||||
|
Loading…
Reference in New Issue
Block a user