Since older yajl ignores trailing garbage, a client can cause
problems by intentionally ending the wrapper array early. Since
we already track nesting, it's not too much harder to reject
invalid nesting pops.
* src/util/virjson. (_virJSONParser): Add field.
(virJSONValueFromString): Set witness.
(virJSONParserHandleEndArray): Use it to catch abuse.
* tests/jsontest.c (mymain): Test it.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
Could be squashed with 3/3, if desired.
src/util/virjson.c | 7 +++++--
tests/jsontest.c | 1 +
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/util/virjson.c b/src/util/virjson.c
index a33005a..3c6ed34 100644
--- a/src/util/virjson.c
+++ b/src/util/virjson.c
@@ -64,6 +64,7 @@ struct _virJSONParser {
virJSONValuePtr head;
virJSONParserStatePtr state;
size_t nstate;
+ int wrap;
};
@@ -1556,7 +1557,7 @@ virJSONParserHandleEndArray(void *ctx)
VIR_DEBUG("parser=%p", parser);
- if (!parser->nstate)
+ if (!(parser->nstate - parser->wrap))
return 0;
state = &(parser->state[parser->nstate-1]);
@@ -1591,7 +1592,7 @@ virJSONValuePtr
virJSONValueFromString(const char *jsonstring)
{
yajl_handle hand;
- virJSONParser parser = { NULL, NULL, 0 };
+ virJSONParser parser = { NULL, NULL, 0, 0 };
virJSONValuePtr ret = NULL;
int rc;
size_t len = strlen(jsonstring);
@@ -1627,8 +1628,10 @@ virJSONValueFromString(const char *jsonstring)
rc = yajl_parse(hand, (const unsigned char *)jsonstring, len);
# else
rc = yajl_parse(hand, (const unsigned char *)"[", 1);
+ parser.wrap = 1;
if (VIR_YAJL_STATUS_OK(rc))
rc = yajl_parse(hand, (const unsigned char *)jsonstring, len);
+ parser.wrap = 0;
if (VIR_YAJL_STATUS_OK(rc))
rc = yajl_parse(hand, (const unsigned char *)"]", 1);
# endif
diff --git a/tests/jsontest.c b/tests/jsontest.c
index a363dc0..97b9c0a 100644
--- a/tests/jsontest.c
+++ b/tests/jsontest.c
@@ -421,6 +421,7 @@ mymain(void)
DO_TEST_PARSE_FAIL("comments", "[ /* nope */\n1 // not this
either\n]");
DO_TEST_PARSE_FAIL("trailing garbage", "[] []");
DO_TEST_PARSE_FAIL("list without array", "1, 1");
+ DO_TEST_PARSE_FAIL("parser abuse", "1] [2");
DO_TEST_PARSE_FAIL("object with numeric keys", "{ 1:1, 2:1, 3:2
}");
DO_TEST_PARSE_FAIL("unterminated object", "{ \"1\":1,
\"2\":1, \"3\":2");
--
2.4.3