vim/backport-CVE-2022-3491.patch
2022-12-06 14:14:14 +08:00

267 lines
6.9 KiB
Diff
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From 3558afe9e9e904cabb8475392d859f2d2fc21041 Mon Sep 17 00:00:00 2001
From: Bram Moolenaar <Bram@vim.org>
Date: Thu, 13 Oct 2022 16:12:57 +0100
Subject: [PATCH] patch 9.0.0742: reading past end of the line when compiling a
function
Problem: Reading past end of the line when compiling a function with
errors.
Solution: Do not return an invalid pointer. Fix skipping redirection.
---
src/testdir/test_vim9_func.vim | 27 ++++++++++++++
src/testdir/test_vim9_script.vim | 55 ++++++++++++++++++++++++++--
src/vim9cmds.c | 62 ++++++++++++++++++--------------
src/vim9compile.c | 23 +++++++++---
4 files changed, 134 insertions(+), 33 deletions(-)
diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim
index 38766e330156..bb5635626484 100644
--- a/src/testdir/test_vim9_func.vim
+++ b/src/testdir/test_vim9_func.vim
@@ -4217,6 +4217,33 @@ def Test_multiple_funcref()
v9.CheckScriptSuccess(lines)
enddef
+def Test_invalid_redir()
+ var lines =<< trim END
+ def Tone()
+ if 1
+ redi =>@0
+ redi END
+ endif
+ enddef
+ defcompile
+ END
+ v9.CheckScriptFailure(lines, 'E354:')
+ delfunc g:Tone
+
+ # this was reading past the end of the line
+ lines =<< trim END
+ def Ttwo()
+ if 0
+ redi =>@0
+ redi END
+ endif
+ enddef
+ defcompile
+ END
+ v9.CheckScriptFailure(lines, 'E354:')
+ delfunc g:Ttwo
+enddef
+
" The following messes up syntax highlight, keep near the end.
if has('python3')
def Test_python3_command()
diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim
index a0b8352f3f72..6c8f1f0ce0b0 100644
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -2112,15 +2112,66 @@ enddef
def Test_skipped_redir()
var lines =<< trim END
- def T()
+ def Tredir()
if 0
- redir =>l[0]
+ redir => l[0]
redir END
endif
enddef
defcompile
END
v9.CheckScriptSuccess(lines)
+ delfunc g:Tredir
+
+ lines =<< trim END
+ def Tredir()
+ if 0
+ redir => l[0]
+ endif
+ echo 'executed'
+ if 0
+ redir END
+ endif
+ enddef
+ defcompile
+ END
+ v9.CheckScriptSuccess(lines)
+ delfunc g:Tredir
+
+ lines =<< trim END
+ def Tredir()
+ var l = ['']
+ if 1
+ redir => l[0]
+ endif
+ echo 'executed'
+ if 0
+ redir END
+ else
+ redir END
+ endif
+ enddef
+ defcompile
+ END
+ v9.CheckScriptSuccess(lines)
+ delfunc g:Tredir
+
+ lines =<< trim END
+ let doit = 1
+ def Tredir()
+ var l = ['']
+ if g:doit
+ redir => l[0]
+ endif
+ echo 'executed'
+ if g:doit
+ redir END
+ endif
+ enddef
+ defcompile
+ END
+ v9.CheckScriptSuccess(lines)
+ delfunc g:Tredir
enddef
def Test_for_loop()
diff --git a/src/vim9cmds.c b/src/vim9cmds.c
index 73f95b26dfe5..e5abf895e6a7 100644
--- a/src/vim9cmds.c
+++ b/src/vim9cmds.c
@@ -2123,34 +2123,37 @@ compile_redir(char_u *line, exarg_T *eap, cctx_T *cctx)
{
if (STRNCMP(arg, "END", 3) == 0)
{
- if (lhs->lhs_append)
+ if (cctx->ctx_skip != SKIP_YES)
{
- // First load the current variable value.
- if (compile_load_lhs_with_index(lhs, lhs->lhs_whole,
+ if (lhs->lhs_append)
+ {
+ // First load the current variable value.
+ if (compile_load_lhs_with_index(lhs, lhs->lhs_whole,
cctx) == FAIL)
- return NULL;
- }
+ return NULL;
+ }
- // Gets the redirected text and put it on the stack, then store it
- // in the variable.
- generate_instr_type(cctx, ISN_REDIREND, &t_string);
+ // Gets the redirected text and put it on the stack, then store
+ // it in the variable.
+ generate_instr_type(cctx, ISN_REDIREND, &t_string);
- if (lhs->lhs_append)
- generate_CONCAT(cctx, 2);
+ if (lhs->lhs_append)
+ generate_CONCAT(cctx, 2);
- if (lhs->lhs_has_index)
- {
- // Use the info in "lhs" to store the value at the index in the
- // list or dict.
- if (compile_assign_unlet(lhs->lhs_whole, lhs, TRUE,
+ if (lhs->lhs_has_index)
+ {
+ // Use the info in "lhs" to store the value at the index in
+ // the list or dict.
+ if (compile_assign_unlet(lhs->lhs_whole, lhs, TRUE,
&t_string, cctx) == FAIL)
+ return NULL;
+ }
+ else if (generate_store_lhs(cctx, lhs, -1, FALSE) == FAIL)
return NULL;
- }
- else if (generate_store_lhs(cctx, lhs, -1, FALSE) == FAIL)
- return NULL;
- VIM_CLEAR(lhs->lhs_name);
- VIM_CLEAR(lhs->lhs_whole);
+ VIM_CLEAR(lhs->lhs_name);
+ VIM_CLEAR(lhs->lhs_whole);
+ }
return arg + 3;
}
emsg(_(e_cannot_nest_redir));
@@ -2176,13 +2179,20 @@ compile_redir(char_u *line, exarg_T *eap, cctx_T *cctx)
if (need_type(&t_string, lhs->lhs_member_type,
-1, 0, cctx, FALSE, FALSE) == FAIL)
return NULL;
- generate_instr(cctx, ISN_REDIRSTART);
- lhs->lhs_append = append;
- if (lhs->lhs_has_index)
+ if (cctx->ctx_skip == SKIP_YES)
{
- lhs->lhs_whole = vim_strnsave(arg, lhs->lhs_varlen_total);
- if (lhs->lhs_whole == NULL)
- return NULL;
+ VIM_CLEAR(lhs->lhs_name);
+ }
+ else
+ {
+ generate_instr(cctx, ISN_REDIRSTART);
+ lhs->lhs_append = append;
+ if (lhs->lhs_has_index)
+ {
+ lhs->lhs_whole = vim_strnsave(arg, lhs->lhs_varlen_total);
+ if (lhs->lhs_whole == NULL)
+ return NULL;
+ }
}
return arg + lhs->lhs_varlen_total;
diff --git a/src/vim9compile.c b/src/vim9compile.c
index b3e1b83ea4ef..73bfa6c6af1e 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -1217,6 +1217,19 @@ vim9_declare_error(char_u *name)
semsg(_(e_cannot_declare_a_scope_variable), scope, name);
}
+/*
+ * Return TRUE if "name" is a valid register to use.
+ * Return FALSE and give an error message if not.
+ */
+ static int
+valid_dest_reg(int name)
+{
+ if ((name == '@' || valid_yank_reg(name, FALSE)) && name != '.')
+ return TRUE;
+ emsg_invreg(name);
+ return FAIL;
+}
+
/*
* For one assignment figure out the type of destination. Return it in "dest".
* When not recognized "dest" is not set.
@@ -1298,12 +1311,8 @@ get_var_dest(
}
else if (*name == '@')
{
- if (name[1] != '@'
- && (!valid_yank_reg(name[1], FALSE) || name[1] == '.'))
- {
- emsg_invreg(name[1]);
+ if (!valid_dest_reg(name[1]))
return FAIL;
- }
*dest = dest_reg;
*type = name[1] == '#' ? &t_number_or_string : &t_string;
}
@@ -1379,7 +1388,11 @@ compile_lhs(
// "var_end" is the end of the variable/option/etc. name.
lhs->lhs_dest_end = skip_var_one(var_start, FALSE);
if (*var_start == '@')
+ {
+ if (!valid_dest_reg(var_start[1]))
+ return FAIL;
var_end = var_start + 2;
+ }
else
{
// skip over the leading "&", "&l:", "&g:" and "$"