diff --git a/src/nvim/memline.c b/src/nvim/memline.c index c1d0884c00..84d9d23323 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -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) { diff --git a/test/old/testdir/samples/recover-mismatch-pc.swp b/test/old/testdir/samples/recover-mismatch-pc.swp new file mode 100644 index 0000000000..dd5a1fa083 Binary files /dev/null and b/test/old/testdir/samples/recover-mismatch-pc.swp differ diff --git a/test/old/testdir/test_recover.vim b/test/old/testdir/test_recover.vim index 2a5c453406..2233536710 100644 --- a/test/old/testdir/test_recover.vim +++ b/test/old/testdir/test_recover.vim @@ -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