From f1833490a046611c90d8be31cab2ef9d5d055056 Mon Sep 17 00:00:00 2001 From: Volodymyr Chernetskyi Date: Fri, 4 Sep 2026 18:48:55 +0200 Subject: [PATCH] fix(msgpack): out-of-bounds read on a truncated string #41683 Problem: `unpack_string()` validates the declared length against `*size`, the size *before* `mpack_rtoken()` consumed the token header, rather than `size2`, the remainder after it. The header is one to five bytes, so any declared length in the window `(size2, *size]` slips through. The returned `String` then covers up to five bytes past the end of the buffer, and `size2 - tok.length` underflows, leaving `*size` near `SIZE_MAX` so every later unpack call on that entry believes it has an unbounded buffer. Reachable from ShaDa, where a history entry ending in a five-byte string header followed by four bytes is enough, so a corrupted or hostile `main.shada` triggers it at startup. Solution: Check the remainder left after the header. AI-assisted --- src/nvim/msgpack_rpc/unpacker.c | 2 +- test/functional/shada/errors_spec.lua | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/nvim/msgpack_rpc/unpacker.c b/src/nvim/msgpack_rpc/unpacker.c index fcad91d236..8d1e9c4c28 100644 --- a/src/nvim/msgpack_rpc/unpacker.c +++ b/src/nvim/msgpack_rpc/unpacker.c @@ -542,7 +542,7 @@ String unpack_string(const char **data, size_t *size) if (result || (tok.type != MPACK_TOKEN_STR && tok.type != MPACK_TOKEN_BIN)) { return (String)STRING_INIT; } - if (*size < tok.length) { + if (size2 < tok.length) { // result = MPACK_EOF; return (String)STRING_INIT; } diff --git a/test/functional/shada/errors_spec.lua b/test/functional/shada/errors_spec.lua index 1ab68b2bf2..edfc6f088c 100644 --- a/test/functional/shada/errors_spec.lua +++ b/test/functional/shada/errors_spec.lua @@ -404,6 +404,15 @@ describe('ShaDa error handling', function() ) end) + it('fails on history item with truncated string', function() + -- The string header declares five bytes, but only four follow it. + wshada('\004\000\007\146\000\165AAAA') + eq( + 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 has wrong history string type', + t.pcall_err(nvim_command, sdrcmd()) + ) + end) + it('fails on history item with second item with zero byte', function() wshada('\004\000\007\146\000\196\003ab\000') eq(