diff options
author | ZyX <kp-pav@yandex.ru> | 2016-03-07 07:10:38 +0300 |
---|---|---|
committer | ZyX <kp-pav@yandex.ru> | 2016-04-18 02:48:20 +0300 |
commit | 4eb5d05f018bc568580c85f17ddb304fcec364ca (patch) | |
tree | 012fd9a854f1febe2879252ee3d34775b04919fd | |
parent | 4a29995fe74ed95c641ef40c68d8a4223e90cccf (diff) | |
download | rneovim-4eb5d05f018bc568580c85f17ddb304fcec364ca.tar.gz rneovim-4eb5d05f018bc568580c85f17ddb304fcec364ca.tar.bz2 rneovim-4eb5d05f018bc568580c85f17ddb304fcec364ca.zip |
eval/decode: Avoid overflow when parsing incomplete null/true/false
Note: second test does not crash or produce asan errors, even though it should.
-rw-r--r-- | src/nvim/eval/decode.c | 6 | ||||
-rw-r--r-- | test/unit/eval/decode_spec.lua | 65 |
2 files changed, 68 insertions, 3 deletions
diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c index fc6e912c20..35e8421716 100644 --- a/src/nvim/eval/decode.c +++ b/src/nvim/eval/decode.c @@ -334,7 +334,7 @@ json_decode_string_cycle_start: continue; } case 'n': { - if (strncmp(p + 1, "ull", 3) != 0) { + if ((p + 3) >= e || strncmp(p + 1, "ull", 3) != 0) { EMSG2(_("E474: Expected null: %s"), p); goto json_decode_string_fail; } @@ -347,7 +347,7 @@ json_decode_string_cycle_start: break; } case 't': { - if (strncmp(p + 1, "rue", 3) != 0) { + if ((p + 3) >= e || strncmp(p + 1, "rue", 3) != 0) { EMSG2(_("E474: Expected true: %s"), p); goto json_decode_string_fail; } @@ -360,7 +360,7 @@ json_decode_string_cycle_start: break; } case 'f': { - if (strncmp(p + 1, "alse", 4) != 0) { + if ((p + 4) >= e || strncmp(p + 1, "alse", 4) != 0) { EMSG2(_("E474: Expected false: %s"), p); goto json_decode_string_fail; } diff --git a/test/unit/eval/decode_spec.lua b/test/unit/eval/decode_spec.lua new file mode 100644 index 0000000000..6ae000a00a --- /dev/null +++ b/test/unit/eval/decode_spec.lua @@ -0,0 +1,65 @@ +local ffi = require('ffi') +local helpers = require('test.unit.helpers') +local eval_helpers = require('test.unit.eval.helpers') + +local cimport = helpers.cimport +local to_cstr = helpers.to_cstr +local eq = helpers.eq + +local list = eval_helpers.list +local lst2tbl = eval_helpers.lst2tbl +local type_key = eval_helpers.type_key +local list_type = eval_helpers.list_type +local null_string = eval_helpers.null_string + +local decode = cimport('./src/nvim/eval/decode.h', './src/nvim/eval_defs.h', + './src/nvim/globals.h', './src/nvim/memory.h') + +describe('json_decode_string()', function() + after_each(function() + decode.emsg_silent = 0 + end) + + it('does not overflow when running with `n…`, `t…`, `f…`', function() + local rettv = ffi.new('typval_T') + decode.emsg_silent = 1 + rettv.v_type = decode.VAR_UNKNOWN + -- This will not crash, but if `len` argument will be ignored it will parse + -- `null` as `null` and if not it will parse `null` as `n`. + eq(0, decode.json_decode_string('null', 1, rettv)) + eq(decode.VAR_UNKNOWN, rettv.v_type) + eq(0, decode.json_decode_string('true', 1, rettv)) + eq(decode.VAR_UNKNOWN, rettv.v_type) + eq(0, decode.json_decode_string('false', 1, rettv)) + eq(decode.VAR_UNKNOWN, rettv.v_type) + eq(0, decode.json_decode_string('null', 2, rettv)) + eq(decode.VAR_UNKNOWN, rettv.v_type) + eq(0, decode.json_decode_string('true', 2, rettv)) + eq(decode.VAR_UNKNOWN, rettv.v_type) + eq(0, decode.json_decode_string('false', 2, rettv)) + eq(decode.VAR_UNKNOWN, rettv.v_type) + eq(0, decode.json_decode_string('null', 3, rettv)) + eq(decode.VAR_UNKNOWN, rettv.v_type) + eq(0, decode.json_decode_string('true', 3, rettv)) + eq(decode.VAR_UNKNOWN, rettv.v_type) + eq(0, decode.json_decode_string('false', 3, rettv)) + eq(decode.VAR_UNKNOWN, rettv.v_type) + eq(0, decode.json_decode_string('false', 4, rettv)) + eq(decode.VAR_UNKNOWN, rettv.v_type) + end) + + it('does not overflow and crash when running with `n`, `t`, `f`', function() + local rettv = ffi.new('typval_T') + decode.emsg_silent = 1 + rettv.v_type = decode.VAR_UNKNOWN + local char = function(c) + return ffi.gc(decode.xmemdup(c, 1), decode.xfree) + end + eq(0, decode.json_decode_string(char('n'), 1, rettv)) + eq(decode.VAR_UNKNOWN, rettv.v_type) + eq(0, decode.json_decode_string(char('t'), 1, rettv)) + eq(decode.VAR_UNKNOWN, rettv.v_type) + eq(0, decode.json_decode_string(char('f'), 1, rettv)) + eq(decode.VAR_UNKNOWN, rettv.v_type) + end) +end) |