cryptospore / rpms / qemu-kvm

Forked from rpms/qemu-kvm 2 years ago
Clone
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