CVE-2022-2581: Out-of-bounds Read (CWE-125)
value: Out-of-bounds Read in GitHub repository vim/vim prior to 9.0.0104.
CWE description: The product reads data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 7.8
Published: 2022-08-01T15:15Z
Repository: https://github.com/vim/vim
Language: C
Files changed: src/regexp.c, src/testdir/test_regexp_utf8.vim, src/version.c
Commit date: 2022-07-29 16:22:25 +0100
Commit message: patch 9.0.0105: illegal memory access when pattern starts with illegal byte

Problem:    Illegal memory access when pattern starts with illegal byte.
Solution:   Do not match a character with an illegal byte.

Diff: diff --git a/src/regexp.c b/src/regexp.c
index 1a5cfd07cbd7..bec046437f0e 100644
--- a/src/regexp.c
+++ b/src/regexp.c
@@ -1639,11 +1639,15 @@ cstrchr(char_u *s, int c)
     {
 	for (p = s; *p != NUL; p += (*mb_ptr2len)(p))
 	{
 	    if (enc_utf8 && c > 0x80)
 	    {
-		if (utf_fold(utf_ptr2char(p)) == cc)
+		int uc = utf_ptr2char(p);
+
+		// Do not match an illegal byte.  E.g. 0xff matches 0xc3 0xbf,
+		// not 0xff.
+		if ((uc < 0x80 || uc != *p) && utf_fold(uc) == cc)
 		    return p;
 	    }
 	    else if (*p == c || *p == cc)
 		return p;
 	}
diff --git a/src/testdir/test_regexp_utf8.vim b/src/testdir/test_regexp_utf8.vim
index d88e26321d3c..e7672ddd86d4 100644
--- a/src/testdir/test_regexp_utf8.vim
+++ b/src/testdir/test_regexp_utf8.vim
@@ -1,7 +1,9 @@
 " Tests for regexp in utf8 encoding
 
+source shared.vim
+
 func s:equivalence_test()
   let str = "AÀÁÂÃÄÅĀĂĄǍǞǠǺȂȦȺḀẠẢẤẦẨẪẬẮẰẲẴẶ BƁɃḂḄḆ CÇĆĈĊČƇȻḈꞒ DĎĐƊḊḌḎḐḒ EÈÉÊËĒĔĖĘĚȄȆȨɆḔḖḘḚḜẸẺẼẾỀỂỄỆ FƑḞꞘ GĜĞĠĢƓǤǦǴḠꞠ HĤĦȞḢḤḦḨḪⱧ IÌÍÎÏĨĪĬĮİƗǏȈȊḬḮỈỊ JĴɈ KĶƘǨḰḲḴⱩꝀ LĹĻĽĿŁȽḶḸḺḼⱠ MḾṀṂ NÑŃŅŇǸṄṆṈṊꞤ OÒÓÔÕÖØŌŎŐƟƠǑǪǬǾȌȎȪȬȮȰṌṎṐṒỌỎỐỒỔỖỘỚỜỞỠỢ PƤṔṖⱣ QɊ RŔŖŘȐȒɌṘṚṜṞⱤꞦ SŚŜŞŠȘṠṢṤṦṨⱾꞨ TŢŤŦƬƮȚȾṪṬṮṰ UÙÚÛÜŨŪŬŮŰƯǕǙǛǓǗȔȖɄṲṴṶṸṺỤỦỨỪỬỮỰ  VƲṼṾ WŴẀẂẄẆẈ XẊẌ YÝŶŸƳȲɎẎỲỴỶỸ ZŹŻŽƵẐẒẔⱫ aàáâãäåāăąǎǟǡǻȃȧᶏḁẚạảấầẩẫậắằẳẵặⱥ bƀɓᵬᶀḃḅḇ cçćĉċčƈȼḉꞓꞔ dďđɗᵭᶁᶑḋḍḏḑḓ eèéêëēĕėęěȅȇȩɇᶒḕḗḙḛḝẹẻẽếềểễệ fƒᵮᶂḟꞙ gĝğġģǥǧǵɠᶃḡꞡ hĥħȟḣḥḧḩḫẖⱨꞕ iìíîïĩīĭįǐȉȋɨᶖḭḯỉị jĵǰɉ kķƙǩᶄḱḳḵⱪꝁ lĺļľŀłƚḷḹḻḽⱡ mᵯḿṁṃ nñńņňŉǹᵰᶇṅṇṉṋꞥ oòóôõöøōŏőơǒǫǭǿȍȏȫȭȯȱɵṍṏṑṓọỏốồổỗộớờởỡợ pƥᵱᵽᶈṕṗ qɋʠ rŕŗřȑȓɍɽᵲᵳᶉṛṝṟꞧ sśŝşšșȿᵴᶊṡṣṥṧṩꞩ tţťŧƫƭțʈᵵṫṭṯṱẗⱦ uùúûüũūŭůűųǚǖưǔǘǜȕȗʉᵾᶙṳṵṷṹṻụủứừửữự vʋᶌṽṿ wŵẁẃẅẇẉẘ xẋẍ yýÿŷƴȳɏẏẙỳỵỷỹ zźżžƶᵶᶎẑẓẕⱬ"
   let groups = split(str)
   for group1 in groups
       for c in split(group1, '\zs')
@@ -558,10 +560,23 @@ func Test_match_invalid_byte()
   source Xinvalid
   bwipe!
   call delete('Xinvalid')
 endfunc
 
+func Test_match_illegal_byte()
+  let lines =<< trim END
+      silent! buffer ÿ\c
+      next ÿ
+      0scriptnames
+      source
+  END
+  call writefile(lines, 'Xregexp')
+  call system(GetVimCommand() .. ' -X -Z -e -s -S Xregexp -c qa!')
+
+  call delete('Xregexp')
+endfunc
+
 func Test_match_too_complicated()
   set regexpengine=1
   exe "noswapfile vsplit \xeb\xdb\x99"
   silent! buf \&\zs*\zs*0
   bwipe!
diff --git a/src/version.c b/src/version.c
index 8c55a62e9d2c..6593e5957ec3 100644
--- a/src/version.c
+++ b/src/version.c
@@ -733,10 +733,12 @@ static char *(features[]) =
 	NULL
 };
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    105,
 /**/
     104,
 /**/
     103,
 /**/

Vulnerable code: 		if (utf_fold(utf_ptr2char(p)) == cc)
Fixed code: 		int uc = utf_ptr2char(p);

		// Do not match an illegal byte.  E.g. 0xff matches 0xc3 0xbf,
		// not 0xff.
		if ((uc < 0x80 || uc != *p) && utf_fold(uc) == cc)
source shared.vim

func Test_match_illegal_byte()
  let lines =<< trim END
      silent! buffer ÿ\c
      next ÿ
      0scriptnames
      source
  END
  call writefile(lines, 'Xregexp')
  call system(GetVimCommand() .. ' -X -Z -e -s -S Xregexp -c qa!')

  call delete('Xregexp')
endfunc

/**/
    105,