diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2012-03-22 12:51:10 +0100 |
---|---|---|
committer | Luiz Capitulino <lcapitulino@redhat.com> | 2012-03-27 09:15:13 -0300 |
commit | e38ac9621c8ab51880b9e6e833a125342d6b46b2 (patch) | |
tree | 9221097ab672970e8929da9827f9a34ecb02a1e2 /qapi | |
parent | 4faaec6acf7f18b39c362edb9f6aa5658aab8b85 (diff) |
qapi: add strict mode to input visitor
While QMP in general is designed so that it is possible to ignore
unknown arguments, in the case of the QMP server it is better to
reject them to detect bad clients. In fact, we're already doing
this at the top level in the argument checker. To extend this to
complex structures, add a mode to the input visitor where it checks
for unvisited keys and raises an error if it finds one.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Diffstat (limited to 'qapi')
-rw-r--r-- | qapi/qmp-input-visitor.c | 48 | ||||
-rw-r--r-- | qapi/qmp-input-visitor.h | 2 |
2 files changed, 47 insertions, 3 deletions
diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c index 5765e76e43..74386b9b1b 100644 --- a/qapi/qmp-input-visitor.c +++ b/qapi/qmp-input-visitor.c @@ -24,6 +24,7 @@ typedef struct StackObject { QObject *obj; const QListEntry *entry; + GHashTable *h; } StackObject; struct QmpInputVisitor @@ -31,6 +32,7 @@ struct QmpInputVisitor Visitor visitor; StackObject stack[QIV_STACK_SIZE]; int nb_stack; + bool strict; }; static QmpInputVisitor *to_qiv(Visitor *v) @@ -45,6 +47,9 @@ static QObject *qmp_input_get_object(QmpInputVisitor *qiv, if (qobj) { if (name && qobject_type(qobj) == QTYPE_QDICT) { + if (qiv->stack[qiv->nb_stack - 1].h) { + g_hash_table_remove(qiv->stack[qiv->nb_stack - 1].h, name); + } return qdict_get(qobject_to_qdict(qobj), name); } else if (qiv->stack[qiv->nb_stack - 1].entry) { return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry); @@ -54,20 +59,47 @@ static QObject *qmp_input_get_object(QmpInputVisitor *qiv, return qobj; } +static void qdict_add_key(const char *key, QObject *obj, void *opaque) +{ + GHashTable *h = opaque; + g_hash_table_insert(h, (gpointer) key, NULL); +} + static void qmp_input_push(QmpInputVisitor *qiv, QObject *obj, Error **errp) { - qiv->stack[qiv->nb_stack].obj = obj; - qiv->stack[qiv->nb_stack].entry = NULL; - qiv->nb_stack++; + GHashTable *h; if (qiv->nb_stack >= QIV_STACK_SIZE) { error_set(errp, QERR_BUFFER_OVERRUN); return; } + + qiv->stack[qiv->nb_stack].obj = obj; + qiv->stack[qiv->nb_stack].entry = NULL; + qiv->stack[qiv->nb_stack].h = NULL; + + if (qiv->strict && qobject_type(obj) == QTYPE_QDICT) { + h = g_hash_table_new(g_str_hash, g_str_equal); + qdict_iter(qobject_to_qdict(obj), qdict_add_key, h); + qiv->stack[qiv->nb_stack].h = h; + } + + qiv->nb_stack++; } static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp) { + GHashTableIter iter; + gpointer key; + + if (qiv->strict && qiv->stack[qiv->nb_stack - 1].h) { + g_hash_table_iter_init(&iter, qiv->stack[qiv->nb_stack - 1].h); + if (g_hash_table_iter_next(&iter, &key, NULL)) { + error_set(errp, QERR_QMP_EXTRA_MEMBER, (char *) key); + } + g_hash_table_unref(qiv->stack[qiv->nb_stack - 1].h); + } + assert(qiv->nb_stack > 0); qiv->nb_stack--; } @@ -262,3 +294,13 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj) return v; } + +QmpInputVisitor *qmp_input_visitor_new_strict(QObject *obj) +{ + QmpInputVisitor *v; + + v = qmp_input_visitor_new(obj); + v->strict = true; + + return v; +} diff --git a/qapi/qmp-input-visitor.h b/qapi/qmp-input-visitor.h index 3f798f0335..e0a48a5f3b 100644 --- a/qapi/qmp-input-visitor.h +++ b/qapi/qmp-input-visitor.h @@ -20,6 +20,8 @@ typedef struct QmpInputVisitor QmpInputVisitor; QmpInputVisitor *qmp_input_visitor_new(QObject *obj); +QmpInputVisitor *qmp_input_visitor_new_strict(QObject *obj); + void qmp_input_visitor_cleanup(QmpInputVisitor *v); Visitor *qmp_input_get_visitor(QmpInputVisitor *v); |