From 1813e1c089bbcef54ee34d8807c3798e45bbc146 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 16 May 2026 08:07:22 +0800 Subject: [PATCH] vim-patch:9.2.0486: out-of-bound read when recovering swap files (#39807) Problem: out-of-bound read when recovering corrupted swap files (Rahul Hoysala) Solution: Validate the db_txt_start field when recovering a swap file. Supported by AI https://github.com/vim/vim/commit/de7a5b5425811169f589a7a3492696e8dedf8d68 Co-authored-by: Christian Brabandt --- runtime/doc/recover.txt | 5 +++++ src/nvim/memline.c | 6 ++++++ test/old/testdir/test_recover.vim | 14 ++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/runtime/doc/recover.txt b/runtime/doc/recover.txt index c07e9e3efb..ce90d52779 100644 --- a/runtime/doc/recover.txt +++ b/runtime/doc/recover.txt @@ -182,5 +182,10 @@ recovered file. Or use |:DiffOrig|. Once you are sure the recovery is ok delete the swap file. Otherwise, you will continue to get warning messages that the ".swp" file already exists. +Note: Recovering swap files is best-effort. Vim attempts to validate fields +and skip corrupted sections, but the swap file format is intended for files +you trust. A crafted swap file may trigger parser bugs; such reports are +treated as robustness issues rather than security vulnerabilities. + vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 7ae4abf667..371b4013c8 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -1123,6 +1123,12 @@ void ml_recover(bool checkext) dp->db_txt_end = page_count * mfp->mf_page_size; } + if (dp->db_txt_start < HEADER_SIZE || dp->db_txt_start > dp->db_txt_end) { + ml_append(lnum++, _("??? block header corrupted"), 0, true); + error++; + has_error = true; + dp->db_txt_start = dp->db_txt_end; + } // Make sure there is a NUL at the end of the block so we // don't go over the end when copying text. *((char *)dp + dp->db_txt_end - 1) = NUL; diff --git a/test/old/testdir/test_recover.vim b/test/old/testdir/test_recover.vim index 52abc25778..c33427572e 100644 --- a/test/old/testdir/test_recover.vim +++ b/test/old/testdir/test_recover.vim @@ -349,7 +349,21 @@ func Test_recover_corrupted_swap_file() call assert_fails('recover Xfile1', 'E312:') call assert_equal('Xfile1', @%) call assert_equal(['???MANY LINES MISSING'], getline(1, '$')) + bw! + " use an out-of-bounds db_txt_start in the data block (would cause OOB + " read past dp->db_index[] in ml_recover() without the bounds check) + let b = copy(save_b) + let b[8200:8203] = s:little_endian ? 0zFEFFFFFF : 0zFFFFFFFE + if s:system_64bit + let b[8208:8215] = 0z00FFFFFF.FFFFFF00 + else + let b[8208:8211] = 0z00FFFF00 + endif + call writefile(b, sn) + call assert_fails('recover Xfile1', 'E312:') + call assert_equal('Xfile1', @%) + call assert_match('??? block header corrupted', getline(1)) bw! call delete(sn) endfunc