vim-patch:9.2.0738: ml_recover() may write beyond block buffer (#40446)

Problem:  A crafted swap file can cause an out-of-bounds write during
          recovery when the same block is referenced twice with
          different pe_page_count values (cipher-creator)
Solution: Check hp->bh_page_count against page_count after mf_get() and
          clamp page_count to the actual block size.

closes: vim/vim#20645

43939cf9eb

Co-authored-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
zeertzjq
2026-06-27 17:21:05 +08:00
committed by GitHub
parent 6a61c81e31
commit f3fbb3928c
3 changed files with 27 additions and 2 deletions

View File

@@ -1111,6 +1111,18 @@ void ml_recover(bool checkext)
// Append all the lines in this block.
bool has_error = false;
// Verify the cached block's actual size matches the
// pointer entry's pe_page_count. mf_get() cache hits
// return the original block without resizing, so a
// crafted swap file referencing the same block twice
// with different pe_page_count values would cause an
// OOB write below.
if (hp->bh_page_count != page_count) {
error++;
ml_append(lnum++, _("??? BLOCK PAGE COUNT MISMATCH"), 0, true);
page_count = hp->bh_page_count;
}
// Check the length of the block.
// If wrong, use the length given in the pointer block.
if (page_count * mfp->mf_page_size != dp->db_txt_end) {

Binary file not shown.

View File

@@ -519,8 +519,8 @@ func Test_recover_corrupted_swap_file1()
call assert_match('???ILLEGAL BLOCK NUMBER', content)
call delete(target)
bw!
"
" " Test 2: Segfault
" Test 2: Segfault
new
let sample = 'samples/recover-crash2.swp'
let target = '.Xpoc2.swp' " Xpoc1.swp (non-hidden) doesn't work in Nvim
@@ -536,6 +536,19 @@ func Test_recover_corrupted_swap_file1()
call assert_match('???LINES MISSING', content)
call delete(target)
bw!
" Test 3: wrong page_count header
new
let sample = 'samples/recover-mismatch-pc.swp'
let target = 'Xmismatch-pc.swp'
call writefile(readblob(sample), target, 'bD')
try
sil noa recover! Xmismatch-pc.swp
catch
endtry
" Verifies no crash occurs. The OOB write is only reliably triggered
" interactively due to memory pressure evicting blocks in the test runner.
bw!
endfunc
" vim: shiftwidth=2 sts=2 expandtab