cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

curl.c (31045B)


      1/*
      2 * QEMU Block driver for CURL images
      3 *
      4 * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
      5 *
      6 * Permission is hereby granted, free of charge, to any person obtaining a copy
      7 * of this software and associated documentation files (the "Software"), to deal
      8 * in the Software without restriction, including without limitation the rights
      9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10 * copies of the Software, and to permit persons to whom the Software is
     11 * furnished to do so, subject to the following conditions:
     12 *
     13 * The above copyright notice and this permission notice shall be included in
     14 * all copies or substantial portions of the Software.
     15 *
     16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22 * THE SOFTWARE.
     23 */
     24
     25#include "qemu/osdep.h"
     26#include "qapi/error.h"
     27#include "qemu/error-report.h"
     28#include "qemu/module.h"
     29#include "qemu/option.h"
     30#include "block/block_int.h"
     31#include "qapi/qmp/qdict.h"
     32#include "qapi/qmp/qstring.h"
     33#include "crypto/secret.h"
     34#include <curl/curl.h>
     35#include "qemu/cutils.h"
     36#include "trace.h"
     37
     38// #define DEBUG_VERBOSE
     39
     40#define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \
     41                   CURLPROTO_FTP | CURLPROTO_FTPS)
     42
     43#define CURL_NUM_STATES 8
     44#define CURL_NUM_ACB    8
     45#define CURL_TIMEOUT_MAX 10000
     46
     47#define CURL_BLOCK_OPT_URL       "url"
     48#define CURL_BLOCK_OPT_READAHEAD "readahead"
     49#define CURL_BLOCK_OPT_SSLVERIFY "sslverify"
     50#define CURL_BLOCK_OPT_TIMEOUT "timeout"
     51#define CURL_BLOCK_OPT_COOKIE    "cookie"
     52#define CURL_BLOCK_OPT_COOKIE_SECRET "cookie-secret"
     53#define CURL_BLOCK_OPT_USERNAME "username"
     54#define CURL_BLOCK_OPT_PASSWORD_SECRET "password-secret"
     55#define CURL_BLOCK_OPT_PROXY_USERNAME "proxy-username"
     56#define CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET "proxy-password-secret"
     57
     58#define CURL_BLOCK_OPT_READAHEAD_DEFAULT (256 * 1024)
     59#define CURL_BLOCK_OPT_SSLVERIFY_DEFAULT true
     60#define CURL_BLOCK_OPT_TIMEOUT_DEFAULT 5
     61
     62struct BDRVCURLState;
     63struct CURLState;
     64
     65static bool libcurl_initialized;
     66
     67typedef struct CURLAIOCB {
     68    Coroutine *co;
     69    QEMUIOVector *qiov;
     70
     71    uint64_t offset;
     72    uint64_t bytes;
     73    int ret;
     74
     75    size_t start;
     76    size_t end;
     77} CURLAIOCB;
     78
     79typedef struct CURLSocket {
     80    int fd;
     81    struct BDRVCURLState *s;
     82} CURLSocket;
     83
     84typedef struct CURLState
     85{
     86    struct BDRVCURLState *s;
     87    CURLAIOCB *acb[CURL_NUM_ACB];
     88    CURL *curl;
     89    char *orig_buf;
     90    uint64_t buf_start;
     91    size_t buf_off;
     92    size_t buf_len;
     93    char range[128];
     94    char errmsg[CURL_ERROR_SIZE];
     95    char in_use;
     96} CURLState;
     97
     98typedef struct BDRVCURLState {
     99    CURLM *multi;
    100    QEMUTimer timer;
    101    uint64_t len;
    102    CURLState states[CURL_NUM_STATES];
    103    GHashTable *sockets; /* GINT_TO_POINTER(fd) -> socket */
    104    char *url;
    105    size_t readahead_size;
    106    bool sslverify;
    107    uint64_t timeout;
    108    char *cookie;
    109    bool accept_range;
    110    AioContext *aio_context;
    111    QemuMutex mutex;
    112    CoQueue free_state_waitq;
    113    char *username;
    114    char *password;
    115    char *proxyusername;
    116    char *proxypassword;
    117} BDRVCURLState;
    118
    119static void curl_clean_state(CURLState *s);
    120static void curl_multi_do(void *arg);
    121
    122static gboolean curl_drop_socket(void *key, void *value, void *opaque)
    123{
    124    CURLSocket *socket = value;
    125    BDRVCURLState *s = socket->s;
    126
    127    aio_set_fd_handler(s->aio_context, socket->fd, false,
    128                       NULL, NULL, NULL, NULL);
    129    return true;
    130}
    131
    132static void curl_drop_all_sockets(GHashTable *sockets)
    133{
    134    g_hash_table_foreach_remove(sockets, curl_drop_socket, NULL);
    135}
    136
    137/* Called from curl_multi_do_locked, with s->mutex held.  */
    138static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
    139{
    140    BDRVCURLState *s = opaque;
    141
    142    trace_curl_timer_cb(timeout_ms);
    143    if (timeout_ms == -1) {
    144        timer_del(&s->timer);
    145    } else {
    146        int64_t timeout_ns = (int64_t)timeout_ms * 1000 * 1000;
    147        timer_mod(&s->timer,
    148                  qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + timeout_ns);
    149    }
    150    return 0;
    151}
    152
    153/* Called from curl_multi_do_locked, with s->mutex held.  */
    154static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
    155                        void *userp, void *sp)
    156{
    157    BDRVCURLState *s;
    158    CURLState *state = NULL;
    159    CURLSocket *socket;
    160
    161    curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&state);
    162    s = state->s;
    163
    164    socket = g_hash_table_lookup(s->sockets, GINT_TO_POINTER(fd));
    165    if (!socket) {
    166        socket = g_new0(CURLSocket, 1);
    167        socket->fd = fd;
    168        socket->s = s;
    169        g_hash_table_insert(s->sockets, GINT_TO_POINTER(fd), socket);
    170    }
    171
    172    trace_curl_sock_cb(action, (int)fd);
    173    switch (action) {
    174        case CURL_POLL_IN:
    175            aio_set_fd_handler(s->aio_context, fd, false,
    176                               curl_multi_do, NULL, NULL, socket);
    177            break;
    178        case CURL_POLL_OUT:
    179            aio_set_fd_handler(s->aio_context, fd, false,
    180                               NULL, curl_multi_do, NULL, socket);
    181            break;
    182        case CURL_POLL_INOUT:
    183            aio_set_fd_handler(s->aio_context, fd, false,
    184                               curl_multi_do, curl_multi_do, NULL, socket);
    185            break;
    186        case CURL_POLL_REMOVE:
    187            aio_set_fd_handler(s->aio_context, fd, false,
    188                               NULL, NULL, NULL, NULL);
    189            break;
    190    }
    191
    192    if (action == CURL_POLL_REMOVE) {
    193        g_hash_table_remove(s->sockets, GINT_TO_POINTER(fd));
    194    }
    195
    196    return 0;
    197}
    198
    199/* Called from curl_multi_do_locked, with s->mutex held.  */
    200static size_t curl_header_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
    201{
    202    BDRVCURLState *s = opaque;
    203    size_t realsize = size * nmemb;
    204    const char *header = (char *)ptr;
    205    const char *end = header + realsize;
    206    const char *accept_ranges = "accept-ranges:";
    207    const char *bytes = "bytes";
    208
    209    if (realsize >= strlen(accept_ranges)
    210        && g_ascii_strncasecmp(header, accept_ranges,
    211                               strlen(accept_ranges)) == 0) {
    212
    213        char *p = strchr(header, ':') + 1;
    214
    215        /* Skip whitespace between the header name and value. */
    216        while (p < end && *p && g_ascii_isspace(*p)) {
    217            p++;
    218        }
    219
    220        if (end - p >= strlen(bytes)
    221            && strncmp(p, bytes, strlen(bytes)) == 0) {
    222
    223            /* Check that there is nothing but whitespace after the value. */
    224            p += strlen(bytes);
    225            while (p < end && *p && g_ascii_isspace(*p)) {
    226                p++;
    227            }
    228
    229            if (p == end || !*p) {
    230                s->accept_range = true;
    231            }
    232        }
    233    }
    234
    235    return realsize;
    236}
    237
    238/* Called from curl_multi_do_locked, with s->mutex held.  */
    239static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
    240{
    241    CURLState *s = ((CURLState*)opaque);
    242    size_t realsize = size * nmemb;
    243
    244    trace_curl_read_cb(realsize);
    245
    246    if (!s || !s->orig_buf) {
    247        goto read_end;
    248    }
    249
    250    if (s->buf_off >= s->buf_len) {
    251        /* buffer full, read nothing */
    252        goto read_end;
    253    }
    254    realsize = MIN(realsize, s->buf_len - s->buf_off);
    255    memcpy(s->orig_buf + s->buf_off, ptr, realsize);
    256    s->buf_off += realsize;
    257
    258read_end:
    259    /* curl will error out if we do not return this value */
    260    return size * nmemb;
    261}
    262
    263/* Called with s->mutex held.  */
    264static bool curl_find_buf(BDRVCURLState *s, uint64_t start, uint64_t len,
    265                          CURLAIOCB *acb)
    266{
    267    int i;
    268    uint64_t end = start + len;
    269    uint64_t clamped_end = MIN(end, s->len);
    270    uint64_t clamped_len = clamped_end - start;
    271
    272    for (i=0; i<CURL_NUM_STATES; i++) {
    273        CURLState *state = &s->states[i];
    274        uint64_t buf_end = (state->buf_start + state->buf_off);
    275        uint64_t buf_fend = (state->buf_start + state->buf_len);
    276
    277        if (!state->orig_buf)
    278            continue;
    279        if (!state->buf_off)
    280            continue;
    281
    282        // Does the existing buffer cover our section?
    283        if ((start >= state->buf_start) &&
    284            (start <= buf_end) &&
    285            (clamped_end >= state->buf_start) &&
    286            (clamped_end <= buf_end))
    287        {
    288            char *buf = state->orig_buf + (start - state->buf_start);
    289
    290            qemu_iovec_from_buf(acb->qiov, 0, buf, clamped_len);
    291            if (clamped_len < len) {
    292                qemu_iovec_memset(acb->qiov, clamped_len, 0, len - clamped_len);
    293            }
    294            acb->ret = 0;
    295            return true;
    296        }
    297
    298        // Wait for unfinished chunks
    299        if (state->in_use &&
    300            (start >= state->buf_start) &&
    301            (start <= buf_fend) &&
    302            (clamped_end >= state->buf_start) &&
    303            (clamped_end <= buf_fend))
    304        {
    305            int j;
    306
    307            acb->start = start - state->buf_start;
    308            acb->end = acb->start + clamped_len;
    309
    310            for (j=0; j<CURL_NUM_ACB; j++) {
    311                if (!state->acb[j]) {
    312                    state->acb[j] = acb;
    313                    return true;
    314                }
    315            }
    316        }
    317    }
    318
    319    return false;
    320}
    321
    322/* Called with s->mutex held.  */
    323static void curl_multi_check_completion(BDRVCURLState *s)
    324{
    325    int msgs_in_queue;
    326
    327    /* Try to find done transfers, so we can free the easy
    328     * handle again. */
    329    for (;;) {
    330        CURLMsg *msg;
    331        msg = curl_multi_info_read(s->multi, &msgs_in_queue);
    332
    333        /* Quit when there are no more completions */
    334        if (!msg)
    335            break;
    336
    337        if (msg->msg == CURLMSG_DONE) {
    338            int i;
    339            CURLState *state = NULL;
    340            bool error = msg->data.result != CURLE_OK;
    341
    342            curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE,
    343                              (char **)&state);
    344
    345            if (error) {
    346                static int errcount = 100;
    347
    348                /* Don't lose the original error message from curl, since
    349                 * it contains extra data.
    350                 */
    351                if (errcount > 0) {
    352                    error_report("curl: %s", state->errmsg);
    353                    if (--errcount == 0) {
    354                        error_report("curl: further errors suppressed");
    355                    }
    356                }
    357            }
    358
    359            for (i = 0; i < CURL_NUM_ACB; i++) {
    360                CURLAIOCB *acb = state->acb[i];
    361
    362                if (acb == NULL) {
    363                    continue;
    364                }
    365
    366                if (!error) {
    367                    /* Assert that we have read all data */
    368                    assert(state->buf_off >= acb->end);
    369
    370                    qemu_iovec_from_buf(acb->qiov, 0,
    371                                        state->orig_buf + acb->start,
    372                                        acb->end - acb->start);
    373
    374                    if (acb->end - acb->start < acb->bytes) {
    375                        size_t offset = acb->end - acb->start;
    376                        qemu_iovec_memset(acb->qiov, offset, 0,
    377                                          acb->bytes - offset);
    378                    }
    379                }
    380
    381                acb->ret = error ? -EIO : 0;
    382                state->acb[i] = NULL;
    383                qemu_mutex_unlock(&s->mutex);
    384                aio_co_wake(acb->co);
    385                qemu_mutex_lock(&s->mutex);
    386            }
    387
    388            curl_clean_state(state);
    389            break;
    390        }
    391    }
    392}
    393
    394/* Called with s->mutex held.  */
    395static void curl_multi_do_locked(CURLSocket *socket)
    396{
    397    BDRVCURLState *s = socket->s;
    398    int running;
    399    int r;
    400
    401    if (!s->multi) {
    402        return;
    403    }
    404
    405    do {
    406        r = curl_multi_socket_action(s->multi, socket->fd, 0, &running);
    407    } while (r == CURLM_CALL_MULTI_PERFORM);
    408}
    409
    410static void curl_multi_do(void *arg)
    411{
    412    CURLSocket *socket = arg;
    413    BDRVCURLState *s = socket->s;
    414
    415    qemu_mutex_lock(&s->mutex);
    416    curl_multi_do_locked(socket);
    417    curl_multi_check_completion(s);
    418    qemu_mutex_unlock(&s->mutex);
    419}
    420
    421static void curl_multi_timeout_do(void *arg)
    422{
    423    BDRVCURLState *s = (BDRVCURLState *)arg;
    424    int running;
    425
    426    if (!s->multi) {
    427        return;
    428    }
    429
    430    qemu_mutex_lock(&s->mutex);
    431    curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
    432
    433    curl_multi_check_completion(s);
    434    qemu_mutex_unlock(&s->mutex);
    435}
    436
    437/* Called with s->mutex held.  */
    438static CURLState *curl_find_state(BDRVCURLState *s)
    439{
    440    CURLState *state = NULL;
    441    int i;
    442
    443    for (i = 0; i < CURL_NUM_STATES; i++) {
    444        if (!s->states[i].in_use) {
    445            state = &s->states[i];
    446            state->in_use = 1;
    447            break;
    448        }
    449    }
    450    return state;
    451}
    452
    453static int curl_init_state(BDRVCURLState *s, CURLState *state)
    454{
    455    if (!state->curl) {
    456        state->curl = curl_easy_init();
    457        if (!state->curl) {
    458            return -EIO;
    459        }
    460        curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
    461        curl_easy_setopt(state->curl, CURLOPT_SSL_VERIFYPEER,
    462                         (long) s->sslverify);
    463        curl_easy_setopt(state->curl, CURLOPT_SSL_VERIFYHOST,
    464                         s->sslverify ? 2L : 0L);
    465        if (s->cookie) {
    466            curl_easy_setopt(state->curl, CURLOPT_COOKIE, s->cookie);
    467        }
    468        curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, (long)s->timeout);
    469        curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION,
    470                         (void *)curl_read_cb);
    471        curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state);
    472        curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state);
    473        curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1);
    474        curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1);
    475        curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1);
    476        curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
    477        curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1);
    478
    479        if (s->username) {
    480            curl_easy_setopt(state->curl, CURLOPT_USERNAME, s->username);
    481        }
    482        if (s->password) {
    483            curl_easy_setopt(state->curl, CURLOPT_PASSWORD, s->password);
    484        }
    485        if (s->proxyusername) {
    486            curl_easy_setopt(state->curl,
    487                             CURLOPT_PROXYUSERNAME, s->proxyusername);
    488        }
    489        if (s->proxypassword) {
    490            curl_easy_setopt(state->curl,
    491                             CURLOPT_PROXYPASSWORD, s->proxypassword);
    492        }
    493
    494        /* Restrict supported protocols to avoid security issues in the more
    495         * obscure protocols.  For example, do not allow POP3/SMTP/IMAP see
    496         * CVE-2013-0249.
    497         *
    498         * Restricting protocols is only supported from 7.19.4 upwards.
    499         */
    500#if LIBCURL_VERSION_NUM >= 0x071304
    501        curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS);
    502        curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS);
    503#endif
    504
    505#ifdef DEBUG_VERBOSE
    506        curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
    507#endif
    508    }
    509
    510    state->s = s;
    511
    512    return 0;
    513}
    514
    515/* Called with s->mutex held.  */
    516static void curl_clean_state(CURLState *s)
    517{
    518    int j;
    519    for (j = 0; j < CURL_NUM_ACB; j++) {
    520        assert(!s->acb[j]);
    521    }
    522
    523    if (s->s->multi)
    524        curl_multi_remove_handle(s->s->multi, s->curl);
    525
    526    s->in_use = 0;
    527
    528    qemu_co_enter_next(&s->s->free_state_waitq, &s->s->mutex);
    529}
    530
    531static void curl_parse_filename(const char *filename, QDict *options,
    532                                Error **errp)
    533{
    534    qdict_put_str(options, CURL_BLOCK_OPT_URL, filename);
    535}
    536
    537static void curl_detach_aio_context(BlockDriverState *bs)
    538{
    539    BDRVCURLState *s = bs->opaque;
    540    int i;
    541
    542    WITH_QEMU_LOCK_GUARD(&s->mutex) {
    543        curl_drop_all_sockets(s->sockets);
    544        for (i = 0; i < CURL_NUM_STATES; i++) {
    545            if (s->states[i].in_use) {
    546                curl_clean_state(&s->states[i]);
    547            }
    548            if (s->states[i].curl) {
    549                curl_easy_cleanup(s->states[i].curl);
    550                s->states[i].curl = NULL;
    551            }
    552            g_free(s->states[i].orig_buf);
    553            s->states[i].orig_buf = NULL;
    554        }
    555        if (s->multi) {
    556            curl_multi_cleanup(s->multi);
    557            s->multi = NULL;
    558        }
    559    }
    560
    561    timer_del(&s->timer);
    562}
    563
    564static void curl_attach_aio_context(BlockDriverState *bs,
    565                                    AioContext *new_context)
    566{
    567    BDRVCURLState *s = bs->opaque;
    568
    569    aio_timer_init(new_context, &s->timer,
    570                   QEMU_CLOCK_REALTIME, SCALE_NS,
    571                   curl_multi_timeout_do, s);
    572
    573    assert(!s->multi);
    574    s->multi = curl_multi_init();
    575    s->aio_context = new_context;
    576    curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb);
    577    curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, s);
    578    curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, curl_timer_cb);
    579}
    580
    581static QemuOptsList runtime_opts = {
    582    .name = "curl",
    583    .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
    584    .desc = {
    585        {
    586            .name = CURL_BLOCK_OPT_URL,
    587            .type = QEMU_OPT_STRING,
    588            .help = "URL to open",
    589        },
    590        {
    591            .name = CURL_BLOCK_OPT_READAHEAD,
    592            .type = QEMU_OPT_SIZE,
    593            .help = "Readahead size",
    594        },
    595        {
    596            .name = CURL_BLOCK_OPT_SSLVERIFY,
    597            .type = QEMU_OPT_BOOL,
    598            .help = "Verify SSL certificate"
    599        },
    600        {
    601            .name = CURL_BLOCK_OPT_TIMEOUT,
    602            .type = QEMU_OPT_NUMBER,
    603            .help = "Curl timeout"
    604        },
    605        {
    606            .name = CURL_BLOCK_OPT_COOKIE,
    607            .type = QEMU_OPT_STRING,
    608            .help = "Pass the cookie or list of cookies with each request"
    609        },
    610        {
    611            .name = CURL_BLOCK_OPT_COOKIE_SECRET,
    612            .type = QEMU_OPT_STRING,
    613            .help = "ID of secret used as cookie passed with each request"
    614        },
    615        {
    616            .name = CURL_BLOCK_OPT_USERNAME,
    617            .type = QEMU_OPT_STRING,
    618            .help = "Username for HTTP auth"
    619        },
    620        {
    621            .name = CURL_BLOCK_OPT_PASSWORD_SECRET,
    622            .type = QEMU_OPT_STRING,
    623            .help = "ID of secret used as password for HTTP auth",
    624        },
    625        {
    626            .name = CURL_BLOCK_OPT_PROXY_USERNAME,
    627            .type = QEMU_OPT_STRING,
    628            .help = "Username for HTTP proxy auth"
    629        },
    630        {
    631            .name = CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET,
    632            .type = QEMU_OPT_STRING,
    633            .help = "ID of secret used as password for HTTP proxy auth",
    634        },
    635        { /* end of list */ }
    636    },
    637};
    638
    639
    640static int curl_open(BlockDriverState *bs, QDict *options, int flags,
    641                     Error **errp)
    642{
    643    BDRVCURLState *s = bs->opaque;
    644    CURLState *state = NULL;
    645    QemuOpts *opts;
    646    const char *file;
    647    const char *cookie;
    648    const char *cookie_secret;
    649    double d;
    650    const char *secretid;
    651    const char *protocol_delimiter;
    652    int ret;
    653
    654    ret = bdrv_apply_auto_read_only(bs, "curl driver does not support writes",
    655                                    errp);
    656    if (ret < 0) {
    657        return ret;
    658    }
    659
    660    if (!libcurl_initialized) {
    661        ret = curl_global_init(CURL_GLOBAL_ALL);
    662        if (ret) {
    663            error_setg(errp, "libcurl initialization failed with %d", ret);
    664            return -EIO;
    665        }
    666        libcurl_initialized = true;
    667    }
    668
    669    qemu_mutex_init(&s->mutex);
    670    opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
    671    if (!qemu_opts_absorb_qdict(opts, options, errp)) {
    672        goto out_noclean;
    673    }
    674
    675    s->readahead_size = qemu_opt_get_size(opts, CURL_BLOCK_OPT_READAHEAD,
    676                                          CURL_BLOCK_OPT_READAHEAD_DEFAULT);
    677    if ((s->readahead_size & 0x1ff) != 0) {
    678        error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512",
    679                   s->readahead_size);
    680        goto out_noclean;
    681    }
    682
    683    s->timeout = qemu_opt_get_number(opts, CURL_BLOCK_OPT_TIMEOUT,
    684                                     CURL_BLOCK_OPT_TIMEOUT_DEFAULT);
    685    if (s->timeout > CURL_TIMEOUT_MAX) {
    686        error_setg(errp, "timeout parameter is too large or negative");
    687        goto out_noclean;
    688    }
    689
    690    s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY,
    691                                     CURL_BLOCK_OPT_SSLVERIFY_DEFAULT);
    692
    693    cookie = qemu_opt_get(opts, CURL_BLOCK_OPT_COOKIE);
    694    cookie_secret = qemu_opt_get(opts, CURL_BLOCK_OPT_COOKIE_SECRET);
    695
    696    if (cookie && cookie_secret) {
    697        error_setg(errp,
    698                   "curl driver cannot handle both cookie and cookie secret");
    699        goto out_noclean;
    700    }
    701
    702    if (cookie_secret) {
    703        s->cookie = qcrypto_secret_lookup_as_utf8(cookie_secret, errp);
    704        if (!s->cookie) {
    705            goto out_noclean;
    706        }
    707    } else {
    708        s->cookie = g_strdup(cookie);
    709    }
    710
    711    file = qemu_opt_get(opts, CURL_BLOCK_OPT_URL);
    712    if (file == NULL) {
    713        error_setg(errp, "curl block driver requires an 'url' option");
    714        goto out_noclean;
    715    }
    716
    717    if (!strstart(file, bs->drv->protocol_name, &protocol_delimiter) ||
    718        !strstart(protocol_delimiter, "://", NULL))
    719    {
    720        error_setg(errp, "%s curl driver cannot handle the URL '%s' (does not "
    721                   "start with '%s://')", bs->drv->protocol_name, file,
    722                   bs->drv->protocol_name);
    723        goto out_noclean;
    724    }
    725
    726    s->username = g_strdup(qemu_opt_get(opts, CURL_BLOCK_OPT_USERNAME));
    727    secretid = qemu_opt_get(opts, CURL_BLOCK_OPT_PASSWORD_SECRET);
    728
    729    if (secretid) {
    730        s->password = qcrypto_secret_lookup_as_utf8(secretid, errp);
    731        if (!s->password) {
    732            goto out_noclean;
    733        }
    734    }
    735
    736    s->proxyusername = g_strdup(
    737        qemu_opt_get(opts, CURL_BLOCK_OPT_PROXY_USERNAME));
    738    secretid = qemu_opt_get(opts, CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET);
    739    if (secretid) {
    740        s->proxypassword = qcrypto_secret_lookup_as_utf8(secretid, errp);
    741        if (!s->proxypassword) {
    742            goto out_noclean;
    743        }
    744    }
    745
    746    trace_curl_open(file);
    747    qemu_co_queue_init(&s->free_state_waitq);
    748    s->aio_context = bdrv_get_aio_context(bs);
    749    s->url = g_strdup(file);
    750    s->sockets = g_hash_table_new_full(NULL, NULL, NULL, g_free);
    751    qemu_mutex_lock(&s->mutex);
    752    state = curl_find_state(s);
    753    qemu_mutex_unlock(&s->mutex);
    754    if (!state) {
    755        goto out_noclean;
    756    }
    757
    758    // Get file size
    759
    760    if (curl_init_state(s, state) < 0) {
    761        goto out;
    762    }
    763
    764    s->accept_range = false;
    765    curl_easy_setopt(state->curl, CURLOPT_NOBODY, 1);
    766    curl_easy_setopt(state->curl, CURLOPT_HEADERFUNCTION,
    767                     curl_header_cb);
    768    curl_easy_setopt(state->curl, CURLOPT_HEADERDATA, s);
    769    if (curl_easy_perform(state->curl))
    770        goto out;
    771    if (curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d)) {
    772        goto out;
    773    }
    774    /* Prior CURL 7.19.4 return value of 0 could mean that the file size is not
    775     * know or the size is zero. From 7.19.4 CURL returns -1 if size is not
    776     * known and zero if it is really zero-length file. */
    777#if LIBCURL_VERSION_NUM >= 0x071304
    778    if (d < 0) {
    779        pstrcpy(state->errmsg, CURL_ERROR_SIZE,
    780                "Server didn't report file size.");
    781        goto out;
    782    }
    783#else
    784    if (d <= 0) {
    785        pstrcpy(state->errmsg, CURL_ERROR_SIZE,
    786                "Unknown file size or zero-length file.");
    787        goto out;
    788    }
    789#endif
    790
    791    s->len = d;
    792
    793    if ((!strncasecmp(s->url, "http://", strlen("http://"))
    794        || !strncasecmp(s->url, "https://", strlen("https://")))
    795        && !s->accept_range) {
    796        pstrcpy(state->errmsg, CURL_ERROR_SIZE,
    797                "Server does not support 'range' (byte ranges).");
    798        goto out;
    799    }
    800    trace_curl_open_size(s->len);
    801
    802    qemu_mutex_lock(&s->mutex);
    803    curl_clean_state(state);
    804    qemu_mutex_unlock(&s->mutex);
    805    curl_easy_cleanup(state->curl);
    806    state->curl = NULL;
    807
    808    curl_attach_aio_context(bs, bdrv_get_aio_context(bs));
    809
    810    qemu_opts_del(opts);
    811    return 0;
    812
    813out:
    814    error_setg(errp, "CURL: Error opening file: %s", state->errmsg);
    815    curl_easy_cleanup(state->curl);
    816    state->curl = NULL;
    817out_noclean:
    818    qemu_mutex_destroy(&s->mutex);
    819    g_free(s->cookie);
    820    g_free(s->url);
    821    g_free(s->username);
    822    g_free(s->proxyusername);
    823    g_free(s->proxypassword);
    824    curl_drop_all_sockets(s->sockets);
    825    g_hash_table_destroy(s->sockets);
    826    qemu_opts_del(opts);
    827    return -EINVAL;
    828}
    829
    830static void curl_setup_preadv(BlockDriverState *bs, CURLAIOCB *acb)
    831{
    832    CURLState *state;
    833    int running;
    834
    835    BDRVCURLState *s = bs->opaque;
    836
    837    uint64_t start = acb->offset;
    838    uint64_t end;
    839
    840    qemu_mutex_lock(&s->mutex);
    841
    842    // In case we have the requested data already (e.g. read-ahead),
    843    // we can just call the callback and be done.
    844    if (curl_find_buf(s, start, acb->bytes, acb)) {
    845        goto out;
    846    }
    847
    848    // No cache found, so let's start a new request
    849    for (;;) {
    850        state = curl_find_state(s);
    851        if (state) {
    852            break;
    853        }
    854        qemu_co_queue_wait(&s->free_state_waitq, &s->mutex);
    855    }
    856
    857    if (curl_init_state(s, state) < 0) {
    858        curl_clean_state(state);
    859        acb->ret = -EIO;
    860        goto out;
    861    }
    862
    863    acb->start = 0;
    864    acb->end = MIN(acb->bytes, s->len - start);
    865
    866    state->buf_off = 0;
    867    g_free(state->orig_buf);
    868    state->buf_start = start;
    869    state->buf_len = MIN(acb->end + s->readahead_size, s->len - start);
    870    end = start + state->buf_len - 1;
    871    state->orig_buf = g_try_malloc(state->buf_len);
    872    if (state->buf_len && state->orig_buf == NULL) {
    873        curl_clean_state(state);
    874        acb->ret = -ENOMEM;
    875        goto out;
    876    }
    877    state->acb[0] = acb;
    878
    879    snprintf(state->range, 127, "%" PRIu64 "-%" PRIu64, start, end);
    880    trace_curl_setup_preadv(acb->bytes, start, state->range);
    881    curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
    882
    883    if (curl_multi_add_handle(s->multi, state->curl) != CURLM_OK) {
    884        state->acb[0] = NULL;
    885        acb->ret = -EIO;
    886
    887        curl_clean_state(state);
    888        goto out;
    889    }
    890
    891    /* Tell curl it needs to kick things off */
    892    curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
    893
    894out:
    895    qemu_mutex_unlock(&s->mutex);
    896}
    897
    898static int coroutine_fn curl_co_preadv(BlockDriverState *bs,
    899        int64_t offset, int64_t bytes, QEMUIOVector *qiov,
    900        BdrvRequestFlags flags)
    901{
    902    CURLAIOCB acb = {
    903        .co = qemu_coroutine_self(),
    904        .ret = -EINPROGRESS,
    905        .qiov = qiov,
    906        .offset = offset,
    907        .bytes = bytes
    908    };
    909
    910    curl_setup_preadv(bs, &acb);
    911    while (acb.ret == -EINPROGRESS) {
    912        qemu_coroutine_yield();
    913    }
    914    return acb.ret;
    915}
    916
    917static void curl_close(BlockDriverState *bs)
    918{
    919    BDRVCURLState *s = bs->opaque;
    920
    921    trace_curl_close();
    922    curl_detach_aio_context(bs);
    923    qemu_mutex_destroy(&s->mutex);
    924
    925    g_hash_table_destroy(s->sockets);
    926    g_free(s->cookie);
    927    g_free(s->url);
    928    g_free(s->username);
    929    g_free(s->proxyusername);
    930    g_free(s->proxypassword);
    931}
    932
    933static int64_t curl_getlength(BlockDriverState *bs)
    934{
    935    BDRVCURLState *s = bs->opaque;
    936    return s->len;
    937}
    938
    939static void curl_refresh_filename(BlockDriverState *bs)
    940{
    941    BDRVCURLState *s = bs->opaque;
    942
    943    /* "readahead" and "timeout" do not change the guest-visible data,
    944     * so ignore them */
    945    if (s->sslverify != CURL_BLOCK_OPT_SSLVERIFY_DEFAULT ||
    946        s->cookie || s->username || s->password || s->proxyusername ||
    947        s->proxypassword)
    948    {
    949        return;
    950    }
    951
    952    pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), s->url);
    953}
    954
    955
    956static const char *const curl_strong_runtime_opts[] = {
    957    CURL_BLOCK_OPT_URL,
    958    CURL_BLOCK_OPT_SSLVERIFY,
    959    CURL_BLOCK_OPT_COOKIE,
    960    CURL_BLOCK_OPT_COOKIE_SECRET,
    961    CURL_BLOCK_OPT_USERNAME,
    962    CURL_BLOCK_OPT_PASSWORD_SECRET,
    963    CURL_BLOCK_OPT_PROXY_USERNAME,
    964    CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET,
    965
    966    NULL
    967};
    968
    969static BlockDriver bdrv_http = {
    970    .format_name                = "http",
    971    .protocol_name              = "http",
    972
    973    .instance_size              = sizeof(BDRVCURLState),
    974    .bdrv_parse_filename        = curl_parse_filename,
    975    .bdrv_file_open             = curl_open,
    976    .bdrv_close                 = curl_close,
    977    .bdrv_getlength             = curl_getlength,
    978
    979    .bdrv_co_preadv             = curl_co_preadv,
    980
    981    .bdrv_detach_aio_context    = curl_detach_aio_context,
    982    .bdrv_attach_aio_context    = curl_attach_aio_context,
    983
    984    .bdrv_refresh_filename      = curl_refresh_filename,
    985    .strong_runtime_opts        = curl_strong_runtime_opts,
    986};
    987
    988static BlockDriver bdrv_https = {
    989    .format_name                = "https",
    990    .protocol_name              = "https",
    991
    992    .instance_size              = sizeof(BDRVCURLState),
    993    .bdrv_parse_filename        = curl_parse_filename,
    994    .bdrv_file_open             = curl_open,
    995    .bdrv_close                 = curl_close,
    996    .bdrv_getlength             = curl_getlength,
    997
    998    .bdrv_co_preadv             = curl_co_preadv,
    999
   1000    .bdrv_detach_aio_context    = curl_detach_aio_context,
   1001    .bdrv_attach_aio_context    = curl_attach_aio_context,
   1002
   1003    .bdrv_refresh_filename      = curl_refresh_filename,
   1004    .strong_runtime_opts        = curl_strong_runtime_opts,
   1005};
   1006
   1007static BlockDriver bdrv_ftp = {
   1008    .format_name                = "ftp",
   1009    .protocol_name              = "ftp",
   1010
   1011    .instance_size              = sizeof(BDRVCURLState),
   1012    .bdrv_parse_filename        = curl_parse_filename,
   1013    .bdrv_file_open             = curl_open,
   1014    .bdrv_close                 = curl_close,
   1015    .bdrv_getlength             = curl_getlength,
   1016
   1017    .bdrv_co_preadv             = curl_co_preadv,
   1018
   1019    .bdrv_detach_aio_context    = curl_detach_aio_context,
   1020    .bdrv_attach_aio_context    = curl_attach_aio_context,
   1021
   1022    .bdrv_refresh_filename      = curl_refresh_filename,
   1023    .strong_runtime_opts        = curl_strong_runtime_opts,
   1024};
   1025
   1026static BlockDriver bdrv_ftps = {
   1027    .format_name                = "ftps",
   1028    .protocol_name              = "ftps",
   1029
   1030    .instance_size              = sizeof(BDRVCURLState),
   1031    .bdrv_parse_filename        = curl_parse_filename,
   1032    .bdrv_file_open             = curl_open,
   1033    .bdrv_close                 = curl_close,
   1034    .bdrv_getlength             = curl_getlength,
   1035
   1036    .bdrv_co_preadv             = curl_co_preadv,
   1037
   1038    .bdrv_detach_aio_context    = curl_detach_aio_context,
   1039    .bdrv_attach_aio_context    = curl_attach_aio_context,
   1040
   1041    .bdrv_refresh_filename      = curl_refresh_filename,
   1042    .strong_runtime_opts        = curl_strong_runtime_opts,
   1043};
   1044
   1045static void curl_block_init(void)
   1046{
   1047    bdrv_register(&bdrv_http);
   1048    bdrv_register(&bdrv_https);
   1049    bdrv_register(&bdrv_ftp);
   1050    bdrv_register(&bdrv_ftps);
   1051}
   1052
   1053block_init(curl_block_init);