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

string-input-visitor.c (10740B)


      1/*
      2 * String parsing visitor
      3 *
      4 * Copyright Red Hat, Inc. 2012-2016
      5 *
      6 * Author: Paolo Bonzini <pbonzini@redhat.com>
      7 *         David Hildenbrand <david@redhat.com>
      8 *
      9 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
     10 * See the COPYING.LIB file in the top-level directory.
     11 */
     12
     13#include "qemu/osdep.h"
     14#include "qapi/error.h"
     15#include "qapi/string-input-visitor.h"
     16#include "qapi/visitor-impl.h"
     17#include "qapi/qmp/qerror.h"
     18#include "qapi/qmp/qnull.h"
     19#include "qemu/option.h"
     20#include "qemu/cutils.h"
     21
     22typedef enum ListMode {
     23    /* no list parsing active / no list expected */
     24    LM_NONE,
     25    /* we have an unparsed string remaining */
     26    LM_UNPARSED,
     27    /* we have an unfinished int64 range */
     28    LM_INT64_RANGE,
     29    /* we have an unfinished uint64 range */
     30    LM_UINT64_RANGE,
     31    /* we have parsed the string completely and no range is remaining */
     32    LM_END,
     33} ListMode;
     34
     35/* protect against DOS attacks, limit the amount of elements per range */
     36#define RANGE_MAX_ELEMENTS 65536
     37
     38typedef union RangeElement {
     39    int64_t i64;
     40    uint64_t u64;
     41} RangeElement;
     42
     43struct StringInputVisitor
     44{
     45    Visitor visitor;
     46
     47    /* List parsing state */
     48    ListMode lm;
     49    RangeElement rangeNext;
     50    RangeElement rangeEnd;
     51    const char *unparsed_string;
     52    void *list;
     53
     54    /* The original string to parse */
     55    const char *string;
     56};
     57
     58static StringInputVisitor *to_siv(Visitor *v)
     59{
     60    return container_of(v, StringInputVisitor, visitor);
     61}
     62
     63static bool start_list(Visitor *v, const char *name, GenericList **list,
     64                       size_t size, Error **errp)
     65{
     66    StringInputVisitor *siv = to_siv(v);
     67
     68    assert(siv->lm == LM_NONE);
     69    siv->list = list;
     70    siv->unparsed_string = siv->string;
     71
     72    if (!siv->string[0]) {
     73        if (list) {
     74            *list = NULL;
     75        }
     76        siv->lm = LM_END;
     77    } else {
     78        if (list) {
     79            *list = g_malloc0(size);
     80        }
     81        siv->lm = LM_UNPARSED;
     82    }
     83    return true;
     84}
     85
     86static GenericList *next_list(Visitor *v, GenericList *tail, size_t size)
     87{
     88    StringInputVisitor *siv = to_siv(v);
     89
     90    switch (siv->lm) {
     91    case LM_END:
     92        return NULL;
     93    case LM_INT64_RANGE:
     94    case LM_UINT64_RANGE:
     95    case LM_UNPARSED:
     96        /* we have an unparsed string or something left in a range */
     97        break;
     98    default:
     99        abort();
    100    }
    101
    102    tail->next = g_malloc0(size);
    103    return tail->next;
    104}
    105
    106static bool check_list(Visitor *v, Error **errp)
    107{
    108    const StringInputVisitor *siv = to_siv(v);
    109
    110    switch (siv->lm) {
    111    case LM_INT64_RANGE:
    112    case LM_UINT64_RANGE:
    113    case LM_UNPARSED:
    114        error_setg(errp, "Fewer list elements expected");
    115        return false;
    116    case LM_END:
    117        return true;
    118    default:
    119        abort();
    120    }
    121}
    122
    123static void end_list(Visitor *v, void **obj)
    124{
    125    StringInputVisitor *siv = to_siv(v);
    126
    127    assert(siv->lm != LM_NONE);
    128    assert(siv->list == obj);
    129    siv->list = NULL;
    130    siv->unparsed_string = NULL;
    131    siv->lm = LM_NONE;
    132}
    133
    134static int try_parse_int64_list_entry(StringInputVisitor *siv, int64_t *obj)
    135{
    136    const char *endptr;
    137    int64_t start, end;
    138
    139    /* parse a simple int64 or range */
    140    if (qemu_strtoi64(siv->unparsed_string, &endptr, 0, &start)) {
    141        return -EINVAL;
    142    }
    143    end = start;
    144
    145    switch (endptr[0]) {
    146    case '\0':
    147        siv->unparsed_string = endptr;
    148        break;
    149    case ',':
    150        siv->unparsed_string = endptr + 1;
    151        break;
    152    case '-':
    153        /* parse the end of the range */
    154        if (qemu_strtoi64(endptr + 1, &endptr, 0, &end)) {
    155            return -EINVAL;
    156        }
    157        if (start > end || end - start >= RANGE_MAX_ELEMENTS) {
    158            return -EINVAL;
    159        }
    160        switch (endptr[0]) {
    161        case '\0':
    162            siv->unparsed_string = endptr;
    163            break;
    164        case ',':
    165            siv->unparsed_string = endptr + 1;
    166            break;
    167        default:
    168            return -EINVAL;
    169        }
    170        break;
    171    default:
    172        return -EINVAL;
    173    }
    174
    175    /* we have a proper range (with maybe only one element) */
    176    siv->lm = LM_INT64_RANGE;
    177    siv->rangeNext.i64 = start;
    178    siv->rangeEnd.i64 = end;
    179    return 0;
    180}
    181
    182static bool parse_type_int64(Visitor *v, const char *name, int64_t *obj,
    183                             Error **errp)
    184{
    185    StringInputVisitor *siv = to_siv(v);
    186    int64_t val;
    187
    188    switch (siv->lm) {
    189    case LM_NONE:
    190        /* just parse a simple int64, bail out if not completely consumed */
    191        if (qemu_strtoi64(siv->string, NULL, 0, &val)) {
    192            error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
    193                       name ? name : "null", "int64");
    194            return false;
    195        }
    196        *obj = val;
    197        return true;
    198    case LM_UNPARSED:
    199        if (try_parse_int64_list_entry(siv, obj)) {
    200            error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
    201                       "list of int64 values or ranges");
    202            return false;
    203        }
    204        assert(siv->lm == LM_INT64_RANGE);
    205        /* fall through */
    206    case LM_INT64_RANGE:
    207        /* return the next element in the range */
    208        assert(siv->rangeNext.i64 <= siv->rangeEnd.i64);
    209        *obj = siv->rangeNext.i64++;
    210
    211        if (siv->rangeNext.i64 > siv->rangeEnd.i64 || *obj == INT64_MAX) {
    212            /* end of range, check if there is more to parse */
    213            siv->lm = siv->unparsed_string[0] ? LM_UNPARSED : LM_END;
    214        }
    215        return true;
    216    case LM_END:
    217        error_setg(errp, "Fewer list elements expected");
    218        return false;
    219    default:
    220        abort();
    221    }
    222}
    223
    224static int try_parse_uint64_list_entry(StringInputVisitor *siv, uint64_t *obj)
    225{
    226    const char *endptr;
    227    uint64_t start, end;
    228
    229    /* parse a simple uint64 or range */
    230    if (qemu_strtou64(siv->unparsed_string, &endptr, 0, &start)) {
    231        return -EINVAL;
    232    }
    233    end = start;
    234
    235    switch (endptr[0]) {
    236    case '\0':
    237        siv->unparsed_string = endptr;
    238        break;
    239    case ',':
    240        siv->unparsed_string = endptr + 1;
    241        break;
    242    case '-':
    243        /* parse the end of the range */
    244        if (qemu_strtou64(endptr + 1, &endptr, 0, &end)) {
    245            return -EINVAL;
    246        }
    247        if (start > end || end - start >= RANGE_MAX_ELEMENTS) {
    248            return -EINVAL;
    249        }
    250        switch (endptr[0]) {
    251        case '\0':
    252            siv->unparsed_string = endptr;
    253            break;
    254        case ',':
    255            siv->unparsed_string = endptr + 1;
    256            break;
    257        default:
    258            return -EINVAL;
    259        }
    260        break;
    261    default:
    262        return -EINVAL;
    263    }
    264
    265    /* we have a proper range (with maybe only one element) */
    266    siv->lm = LM_UINT64_RANGE;
    267    siv->rangeNext.u64 = start;
    268    siv->rangeEnd.u64 = end;
    269    return 0;
    270}
    271
    272static bool parse_type_uint64(Visitor *v, const char *name, uint64_t *obj,
    273                              Error **errp)
    274{
    275    StringInputVisitor *siv = to_siv(v);
    276    uint64_t val;
    277
    278    switch (siv->lm) {
    279    case LM_NONE:
    280        /* just parse a simple uint64, bail out if not completely consumed */
    281        if (qemu_strtou64(siv->string, NULL, 0, &val)) {
    282            error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
    283                       "uint64");
    284            return false;
    285        }
    286        *obj = val;
    287        return true;
    288    case LM_UNPARSED:
    289        if (try_parse_uint64_list_entry(siv, obj)) {
    290            error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
    291                       "list of uint64 values or ranges");
    292            return false;
    293        }
    294        assert(siv->lm == LM_UINT64_RANGE);
    295        /* fall through */
    296    case LM_UINT64_RANGE:
    297        /* return the next element in the range */
    298        assert(siv->rangeNext.u64 <= siv->rangeEnd.u64);
    299        *obj = siv->rangeNext.u64++;
    300
    301        if (siv->rangeNext.u64 > siv->rangeEnd.u64 || *obj == UINT64_MAX) {
    302            /* end of range, check if there is more to parse */
    303            siv->lm = siv->unparsed_string[0] ? LM_UNPARSED : LM_END;
    304        }
    305        return true;
    306    case LM_END:
    307        error_setg(errp, "Fewer list elements expected");
    308        return false;
    309    default:
    310        abort();
    311    }
    312}
    313
    314static bool parse_type_size(Visitor *v, const char *name, uint64_t *obj,
    315                            Error **errp)
    316{
    317    StringInputVisitor *siv = to_siv(v);
    318    uint64_t val;
    319
    320    assert(siv->lm == LM_NONE);
    321    if (!parse_option_size(name, siv->string, &val, errp)) {
    322        return false;
    323    }
    324
    325    *obj = val;
    326    return true;
    327}
    328
    329static bool parse_type_bool(Visitor *v, const char *name, bool *obj,
    330                            Error **errp)
    331{
    332    StringInputVisitor *siv = to_siv(v);
    333
    334    assert(siv->lm == LM_NONE);
    335    return qapi_bool_parse(name ? name : "null", siv->string, obj, errp);
    336}
    337
    338static bool parse_type_str(Visitor *v, const char *name, char **obj,
    339                           Error **errp)
    340{
    341    StringInputVisitor *siv = to_siv(v);
    342
    343    assert(siv->lm == LM_NONE);
    344    *obj = g_strdup(siv->string);
    345    return true;
    346}
    347
    348static bool parse_type_number(Visitor *v, const char *name, double *obj,
    349                              Error **errp)
    350{
    351    StringInputVisitor *siv = to_siv(v);
    352    double val;
    353
    354    assert(siv->lm == LM_NONE);
    355    if (qemu_strtod_finite(siv->string, NULL, &val)) {
    356        error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
    357                   "number");
    358        return false;
    359    }
    360
    361    *obj = val;
    362    return true;
    363}
    364
    365static bool parse_type_null(Visitor *v, const char *name, QNull **obj,
    366                            Error **errp)
    367{
    368    StringInputVisitor *siv = to_siv(v);
    369
    370    assert(siv->lm == LM_NONE);
    371    *obj = NULL;
    372
    373    if (siv->string[0]) {
    374        error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
    375                   "null");
    376        return false;
    377    }
    378
    379    *obj = qnull();
    380    return true;
    381}
    382
    383static void string_input_free(Visitor *v)
    384{
    385    StringInputVisitor *siv = to_siv(v);
    386
    387    g_free(siv);
    388}
    389
    390Visitor *string_input_visitor_new(const char *str)
    391{
    392    StringInputVisitor *v;
    393
    394    assert(str);
    395    v = g_malloc0(sizeof(*v));
    396
    397    v->visitor.type = VISITOR_INPUT;
    398    v->visitor.type_int64 = parse_type_int64;
    399    v->visitor.type_uint64 = parse_type_uint64;
    400    v->visitor.type_size = parse_type_size;
    401    v->visitor.type_bool = parse_type_bool;
    402    v->visitor.type_str = parse_type_str;
    403    v->visitor.type_number = parse_type_number;
    404    v->visitor.type_null = parse_type_null;
    405    v->visitor.start_list = start_list;
    406    v->visitor.next_list = next_list;
    407    v->visitor.check_list = check_list;
    408    v->visitor.end_list = end_list;
    409    v->visitor.free = string_input_free;
    410
    411    v->string = str;
    412    v->lm = LM_NONE;
    413    return &v->visitor;
    414}