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
This commit is contained in:
Volodymyr Chernetskyi
2026-09-04 18:48:55 +02:00
committed by GitHub
parent 0a173b09f4
commit f1833490a0
2 changed files with 10 additions and 1 deletions

View File

@@ -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;
}

View File

@@ -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(