Merge pull request #703 from simonduq/fix/json-buffer-overflows

Json library: fix a number of potential buffer overflows
This commit is contained in:
Simon Duquennoy 2018-10-24 12:16:38 +02:00 committed by GitHub
commit 42436cc486
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 61 additions and 47 deletions

View File

@ -32,34 +32,42 @@
#include "jsonparse.h" #include "jsonparse.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdbool.h>
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
static int static bool
push(struct jsonparse_state *state, char c) push(struct jsonparse_state *state, char c)
{ {
state->stack[state->depth] = c; if(state->depth < JSONPARSE_MAX_DEPTH) {
state->depth++; state->stack[state->depth] = c;
state->vtype = 0; state->depth++;
return state->depth < JSONPARSE_MAX_DEPTH; state->vtype = 0;
return true;
} else {
return false;
}
} }
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
static void static bool
modify(struct jsonparse_state *state, char c) modify(struct jsonparse_state *state, char c)
{ {
if(state->depth > 0) { if(state->depth > 0) {
state->stack[state->depth - 1] = c; state->stack[state->depth - 1] = c;
return true;
} else {
return false;
} }
} }
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
static char static bool
pop(struct jsonparse_state *state) pop(struct jsonparse_state *state)
{ {
if(state->depth == 0) { if(state->depth == 0) {
return JSON_TYPE_ERROR; return false;
} }
state->depth--; state->depth--;
state->vtype = state->stack[state->depth]; state->vtype = state->stack[state->depth];
return state->stack[state->depth]; return true;
} }
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
/* will pass by the value and store the start and length of the value for /* will pass by the value and store the start and length of the value for
@ -134,15 +142,11 @@ skip_ws(struct jsonparse_state *state)
} }
} }
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
static int static bool
is_atomic(struct jsonparse_state *state) is_atomic(struct jsonparse_state *state)
{ {
char v = state->vtype; char v = state->vtype;
if(v == 'N' || v == '"' || v == '0' || v == 'n' || v == 't' || v == 'f') { return v == 'N' || v == '"' || v == '0' || v == 'n' || v == 't' || v == 'f';
return 1;
} else {
return 0;
}
} }
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
void void
@ -163,6 +167,7 @@ jsonparse_next(struct jsonparse_state *state)
char c; char c;
char s; char s;
char v; char v;
bool ret;
skip_ws(state); skip_ws(state);
c = state->json[state->pos]; c = state->json[state->pos];
@ -173,48 +178,51 @@ jsonparse_next(struct jsonparse_state *state)
switch(c) { switch(c) {
case '{': case '{':
if((s == 0 && v == 0) || s == '[' || s == ':') { if((s == 0 && v == 0) || s == '[' || s == ':') {
push(state, c); if(push(state, c)) {
} else { return c;
state->error = JSON_ERROR_UNEXPECTED_OBJECT; }
return JSON_TYPE_ERROR;
} }
return c; state->error = JSON_ERROR_UNEXPECTED_OBJECT;
return JSON_TYPE_ERROR;
case '}': case '}':
if((s == ':' && v != ',' && v != 0 ) || (s == '{' && v == 0)) { if((s == ':' && v != ',' && v != 0 ) || (s == '{' && v == 0)) {
pop(state); if(pop(state)) {
} else { return c;
state->error = JSON_ERROR_UNEXPECTED_END_OF_OBJECT; }
return JSON_TYPE_ERROR;
} }
return c; state->error = JSON_ERROR_UNEXPECTED_END_OF_OBJECT;
return JSON_TYPE_ERROR;
case ']': case ']':
if(s == '[' && v != ',') { if(s == '[' && v != ',') {
pop(state); if(pop(state)) {
} else { return c;
state->error = JSON_ERROR_UNEXPECTED_END_OF_ARRAY; }
return JSON_TYPE_ERROR;
} }
return c; state->error = JSON_ERROR_UNEXPECTED_END_OF_ARRAY;
return JSON_TYPE_ERROR;
case ':': case ':':
if(s == '{' && v == 'N') { if(s == '{' && v == 'N') {
modify(state, ':'); ret = modify(state, ':');
state->vtype = 0; state->vtype = 0;
} else { if(ret) {
state->error = JSON_ERROR_SYNTAX; return jsonparse_next(state);
return JSON_TYPE_ERROR; }
} }
return jsonparse_next(state); state->error = JSON_ERROR_SYNTAX;
return JSON_TYPE_ERROR;
case ',': case ',':
if(s == ':' && v != 0) { if(s == ':' && v != 0) {
modify(state, '{'); ret = modify(state, '{');
state->vtype = c; state->vtype = c;
if(ret) {
return c;
}
} else if(s == '[') { } else if(s == '[') {
state->vtype = c; state->vtype = c;
} else { return c;
state->error = JSON_ERROR_SYNTAX;
return JSON_TYPE_ERROR;
} }
return c; state->error = JSON_ERROR_SYNTAX;
return JSON_TYPE_ERROR;
case '"': case '"':
if((s == 0 && v == 0) || s == '{' || s == '[' || s == ':') { if((s == 0 && v == 0) || s == '{' || s == '[' || s == ':') {
return atomic(state, c = (s == '{' ? JSON_TYPE_PAIR_NAME : c)); return atomic(state, c = (s == '{' ? JSON_TYPE_PAIR_NAME : c));
@ -225,12 +233,12 @@ jsonparse_next(struct jsonparse_state *state)
return c; return c;
case '[': case '[':
if((s == 0 && v == 0) || s == '[' || s == ':') { if((s == 0 && v == 0) || s == '[' || s == ':') {
push(state, c); if(push(state, c)) {
} else { return c;
state->error = JSON_ERROR_UNEXPECTED_ARRAY; }
return JSON_TYPE_ERROR;
} }
return c; state->error = JSON_ERROR_UNEXPECTED_ARRAY;
return JSON_TYPE_ERROR;
case 0: case 0:
if(v == 0 || state->depth > 0) { if(v == 0 || state->depth > 0) {
state->error = JSON_ERROR_SYNTAX; state->error = JSON_ERROR_SYNTAX;

View File

@ -198,7 +198,10 @@ jsontree_print_next(struct jsontree_context *js_ctx)
} else { } else {
ov = o->values[index]; ov = o->values[index];
} }
/* TODO check max depth */ if(js_ctx->depth >= JSONTREE_MAX_DEPTH - 1) {
/* Too deep: return 0 */
return 0;
}
js_ctx->depth++; /* step down to value... */ js_ctx->depth++; /* step down to value... */
js_ctx->index[js_ctx->depth] = 0; /* and init index */ js_ctx->index[js_ctx->depth] = 0; /* and init index */
js_ctx->values[js_ctx->depth] = ov; js_ctx->values[js_ctx->depth] = ov;
@ -299,7 +302,10 @@ find_next(struct jsontree_context *js_ctx)
} else { } else {
ov = o->values[index]; ov = o->values[index];
} }
/* TODO check max depth */ if(js_ctx->depth >= JSONTREE_MAX_DEPTH - 1) {
/* Too deep: return NULL */
return NULL;
}
js_ctx->depth++; /* step down to value... */ js_ctx->depth++; /* step down to value... */
js_ctx->index[js_ctx->depth] = 0; /* and init index */ js_ctx->index[js_ctx->depth] = 0; /* and init index */
js_ctx->values[js_ctx->depth] = ov; js_ctx->values[js_ctx->depth] = ov;