|
|
05bba0 |
From cb2dd196bc247db6a40ea2847f86b63e9a923351 Mon Sep 17 00:00:00 2001
|
|
|
05bba0 |
From: Richard Jones <rjones@redhat.com>
|
|
|
05bba0 |
Date: Thu, 11 Jun 2015 11:40:21 +0200
|
|
|
05bba0 |
Subject: [PATCH 21/30] curl: refuse to open URL from HTTP server without range
|
|
|
05bba0 |
support
|
|
|
05bba0 |
|
|
|
05bba0 |
Message-id: <1434022828-13037-15-git-send-email-rjones@redhat.com>
|
|
|
05bba0 |
Patchwork-id: 65849
|
|
|
05bba0 |
O-Subject: [RHEL-7.2 qemu-kvm v3 PATCH 14/21] curl: refuse to open URL from HTTP server without range support
|
|
|
05bba0 |
Bugzilla: 1226684
|
|
|
05bba0 |
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
05bba0 |
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
05bba0 |
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
05bba0 |
|
|
|
05bba0 |
From: Fam Zheng <famz@redhat.com>
|
|
|
05bba0 |
|
|
|
05bba0 |
CURL driver requests partial data from server on guest IO req. For HTTP
|
|
|
05bba0 |
and HTTPS, it uses "Range: ***" in requests, and this will not work if
|
|
|
05bba0 |
server not accepting range. This patch does this check when open.
|
|
|
05bba0 |
|
|
|
05bba0 |
* Removed curl_size_cb, which is not used: On one hand it's registered to
|
|
|
05bba0 |
libcurl as CURLOPT_WRITEFUNCTION, instead of CURLOPT_HEADERFUNCTION,
|
|
|
05bba0 |
which will get called with *data*, not *header*. On the other hand the
|
|
|
05bba0 |
s->len is assigned unconditionally later.
|
|
|
05bba0 |
|
|
|
05bba0 |
In this gone function, the sscanf for "Content-Length: %zd", on
|
|
|
05bba0 |
(void *)ptr, which is not guaranteed to be zero-terminated, is
|
|
|
05bba0 |
potentially a security bug. So this patch fixes it as a side-effect. The
|
|
|
05bba0 |
bug is reported as: https://bugs.launchpad.net/qemu/+bug/1188943
|
|
|
05bba0 |
(Note the bug is marked "private" so you might not be able to see it)
|
|
|
05bba0 |
|
|
|
05bba0 |
* Introduced curl_header_cb, which is used to parse header and mark the
|
|
|
05bba0 |
server as accepting range if "Accept-Ranges: bytes" line is seen from
|
|
|
05bba0 |
response header. If protocol is HTTP or HTTPS, but server response has
|
|
|
05bba0 |
no not this support, refuse to open this URL.
|
|
|
05bba0 |
|
|
|
05bba0 |
Note that python builtin module SimpleHTTPServer is an example of not
|
|
|
05bba0 |
supporting range, if you need to test this driver, get a better server
|
|
|
05bba0 |
or use internet URLs.
|
|
|
05bba0 |
|
|
|
05bba0 |
Signed-off-by: Fam Zheng <famz@redhat.com>
|
|
|
05bba0 |
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
05bba0 |
|
|
|
05bba0 |
Upstream-status: 3494d650273e619606c6cb2c38aa9b8b7bed98e2
|
|
|
05bba0 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
05bba0 |
---
|
|
|
05bba0 |
block/curl.c | 24 ++++++++++++++++++------
|
|
|
05bba0 |
1 file changed, 18 insertions(+), 6 deletions(-)
|
|
|
05bba0 |
|
|
|
05bba0 |
diff --git a/block/curl.c b/block/curl.c
|
|
|
05bba0 |
index 67ea05f..e97682f 100644
|
|
|
05bba0 |
--- a/block/curl.c
|
|
|
05bba0 |
+++ b/block/curl.c
|
|
|
05bba0 |
@@ -106,6 +106,7 @@ typedef struct BDRVCURLState {
|
|
|
05bba0 |
CURLState states[CURL_NUM_STATES];
|
|
|
05bba0 |
char *url;
|
|
|
05bba0 |
size_t readahead_size;
|
|
|
05bba0 |
+ bool accept_range;
|
|
|
05bba0 |
} BDRVCURLState;
|
|
|
05bba0 |
|
|
|
05bba0 |
static void curl_clean_state(CURLState *s);
|
|
|
05bba0 |
@@ -157,14 +158,15 @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
|
|
|
05bba0 |
return 0;
|
|
|
05bba0 |
}
|
|
|
05bba0 |
|
|
|
05bba0 |
-static size_t curl_size_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
|
|
05bba0 |
+static size_t curl_header_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
|
|
05bba0 |
{
|
|
|
05bba0 |
- CURLState *s = ((CURLState*)opaque);
|
|
|
05bba0 |
+ BDRVCURLState *s = opaque;
|
|
|
05bba0 |
size_t realsize = size * nmemb;
|
|
|
05bba0 |
- size_t fsize;
|
|
|
05bba0 |
+ const char *accept_line = "Accept-Ranges: bytes";
|
|
|
05bba0 |
|
|
|
05bba0 |
- if(sscanf(ptr, "Content-Length: %zd", &fsize) == 1) {
|
|
|
05bba0 |
- s->s->len = fsize;
|
|
|
05bba0 |
+ if (realsize >= strlen(accept_line)
|
|
|
05bba0 |
+ && strncmp((char *)ptr, accept_line, strlen(accept_line)) == 0) {
|
|
|
05bba0 |
+ s->accept_range = true;
|
|
|
05bba0 |
}
|
|
|
05bba0 |
|
|
|
05bba0 |
return realsize;
|
|
|
05bba0 |
@@ -483,8 +485,11 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
|
|
05bba0 |
|
|
|
05bba0 |
// Get file size
|
|
|
05bba0 |
|
|
|
05bba0 |
+ s->accept_range = false;
|
|
|
05bba0 |
curl_easy_setopt(state->curl, CURLOPT_NOBODY, 1);
|
|
|
05bba0 |
- curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, (void *)curl_size_cb);
|
|
|
05bba0 |
+ curl_easy_setopt(state->curl, CURLOPT_HEADERFUNCTION,
|
|
|
05bba0 |
+ curl_header_cb);
|
|
|
05bba0 |
+ curl_easy_setopt(state->curl, CURLOPT_HEADERDATA, s);
|
|
|
05bba0 |
if (curl_easy_perform(state->curl))
|
|
|
05bba0 |
goto out;
|
|
|
05bba0 |
curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d);
|
|
|
05bba0 |
@@ -494,6 +499,13 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
|
|
05bba0 |
s->len = (size_t)d;
|
|
|
05bba0 |
else if(!s->len)
|
|
|
05bba0 |
goto out;
|
|
|
05bba0 |
+ if ((!strncasecmp(s->url, "http://", strlen("http://"))
|
|
|
05bba0 |
+ || !strncasecmp(s->url, "https://", strlen("https://")))
|
|
|
05bba0 |
+ && !s->accept_range) {
|
|
|
05bba0 |
+ pstrcpy(state->errmsg, CURL_ERROR_SIZE,
|
|
|
05bba0 |
+ "Server does not support 'range' (byte ranges).");
|
|
|
05bba0 |
+ goto out;
|
|
|
05bba0 |
+ }
|
|
|
05bba0 |
DPRINTF("CURL: Size = %zd\n", s->len);
|
|
|
05bba0 |
|
|
|
05bba0 |
curl_clean_state(state);
|
|
|
05bba0 |
--
|
|
|
05bba0 |
1.8.3.1
|
|
|
05bba0 |
|