]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0486: out-of-bound read when recovering swap files v9.2.0486
authorChristian Brabandt <cb@256bit.org>
Fri, 15 May 2026 16:31:14 +0000 (16:31 +0000)
committerChristian Brabandt <cb@256bit.org>
Fri, 15 May 2026 16:34:53 +0000 (16:34 +0000)
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

Signed-off-by: Christian Brabandt <cb@256bit.org>
runtime/doc/recover.txt
src/memline.c
src/po/vim.pot
src/testdir/test_recover.vim
src/version.c

index c52910c1f720f53097cb753da80b5f1ed5c54a3d..d52aacd880d7736d86a78f7581aa5fb58dbf44a9 100644 (file)
@@ -195,6 +195,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.
 
 
 ENCRYPTION AND THE SWAP FILE                           *:recover-crypt*
index 2887ebbf9db351f22b09498156843dbd01e8908a..ffd3fbd72a505610abeec54c7e4c8bd08689251a 100644 (file)
@@ -1690,6 +1690,15 @@ ml_recover(int 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++, (char_u *)_("??? block header corrupted"),
+                                                                   (colnr_T)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_u *)dp + dp->db_txt_end - 1) = NUL;
index 5db285038994a986ba8eb43e7c1202f82cb2bcb3..3c0746495517c62c4369dacfe5a871f7d2cf2c9e 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Vim\n"
 "Report-Msgid-Bugs-To: vim-dev@vim.org\n"
-"POT-Creation-Date: 2026-05-07 19:25+0000\n"
+"POT-Creation-Date: 2026-05-15 16:34+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -1969,6 +1969,9 @@ msgstr ""
 msgid "??? from here until ???END lines may be messed up"
 msgstr ""
 
+msgid "??? block header corrupted"
+msgstr ""
+
 msgid "??? from here until ???END lines may have been inserted/deleted"
 msgstr ""
 
index b36d23e18d058ad07ca9cab1742b400416e43332..69caa89135f30afd6353055f332ae0c9f5655c92 100644 (file)
@@ -344,7 +344,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
index fa746a9ae6817f490a5ab1e212690ebba7816a28..046cc83425f1495e4589187d7441be83cd17de7c 100644 (file)
@@ -729,6 +729,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    486,
 /**/
     485,
 /**/