Michael S. Tsirkin
2013-Jun-20 11:48 UTC
[PATCH net] 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 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. Signed-off-by: Michael S. Tsirkin <mst at redhat.com> --- Dave, this is needed for stable as well, but the code has moved a bit since then. I'll post a patch tweaked to apply against 3.9 and 3.8 separately. drivers/vhost/net.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 5c77d6a..534adb0 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -149,6 +149,11 @@ static void vhost_net_ubuf_put_and_wait(struct vhost_net_ubuf_ref *ubufs) { kref_put(&ubufs->kref, vhost_net_zerocopy_done_signal); wait_event(ubufs->wait, !atomic_read(&ubufs->kref.refcount)); +} + +static void vhost_net_ubuf_put_wait_and_free(struct vhost_net_ubuf_ref *ubufs) +{ + vhost_net_ubuf_put_and_wait(ubufs); kfree(ubufs); } @@ -1073,7 +1078,7 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) mutex_unlock(&vq->mutex); if (oldubufs) { - vhost_net_ubuf_put_and_wait(oldubufs); + vhost_net_ubuf_put_wait_and_free(oldubufs); mutex_lock(&vq->mutex); vhost_zerocopy_signal_used(n, vq); mutex_unlock(&vq->mutex); @@ -1091,7 +1096,7 @@ err_used: vq->private_data = oldsock; vhost_net_enable_vq(n, vq); if (ubufs) - vhost_net_ubuf_put_and_wait(ubufs); + vhost_net_ubuf_put_wait_and_free(ubufs); err_ubufs: fput(sock->file); err_vq: -- MST
Sergei Shtylyov
2013-Jun-20 12:47 UTC
[PATCH net] vhost-net: fix use-after-free in vhost_net_flush
Hello. On 20-06-2013 15:48, Michael S. Tsirkin wrote:> vhost_net_ubuf_put_and_wait has a confusing name: > it will actually also free it's argument. > Thus since commit 1280c27f8e29acf4af2da914e80ec27c3dbd5c01Please also specify that commit's summary line in parens.> 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.> Signed-off-by: Michael S. Tsirkin <mst at redhat.com>WBR, Sergei
Jason Wang
2013-Jun-21 06:50 UTC
[PATCH net] vhost-net: fix use-after-free in vhost_net_flush
On 06/20/2013 07:48 PM, Michael S. Tsirkin wrote:> 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 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. > > Signed-off-by: Michael S. Tsirkin <mst at redhat.com> > --- > > Dave, this is needed for stable as well, but > the code has moved a bit since then. > I'll post a patch tweaked to apply against 3.9 and 3.8 separately. > > drivers/vhost/net.c | 9 +++++++-- > 1 file changed, 7 insertions(+), 2 deletions(-) > > diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c > index 5c77d6a..534adb0 100644 > --- a/drivers/vhost/net.c > +++ b/drivers/vhost/net.c > @@ -149,6 +149,11 @@ static void vhost_net_ubuf_put_and_wait(struct vhost_net_ubuf_ref *ubufs) > { > kref_put(&ubufs->kref, vhost_net_zerocopy_done_signal); > wait_event(ubufs->wait, !atomic_read(&ubufs->kref.refcount)); > +} > + > +static void vhost_net_ubuf_put_wait_and_free(struct vhost_net_ubuf_ref *ubufs) > +{ > + vhost_net_ubuf_put_and_wait(ubufs); > kfree(ubufs); > } > > @@ -1073,7 +1078,7 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) > mutex_unlock(&vq->mutex); > > if (oldubufs) { > - vhost_net_ubuf_put_and_wait(oldubufs); > + vhost_net_ubuf_put_wait_and_free(oldubufs); > mutex_lock(&vq->mutex); > vhost_zerocopy_signal_used(n, vq); > mutex_unlock(&vq->mutex); > @@ -1091,7 +1096,7 @@ err_used: > vq->private_data = oldsock; > vhost_net_enable_vq(n, vq); > if (ubufs) > - vhost_net_ubuf_put_and_wait(ubufs); > + vhost_net_ubuf_put_wait_and_free(ubufs); > err_ubufs: > fput(sock->file); > err_vq:Acked-by: Jason Wang <jasowang at redhat.com>
Asias He
2013-Jun-21 07:20 UTC
[PATCH net] vhost-net: fix use-after-free in vhost_net_flush
On Thu, Jun 20, 2013 at 02:48:13PM +0300, Michael S. Tsirkin wrote:> 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 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. > > Signed-off-by: Michael S. Tsirkin <mst at redhat.com>Acked-by: Asias He <asias at redhat.com>> --- > > Dave, this is needed for stable as well, but > the code has moved a bit since then. > I'll post a patch tweaked to apply against 3.9 and 3.8 separately. > > drivers/vhost/net.c | 9 +++++++-- > 1 file changed, 7 insertions(+), 2 deletions(-) > > diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c > index 5c77d6a..534adb0 100644 > --- a/drivers/vhost/net.c > +++ b/drivers/vhost/net.c > @@ -149,6 +149,11 @@ static void vhost_net_ubuf_put_and_wait(struct vhost_net_ubuf_ref *ubufs) > { > kref_put(&ubufs->kref, vhost_net_zerocopy_done_signal); > wait_event(ubufs->wait, !atomic_read(&ubufs->kref.refcount)); > +} > + > +static void vhost_net_ubuf_put_wait_and_free(struct vhost_net_ubuf_ref *ubufs) > +{ > + vhost_net_ubuf_put_and_wait(ubufs); > kfree(ubufs); > } > > @@ -1073,7 +1078,7 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) > mutex_unlock(&vq->mutex); > > if (oldubufs) { > - vhost_net_ubuf_put_and_wait(oldubufs); > + vhost_net_ubuf_put_wait_and_free(oldubufs); > mutex_lock(&vq->mutex); > vhost_zerocopy_signal_used(n, vq); > mutex_unlock(&vq->mutex); > @@ -1091,7 +1096,7 @@ err_used: > vq->private_data = oldsock; > vhost_net_enable_vq(n, vq); > if (ubufs) > - vhost_net_ubuf_put_and_wait(ubufs); > + vhost_net_ubuf_put_wait_and_free(ubufs); > err_ubufs: > fput(sock->file); > err_vq: > -- > MST-- Asias
David Miller
2013-Jun-24 07:01 UTC
[PATCH net] vhost-net: fix use-after-free in vhost_net_flush
From: "Michael S. Tsirkin" <mst at redhat.com> Date: Thu, 20 Jun 2013 14:48:13 +0300> vhost_net_ubuf_put_and_wait has a confusing name: > it will actually also free it's argument. > Thus since commit 1280c27f8e29acf4af2da914e80ec27c3dbd5c01Never reference commits only by SHA1 ID, it is never sufficient. Always provide, after the SHA1 ID, in parenthesis, the header line from the commit message. To be honest, I'm kind of tired of telling people they need to do this over and over again. Maybe people keep forgetting because the reason why this is an issue hasn't really sunk in. If the patch you reference got backported into another tree, it will not have the SHA1 ID, and therefore someone reading the "fix" won't be able to find the fault causing change without going through a lot of trouble. By providing the commit header line you remove that problem altogether, no ambiguity is possible.
Reasonably Related Threads
- [PATCH net] vhost-net: fix use-after-free in vhost_net_flush
- [PATCHv2] vhost-net: fix use-after-free in vhost_net_flush
- [PATCHv2] vhost-net: fix use-after-free in vhost_net_flush
- [PATCHv3] vhost-net: fix use-after-free in vhost_net_flush
- [PATCHv3] vhost-net: fix use-after-free in vhost_net_flush