aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZyX <kp-pav@yandex.ru>2016-03-07 07:10:38 +0300
committerZyX <kp-pav@yandex.ru>2016-04-18 02:48:20 +0300
commit4eb5d05f018bc568580c85f17ddb304fcec364ca (patch)
tree012fd9a854f1febe2879252ee3d34775b04919fd
parent4a29995fe74ed95c641ef40c68d8a4223e90cccf (diff)
downloadrneovim-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.c6
-rw-r--r--test/unit/eval/decode_spec.lua65
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)