qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Max Reitz <mreitz@redhat.com>
To: qemu-block@nongnu.org
Cc: Kevin Wolf <kwolf@redhat.com>,
	qemu-devel@nongnu.org, Max Reitz <mreitz@redhat.com>
Subject: [PATCH 0/2] block/curl: Disconnect sockets from CURLState
Date: Tue,  9 Mar 2021 14:05:39 +0100	[thread overview]
Message-ID: <20210309130541.37540-1-mreitz@redhat.com> (raw)

Hi,

There’s been a bug report concerning our curl driver on Launchpad:
  https://bugs.launchpad.net/qemu/+bug/1916501

When downloading an image from a certain URL, it crashes.
(https://download.cirros-cloud.net/0.4.0/cirros-0.4.0-x86_64-disk.img)

The crash is a use-after-free: A CURLState (which basically represents a
transfer) has several CURLSocket objects (encapsulating an FD) over
which the data is transmitted.  Once that transfer is done, the state is
purged and all CURLSocket objects belonging to it are freed, under the
assumption that once the transfer is done, the sockets are no longer
used.

That seems to work with most servers.

However, I suspect that in the above case, some sockets might be reused
for later transfers; so libcurl doesn’t actually tell us to drop them
(by invoking curl_sock_cb() with CURL_POLL_REMOVE), and that means our
AIO handler (curl_multi_do()) is invoked for some socket after its
corresponding CURLSocket object is freed, leading to said
use-after-free.

I don’t think libcurl actually says anywhere that sockets are bound to
CURL states (“CURL” objects), though one is always passed to
curl_sock_cb().  But I can’t find any mention that a socket might not be
reused by some other state.

In fact, there is absolutely no necessity to bind sockets to states.  We
can trivially replace the CURLState pointer in CURLSocket by a
BDRVCURLState pointer (patch 1), and very easily move the sockets from a
per-state list to a global hash table (patch 2).

By doing so, there is no longer any need to free any socket object when
purging a CURLState, because the sockets are then independent of any
such state.  (As far as I can tell from testing, this does not lead to
any memory leaks.  For every socket there is, libcurl does tell us
eventually to remove it by invoking curl_sock_cb() with
CURL_POLL_REMOVE.)


Max Reitz (2):
  curl: Store BDRVCURLState pointer in CURLSocket
  curl: Disconnect sockets from CURLState

 block/curl.c | 50 ++++++++++++++++++++++++++++----------------------
 1 file changed, 28 insertions(+), 22 deletions(-)

-- 
2.29.2



             reply	other threads:[~2021-03-09 13:19 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-09 13:05 Max Reitz [this message]
2021-03-09 13:05 ` [PATCH 1/2] curl: Store BDRVCURLState pointer in CURLSocket Max Reitz
2021-03-09 13:13   ` Philippe Mathieu-Daudé
2021-03-09 13:05 ` [PATCH 2/2] curl: Disconnect sockets from CURLState Max Reitz
2021-03-10 11:51 ` [PATCH 0/2] block/curl: " Kevin Wolf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210309130541.37540-1-mreitz@redhat.com \
    --to=mreitz@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).