# HG changeset patch # User Christian Brabandt # Date 1705077006 -3600 # Node ID c4ad4778946c2286de0eb354559fe094f4e551a9 # Parent 99a0d2fa5921f7381271d4ab05fa559a3230cf7a patch 9.1.0017: [security]: use-after-free in eval1_emsg() Commit: https://github.com/vim/vim/commit/28d71b566a29ceea3a2d05bcee9264ed5d630d42 Author: Yegappan Lakshmanan Date: Fri Jan 12 17:21:55 2024 +0100 patch 9.1.0017: [security]: use-after-free in eval1_emsg() Problem: use-after-free in eval1_emsg() when an empty line follows a lambda (by @yu3s) Solution: only set evalarg->eval_using_cmdline = FALSE when the *arg pointer is not null fixes: #13833 closes: #13841 Signed-off-by: Yegappan Lakshmanan Signed-off-by: Christian Brabandt diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -2699,6 +2699,9 @@ eval_next_non_blank(char_u *arg, evalarg /* * To be called after eval_next_non_blank() sets "getnext" to TRUE. * Only called for Vim9 script. + * + * If "arg" is not NULL, then the caller should assign the return value to + * "arg". */ char_u * eval_next_line(char_u *arg, evalarg_T *evalarg) @@ -2747,8 +2750,12 @@ eval_next_line(char_u *arg, evalarg_T *e } // Advanced to the next line, "arg" no longer points into the previous - // line. - evalarg->eval_using_cmdline = FALSE; + // line. The caller assigns the return value to "arg". + // If "arg" is NULL, then the return value is discarded. In that case, + // "arg" still points to the previous line. So don't reset + // "eval_using_cmdline". + if (arg != NULL) + evalarg->eval_using_cmdline = FALSE; return skipwhite(line); } diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -4906,6 +4906,31 @@ def Test_for_stmt_space_before_type() v9.CheckSourceFailure(lines, 'E1059: No white space allowed before colon: :number in range(10)', 2) enddef +" This test used to cause an use-after-free memory access +def Test_for_empty_line_after_lambda() + var lines =<< trim END + vim9script + echomsg range(0, 2)->map((_, v) => { + return 1 + }) + + assert_equal('[1, 1, 1]', v:statusmsg) + END + v9.CheckSourceSuccess(lines) + + lines =<< trim END + vim9script + echomsg range(0, 1)->map((_, v) => { + return 1 + }) range(0, 1)->map((_, v) => { + return 2 + }) # comment + + assert_equal('[1, 1] [2, 2]', v:statusmsg) + END + v9.CheckSourceSuccess(lines) +enddef + " Keep this last, it messes up highlighting. def Test_substitute_cmd() new diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -705,6 +705,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 17, +/**/ 16, /**/ 15,