vim-patch:9.0.1848: [security] buffer-overflow in vim_regsub_both() (#25001)

Problem:  buffer-overflow in vim_regsub_both()
Solution: Check remaining space

ced2c7394a

The change to do_sub() looks confusing. Maybe it's an overflow check?
Then the crash may not be applicable to Nvim because of different casts.
The test also looks confusing. It seems to source itself recursively.
Also don't call strlen() twice on evaluation result.

N/A patches for version.c:
vim-patch:9.0.1849: CI error on different signedness in ex_cmds.c
vim-patch:9.0.1853: CI error on different signedness in regexp.c

Co-authored-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
zeertzjq
2023-09-03 13:47:55 +08:00
committed by GitHub
parent 0e11bf0e1a
commit bebdf1dab3
4 changed files with 30 additions and 6 deletions

View File

@@ -3953,15 +3953,19 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const long cmdpreview_
p1 = ml_get(sub_firstlnum + (linenr_T)nmatch - 1);
nmatch_tl += nmatch - 1;
}
size_t copy_len = (size_t)(regmatch.startpos[0].col - copycol);
int copy_len = regmatch.startpos[0].col - copycol;
new_end = sub_grow_buf(&new_start, &new_start_len,
(colnr_T)strlen(p1) - regmatch.endpos[0].col
+ (colnr_T)copy_len + sublen + 1);
+ copy_len + sublen + 1);
// copy the text up to the part that matched
memmove(new_end, sub_firstline + copycol, copy_len);
memmove(new_end, sub_firstline + copycol, (size_t)copy_len);
new_end += copy_len;
if (new_start_len - copy_len < sublen) {
sublen = new_start_len - copy_len - 1;
}
// Finally, at this point we can know where the match actually will
// start in the new text
int start_col = (int)(new_end - new_start);

View File

@@ -1765,9 +1765,10 @@ static int vim_regsub_both(char *source, typval_T *expr, char *dest, int destlen
// "flags & REGSUB_COPY" == 0 to the call with
// "flags & REGSUB_COPY" != 0.
if (copy) {
if (eval_result[nested] != NULL) {
size_t reslen = eval_result[nested] != NULL ? strlen(eval_result[nested]) : 0;
if (eval_result[nested] != NULL && reslen < (size_t)destlen) {
STRCPY(dest, eval_result[nested]);
dst += strlen(eval_result[nested]);
dst += reslen;
XFREE_CLEAR(eval_result[nested]);
}
} else {

View File

@@ -0,0 +1,10 @@
fu R()
sil!norm0z=
endf
cal R()
s/\%')/\=R()
d
no0 normyynore sm:vs0@vvvvvvvvvvse()dir(<28>Xtest=csd{so88
vs
0scr
so

View File

@@ -6,7 +6,7 @@ CheckScreendump
func Test_crash1()
" The following used to crash Vim
let opts = #{wait_for_ruler: 0}
let opts = #{wait_for_ruler: 0, rows: 20}
let args = ' -u NONE -i NONE -n -e -s -S '
let buf = RunVimInTerminal(args .. ' crash/poc_huaf1', opts)
call VerifyScreenDump(buf, 'Test_crash_01', {})
@@ -22,4 +22,13 @@ func Test_crash1()
endfunc
func Test_crash2()
" The following used to crash Vim
let opts = #{wait_for_ruler: 0, rows: 20}
let args = ' -u NONE -i NONE -n -e -s -S '
let buf = RunVimInTerminal(args .. ' crash/vim_regsub_both', opts)
call VerifyScreenDump(buf, 'Test_crash_01', {})
exe buf .. "bw!"
endfunc
" vim: shiftwidth=2 sts=2 expandtab