Commit c38e39c378f46f00ce922dd40a91043a9925c28d

Authored by Michael S. Tsirkin
1 parent 8bb495e3f0

vhost-net: fix use-after-free in vhost_net_flush

vhost_net_ubuf_put_and_wait has a confusing name:
it will actually also free it's argument.
Thus since commit 1280c27f8e29acf4af2da914e80ec27c3dbd5c01
    "vhost-net: flush outstanding DMAs on memory change"
vhost_net_flush tries to use the argument after passing it
to vhost_net_ubuf_put_and_wait, this results
in use after free.
To fix, don't free the argument in vhost_net_ubuf_put_and_wait,
add an new API for callers that want to free ubufs.

Acked-by: Asias He <asias@redhat.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

Showing 1 changed file with 7 additions and 2 deletions Side-by-side Diff

... ... @@ -150,6 +150,11 @@
150 150 {
151 151 kref_put(&ubufs->kref, vhost_net_zerocopy_done_signal);
152 152 wait_event(ubufs->wait, !atomic_read(&ubufs->kref.refcount));
  153 +}
  154 +
  155 +static void vhost_net_ubuf_put_wait_and_free(struct vhost_net_ubuf_ref *ubufs)
  156 +{
  157 + vhost_net_ubuf_put_and_wait(ubufs);
153 158 kfree(ubufs);
154 159 }
155 160  
... ... @@ -948,7 +953,7 @@
948 953 mutex_unlock(&vq->mutex);
949 954  
950 955 if (oldubufs) {
951   - vhost_net_ubuf_put_and_wait(oldubufs);
  956 + vhost_net_ubuf_put_wait_and_free(oldubufs);
952 957 mutex_lock(&vq->mutex);
953 958 vhost_zerocopy_signal_used(n, vq);
954 959 mutex_unlock(&vq->mutex);
... ... @@ -966,7 +971,7 @@
966 971 rcu_assign_pointer(vq->private_data, oldsock);
967 972 vhost_net_enable_vq(n, vq);
968 973 if (ubufs)
969   - vhost_net_ubuf_put_and_wait(ubufs);
  974 + vhost_net_ubuf_put_wait_and_free(ubufs);
970 975 err_ubufs:
971 976 fput(sock->file);
972 977 err_vq: