CVE-2022-1621: Heap-based Buffer Overflow (CWE-122)
value: Heap buffer overflow in vim_strncpy find_word in GitHub repository vim/vim prior to 8.2.4919. This vulnerability is capable of crashing software, Bypass Protection Mechanism, Modify Memory, and possible remote execution
CWE description: A heap overflow condition is a buffer overflow, where the buffer that can be overwritten is allocated in the heap portion of memory, generally meaning that the buffer was allocated using a routine such as malloc().
CVSS v3 base score: 7.8
Published: 2022-05-10T14:15Z
Repository: https://github.com/vim/vim
Language: C
Files changed: src/errors.h, src/mbyte.c, src/spellfile.c, src/testdir/test_spell_utf8.vim, src/version.c
Commit date: 2022-05-08 22:32:58 +0100
Commit message: patch 8.2.4919: can add invalid bytes with :spellgood

Problem:    Can add invalid bytes with :spellgood.
Solution:   Check for a valid word string.

Diff: diff --git a/src/errors.h b/src/errors.h
index 1e9be6c3e350..087f49753df3 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -3271,5 +3271,9 @@ EXTERN char e_channel_job_feature_not_available[]
 EXTERN char e_stray_closing_curly_str[]
 	INIT(= N_("E1278: Stray '}' without a matching '{': %s"));
 EXTERN char e_missing_close_curly_str[]
 	INIT(= N_("E1279: Missing '}': %s"));
 #endif
+#ifdef FEAT_SPELL
+EXTERN char e_illegal_character_in_word[]
+	INIT(= N_("E1280: Illegal character in word"));
+#endif
diff --git a/src/mbyte.c b/src/mbyte.c
index 2b7f9991ae14..a01a05140207 100644
--- a/src/mbyte.c
+++ b/src/mbyte.c
@@ -4224,11 +4224,11 @@ utf_find_illegal(void)
 theend:
     vim_free(tofree);
     convert_setup(&vimconv, NULL, NULL);
 }
 
-#if defined(FEAT_GUI_GTK) || defined(PROTO)
+#if defined(FEAT_GUI_GTK) || defined(FEAT_SPELL) || defined(PROTO)
 /*
  * Return TRUE if string "s" is a valid utf-8 string.
  * When "end" is NULL stop at the first NUL.
  * When "end" is positive stop there.
  */
diff --git a/src/spellfile.c b/src/spellfile.c
index 22cf82da0872..f0d6d96a47f0 100644
--- a/src/spellfile.c
+++ b/src/spellfile.c
@@ -4388,10 +4388,14 @@ store_word(
     int		ct = captype(word, word + len);
     char_u	foldword[MAXWLEN];
     int		res = OK;
     char_u	*p;
 
+    // Avoid adding illegal bytes to the word tree.
+    if (enc_utf8 && !utf_valid_string(word, NULL))
+	return FAIL;
+
     (void)spell_casefold(curwin, word, len, foldword, MAXWLEN);
     for (p = pfxlist; res == OK; ++p)
     {
 	if (!need_affix || (p != NULL && *p != NUL))
 	    res = tree_add_word(spin, foldword, spin->si_foldroot, ct | flags,
@@ -6188,10 +6192,16 @@ spell_add_word(
     char_u	line[MAXWLEN * 2];
     long	fpos, fpos_next = 0;
     int		i;
     char_u	*spf;
 
+    if (enc_utf8 && !utf_valid_string(word, NULL))
+    {
+	emsg(_(e_illegal_character_in_word));
+	return;
+    }
+
     if (idx == 0)	    // use internal wordlist
     {
 	if (int_wordlist == NULL)
 	{
 	    int_wordlist = vim_tempname('s', FALSE);
diff --git a/src/testdir/test_spell_utf8.vim b/src/testdir/test_spell_utf8.vim
index 79dc3e4a4a62..17fa23555818 100644
--- a/src/testdir/test_spell_utf8.vim
+++ b/src/testdir/test_spell_utf8.vim
@@ -778,7 +778,12 @@ func Test_no_crash_with_weird_text()
   exe "%norm \<C-v>ez=>\<C-v>wzG"
 
   bwipe!
 endfunc
 
+" Invalid bytes may cause trouble when creating the word list.
+func Test_check_for_valid_word()
+  call assert_fails("spellgood! 0\xac", 'E1280:')
+endfunc
+
 
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index f949dd6d7ed0..c4f5655bf6c2 100644
--- a/src/version.c
+++ b/src/version.c
@@ -744,10 +744,12 @@ static char *(features[]) =
 	NULL
 };
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4919,
 /**/
     4918,
 /**/
     4917,
 /**/

Vulnerable code: #if defined(FEAT_GUI_GTK) || defined(PROTO)
Fixed code: #ifdef FEAT_SPELL
EXTERN char e_illegal_character_in_word[]
	INIT(= N_("E1280: Illegal character in word"));
#endif
#if defined(FEAT_GUI_GTK) || defined(FEAT_SPELL) || defined(PROTO)
    // Avoid adding illegal bytes to the word tree.
    if (enc_utf8 && !utf_valid_string(word, NULL))
	return FAIL;

    if (enc_utf8 && !utf_valid_string(word, NULL))
    {
	emsg(_(e_illegal_character_in_word));
	return;
    }

" Invalid bytes may cause trouble when creating the word list.
func Test_check_for_valid_word()
  call assert_fails("spellgood! 0\xac", 'E1280:')
endfunc

/**/
    4919,