aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/vhost
diff options
context:
space:
mode:
authorMichael S. Tsirkin <mst@redhat.com>2013-06-25 10:29:46 -0400
committerMichael S. Tsirkin <mst@redhat.com>2013-07-07 07:06:22 -0400
commitc38e39c378f46f00ce922dd40a91043a9925c28d (patch)
treea5286110beeea3f5fef0c86fb44535d91402ea3b /drivers/vhost
parent8bb495e3f02401ee6f76d1b1d77f3ac9f079e376 (diff)
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>
Diffstat (limited to 'drivers/vhost')
-rw-r--r--drivers/vhost/net.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index f80d3dd41d8c..8ca5ac71b845 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -150,6 +150,11 @@ static void vhost_net_ubuf_put_and_wait(struct vhost_net_ubuf_ref *ubufs)
150{ 150{
151 kref_put(&ubufs->kref, vhost_net_zerocopy_done_signal); 151 kref_put(&ubufs->kref, vhost_net_zerocopy_done_signal);
152 wait_event(ubufs->wait, !atomic_read(&ubufs->kref.refcount)); 152 wait_event(ubufs->wait, !atomic_read(&ubufs->kref.refcount));
153}
154
155static void vhost_net_ubuf_put_wait_and_free(struct vhost_net_ubuf_ref *ubufs)
156{
157 vhost_net_ubuf_put_and_wait(ubufs);
153 kfree(ubufs); 158 kfree(ubufs);
154} 159}
155 160
@@ -948,7 +953,7 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
948 mutex_unlock(&vq->mutex); 953 mutex_unlock(&vq->mutex);
949 954
950 if (oldubufs) { 955 if (oldubufs) {
951 vhost_net_ubuf_put_and_wait(oldubufs); 956 vhost_net_ubuf_put_wait_and_free(oldubufs);
952 mutex_lock(&vq->mutex); 957 mutex_lock(&vq->mutex);
953 vhost_zerocopy_signal_used(n, vq); 958 vhost_zerocopy_signal_used(n, vq);
954 mutex_unlock(&vq->mutex); 959 mutex_unlock(&vq->mutex);
@@ -966,7 +971,7 @@ err_used:
966 rcu_assign_pointer(vq->private_data, oldsock); 971 rcu_assign_pointer(vq->private_data, oldsock);
967 vhost_net_enable_vq(n, vq); 972 vhost_net_enable_vq(n, vq);
968 if (ubufs) 973 if (ubufs)
969 vhost_net_ubuf_put_and_wait(ubufs); 974 vhost_net_ubuf_put_wait_and_free(ubufs);
970err_ubufs: 975err_ubufs:
971 fput(sock->file); 976 fput(sock->file);
972err_vq: 977err_vq: