mirror of
https://github.com/neovim/neovim.git
synced 2026-07-18 07:01:19 +00:00
vim-patch:9.2.0331: spellfile: stack buffer overflows in spell file generation (#38948)
Problem: spell_read_aff() uses sprintf() into a fixed-size stack buffer
without bounds checking. store_aff_word() uses STRCAT() to
append attacker-controlled strings into newword[MAXWLEN] without
checking remaining space. Both are reachable via :mkspell with
crafted .aff/.dic files (xinyi234)
Solution: Replace sprintf() with vim_snprintf() in spell_read_aff().
Replace STRCAT() with STRNCAT() with explicit remaining-space
calculation in store_aff_word().
closes: vim/vim#19944
07faa961a0
Co-authored-by: Christian Brabandt <cb@256bit.org>
(cherry picked from commit 4f7b6083e5)
This commit is contained in:
committed by
github-actions[bot]
parent
1a5d41a48f
commit
e203257fff
@@ -2435,6 +2435,8 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char *fname)
|
|||||||
char buf[MAXLINELEN];
|
char buf[MAXLINELEN];
|
||||||
|
|
||||||
aff_entry->ae_cond = getroom_save(spin, items[4]);
|
aff_entry->ae_cond = getroom_save(spin, items[4]);
|
||||||
|
// Note: this silently truncates the buffer, but this should
|
||||||
|
// not happen in practice
|
||||||
snprintf(buf, sizeof(buf), *items[0] == 'P' ? "^%s" : "%s$", items[4]);
|
snprintf(buf, sizeof(buf), *items[0] == 'P' ? "^%s" : "%s$", items[4]);
|
||||||
aff_entry->ae_prog = vim_regcomp(buf, RE_MAGIC + RE_STRING + RE_STRICT);
|
aff_entry->ae_prog = vim_regcomp(buf, RE_MAGIC + RE_STRING + RE_STRICT);
|
||||||
if (aff_entry->ae_prog == NULL) {
|
if (aff_entry->ae_prog == NULL) {
|
||||||
@@ -3389,7 +3391,9 @@ static int store_aff_word(spellinfo_T *spin, char *word, char *afflist, afffile_
|
|||||||
MB_PTR_ADV(p);
|
MB_PTR_ADV(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
strcat(newword, p);
|
// Note: this silently truncates the buffer, but this should
|
||||||
|
// not happen in practice
|
||||||
|
xstrlcat(newword, p, MAXWLEN);
|
||||||
} else {
|
} else {
|
||||||
// suffix: chop/add at the end of the word
|
// suffix: chop/add at the end of the word
|
||||||
xstrlcpy(newword, word, MAXWLEN);
|
xstrlcpy(newword, word, MAXWLEN);
|
||||||
@@ -3403,7 +3407,9 @@ static int store_aff_word(spellinfo_T *spin, char *word, char *afflist, afffile_
|
|||||||
*p = NUL;
|
*p = NUL;
|
||||||
}
|
}
|
||||||
if (ae->ae_add != NULL) {
|
if (ae->ae_add != NULL) {
|
||||||
strcat(newword, ae->ae_add);
|
// Note: this silently truncates the buffer, but this should
|
||||||
|
// not happen in practice
|
||||||
|
xstrlcat(newword, ae->ae_add, MAXWLEN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1170,5 +1170,32 @@ func Test_mkspell_empty_dic()
|
|||||||
call delete('XtestEmpty.spl')
|
call delete('XtestEmpty.spl')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" This used to cause a buffer overflow
|
||||||
|
func Test_mkspell_no_buffer_overflow()
|
||||||
|
CheckNotMSWindows
|
||||||
|
|
||||||
|
let aff_lines = ['SET ISO8859-1', 'SFX A Y 1',
|
||||||
|
\ 'SFX A 0 s ' .. repeat(nr2char(0xff), 491)]
|
||||||
|
call writefile(aff_lines, 'Xbof.aff', 'D')
|
||||||
|
call writefile(['1', 'word/A'], 'Xbof.dic', 'D')
|
||||||
|
" Must not crash; ignore any conversion/regex errors.
|
||||||
|
try
|
||||||
|
mkspell! Xbof.spl Xbof
|
||||||
|
catch
|
||||||
|
endtry
|
||||||
|
defer delete('Xbof.spl')
|
||||||
|
|
||||||
|
let long = repeat(nr2char(0xff), 200)
|
||||||
|
let aff2_lines = ['SET ISO8859-1', 'SFX A Y 1',
|
||||||
|
\ 'SFX A 0 ' .. long .. ' .']
|
||||||
|
call writefile(aff2_lines, 'Xbof2.aff', 'D')
|
||||||
|
call writefile(['1', long .. '/A'], 'Xbof2.dic', 'D')
|
||||||
|
try
|
||||||
|
mkspell! Xbof2.spl Xbof2
|
||||||
|
catch
|
||||||
|
endtry
|
||||||
|
defer delete('Xbof2.spl')
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
|
||||||
" vim: shiftwidth=2 sts=2 expandtab
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
|||||||
Reference in New Issue
Block a user