aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/vhost/net.c
diff options
context:
space:
mode:
authorMichael S. Tsirkin <mst@redhat.com>2013-06-25 10:29:46 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-07-28 19:29:57 -0400
commitf5ce1d2513b74d4603769ed99636dc52144f02c4 (patch)
tree3182bebad76864a8505b0df755dce840de48dd24 /drivers/vhost/net.c
parent2b0e8a4ff83fd85afe5d0b84a2e1c6faa5fa56b8 (diff)
vhost-net: fix use-after-free in vhost_net_flush
[ Upstream commit c38e39c378f46f00ce922dd40a91043a9925c28d ] 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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/vhost/net.c')
-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: