diff --git a/backport-CVE-2022-3296.patch b/backport-CVE-2022-3296.patch new file mode 100644 index 0000000000000000000000000000000000000000..6c17c41cf3c251e18e19f6b9f0707787ef3e06c1 --- /dev/null +++ b/backport-CVE-2022-3296.patch @@ -0,0 +1,552 @@ +From 96b9bf8f74af8abf1e30054f996708db7dc285be Mon Sep 17 00:00:00 2001 +From: Bram Moolenaar +Date: Sat, 24 Sep 2022 17:24:12 +0100 +Subject: [PATCH] patch 9.0.0577: buffer underflow with unexpected :finally + +Problem: Buffer underflow with unexpected :finally. +Solution: Check CSF_TRY can be found. +--- + src/ex_eval.c | 487 +++++++++++++++++++++++++------------------------- + 1 file changed, 243 insertions(+), 244 deletions(-) + +diff --git a/src/ex_eval.c b/src/ex_eval.c +index 645b27d..0c2dad8 100644 +--- a/src/ex_eval.c ++++ b/src/ex_eval.c +@@ -1646,119 +1646,117 @@ ex_finally(exarg_T *eap) + int pending = CSTP_NONE; + struct condstack *cstack = eap->cstack; + +- if (cstack->cs_trylevel <= 0 || cstack->cs_idx < 0) ++ for (idx = cstack->cs_idx; idx >= 0; --idx) ++ if (cstack->cs_flags[idx] & CSF_TRY) ++ break; ++ if (cstack->cs_trylevel <= 0 || idx < 0) ++ { + eap->errmsg = N_("E606: :finally without :try"); +- else ++ return; ++ } ++ ++ if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) + { +- if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) +- { +- eap->errmsg = get_end_emsg(cstack); +- for (idx = cstack->cs_idx - 1; idx > 0; --idx) +- if (cstack->cs_flags[idx] & CSF_TRY) +- break; +- // Make this error pending, so that the commands in the following +- // finally clause can be executed. This overrules also a pending +- // ":continue", ":break", ":return", or ":finish". +- pending = CSTP_ERROR; +- } +- else +- idx = cstack->cs_idx; ++ eap->errmsg = get_end_emsg(cstack); ++ // Make this error pending, so that the commands in the following ++ // finally clause can be executed. This overrules also a pending ++ // ":continue", ":break", ":return", or ":finish". ++ pending = CSTP_ERROR; ++ } ++ if (cstack->cs_flags[idx] & CSF_FINALLY) ++ { ++ // Give up for a multiple ":finally" and ignore it. ++ eap->errmsg = N_("E607: multiple :finally"); ++ return; ++ } ++ rewind_conditionals(cstack, idx, CSF_WHILE | CSF_FOR, ++ &cstack->cs_looplevel); + +- if (cstack->cs_flags[idx] & CSF_FINALLY) ++ /* ++ * Don't do something when the corresponding try block never got active ++ * (because of an inactive surrounding conditional or after an error or ++ * interrupt or throw) or for a ":finally" without ":try" or a multiple ++ * ":finally". After every other error (did_emsg or the conditional ++ * errors detected above) or after an interrupt (got_int) or an ++ * exception (did_throw), the finally clause must be executed. ++ */ ++ skip = !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE); ++ ++ if (!skip) ++ { ++ // When debugging or a breakpoint was encountered, display the ++ // debug prompt (if not already done). The user then knows that the ++ // finally clause is executed. ++ if (dbg_check_skipped(eap)) + { +- // Give up for a multiple ":finally" and ignore it. +- eap->errmsg = N_("E607: multiple :finally"); +- return; ++ // Handle a ">quit" debug command as if an interrupt had ++ // occurred before the ":finally". That is, discard the ++ // original exception and replace it by an interrupt ++ // exception. ++ (void)do_intthrow(cstack); + } +- rewind_conditionals(cstack, idx, CSF_WHILE | CSF_FOR, +- &cstack->cs_looplevel); + + /* +- * Don't do something when the corresponding try block never got active +- * (because of an inactive surrounding conditional or after an error or +- * interrupt or throw) or for a ":finally" without ":try" or a multiple +- * ":finally". After every other error (did_emsg or the conditional +- * errors detected above) or after an interrupt (got_int) or an +- * exception (did_throw), the finally clause must be executed. ++ * If there is a preceding catch clause and it caught the exception, ++ * finish the exception now. This happens also after errors except ++ * when this is a multiple ":finally" or one not within a ":try". ++ * After an error or interrupt, this also discards a pending ++ * ":continue", ":break", ":finish", or ":return" from the preceding ++ * try block or catch clause. + */ +- skip = !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE); ++ cleanup_conditionals(cstack, CSF_TRY, FALSE); + +- if (!skip) ++ /* ++ * Make did_emsg, got_int, did_throw pending. If set, they overrule ++ * a pending ":continue", ":break", ":return", or ":finish". Then ++ * we have particularly to discard a pending return value (as done ++ * by the call to cleanup_conditionals() above when did_emsg or ++ * got_int is set). The pending values are restored by the ++ * ":endtry", except if there is a new error, interrupt, exception, ++ * ":continue", ":break", ":return", or ":finish" in the following ++ * finally clause. A missing ":endwhile", ":endfor" or ":endif" ++ * detected here is treated as if did_emsg and did_throw had ++ * already been set, respectively in case that the error is not ++ * converted to an exception, did_throw had already been unset. ++ * We must not set did_emsg here since that would suppress the ++ * error message. ++ */ ++ if (pending == CSTP_ERROR || did_emsg || got_int || did_throw) + { +- // When debugging or a breakpoint was encountered, display the +- // debug prompt (if not already done). The user then knows that the +- // finally clause is executed. +- if (dbg_check_skipped(eap)) +- { +- // Handle a ">quit" debug command as if an interrupt had +- // occurred before the ":finally". That is, discard the +- // original exception and replace it by an interrupt +- // exception. +- (void)do_intthrow(cstack); +- } +- +- /* +- * If there is a preceding catch clause and it caught the exception, +- * finish the exception now. This happens also after errors except +- * when this is a multiple ":finally" or one not within a ":try". +- * After an error or interrupt, this also discards a pending +- * ":continue", ":break", ":finish", or ":return" from the preceding +- * try block or catch clause. +- */ +- cleanup_conditionals(cstack, CSF_TRY, FALSE); +- +- /* +- * Make did_emsg, got_int, did_throw pending. If set, they overrule +- * a pending ":continue", ":break", ":return", or ":finish". Then +- * we have particularly to discard a pending return value (as done +- * by the call to cleanup_conditionals() above when did_emsg or +- * got_int is set). The pending values are restored by the +- * ":endtry", except if there is a new error, interrupt, exception, +- * ":continue", ":break", ":return", or ":finish" in the following +- * finally clause. A missing ":endwhile", ":endfor" or ":endif" +- * detected here is treated as if did_emsg and did_throw had +- * already been set, respectively in case that the error is not +- * converted to an exception, did_throw had already been unset. +- * We must not set did_emsg here since that would suppress the +- * error message. +- */ +- if (pending == CSTP_ERROR || did_emsg || got_int || did_throw) ++ if (cstack->cs_pending[cstack->cs_idx] == CSTP_RETURN) + { +- if (cstack->cs_pending[cstack->cs_idx] == CSTP_RETURN) +- { +- report_discard_pending(CSTP_RETURN, +- cstack->cs_rettv[cstack->cs_idx]); +- discard_pending_return(cstack->cs_rettv[cstack->cs_idx]); +- } +- if (pending == CSTP_ERROR && !did_emsg) +- pending |= (THROW_ON_ERROR) ? CSTP_THROW : 0; +- else +- pending |= did_throw ? CSTP_THROW : 0; +- pending |= did_emsg ? CSTP_ERROR : 0; +- pending |= got_int ? CSTP_INTERRUPT : 0; +- cstack->cs_pending[cstack->cs_idx] = pending; +- +- // It's mandatory that the current exception is stored in the +- // cstack so that it can be rethrown at the ":endtry" or be +- // discarded if the finally clause is left by a ":continue", +- // ":break", ":return", ":finish", error, interrupt, or another +- // exception. When emsg() is called for a missing ":endif" or +- // a missing ":endwhile"/":endfor" detected here, the +- // exception will be discarded. +- if (did_throw && cstack->cs_exception[cstack->cs_idx] +- != current_exception) +- internal_error("ex_finally()"); ++ report_discard_pending(CSTP_RETURN, ++ cstack->cs_rettv[cstack->cs_idx]); ++ discard_pending_return(cstack->cs_rettv[cstack->cs_idx]); + } +- +- /* +- * Set CSL_HAD_FINA, so do_cmdline() will reset did_emsg, +- * got_int, and did_throw and make the finally clause active. +- * This will happen after emsg() has been called for a missing +- * ":endif" or a missing ":endwhile"/":endfor" detected here, so +- * that the following finally clause will be executed even then. +- */ +- cstack->cs_lflags |= CSL_HAD_FINA; ++ if (pending == CSTP_ERROR && !did_emsg) ++ pending |= (THROW_ON_ERROR) ? CSTP_THROW : 0; ++ else ++ pending |= did_throw ? CSTP_THROW : 0; ++ pending |= did_emsg ? CSTP_ERROR : 0; ++ pending |= got_int ? CSTP_INTERRUPT : 0; ++ cstack->cs_pending[cstack->cs_idx] = pending; ++ ++ // It's mandatory that the current exception is stored in the ++ // cstack so that it can be rethrown at the ":endtry" or be ++ // discarded if the finally clause is left by a ":continue", ++ // ":break", ":return", ":finish", error, interrupt, or another ++ // exception. When emsg() is called for a missing ":endif" or ++ // a missing ":endwhile"/":endfor" detected here, the ++ // exception will be discarded. ++ if (did_throw && cstack->cs_exception[cstack->cs_idx] ++ != current_exception) ++ internal_error("ex_finally()"); + } ++ ++ /* ++ * Set CSL_HAD_FINA, so do_cmdline() will reset did_emsg, ++ * got_int, and did_throw and make the finally clause active. ++ * This will happen after emsg() has been called for a missing ++ * ":endif" or a missing ":endwhile"/":endfor" detected here, so ++ * that the following finally clause will be executed even then. ++ */ ++ cstack->cs_lflags |= CSL_HAD_FINA; + } + } + +@@ -1775,170 +1773,171 @@ ex_endtry(exarg_T *eap) + void *rettv = NULL; + struct condstack *cstack = eap->cstack; + +- if (cstack->cs_trylevel <= 0 || cstack->cs_idx < 0) +- eap->errmsg = N_("E602: :endtry without :try"); +- else ++ for (idx = cstack->cs_idx; idx >= 0; --idx) ++ if (cstack->cs_flags[idx] & CSF_TRY) ++ break; ++ if (cstack->cs_trylevel <= 0 || idx < 0) + { +- /* +- * Don't do something after an error, interrupt or throw in the try +- * block, catch clause, or finally clause preceding this ":endtry" or +- * when an error or interrupt occurred after a ":continue", ":break", +- * ":return", or ":finish" in a try block or catch clause preceding this +- * ":endtry" or when the try block never got active (because of an +- * inactive surrounding conditional or after an error or interrupt or +- * throw) or when there is a surrounding conditional and it has been +- * made inactive by a ":continue", ":break", ":return", or ":finish" in +- * the finally clause. The latter case need not be tested since then +- * anything pending has already been discarded. */ +- skip = did_emsg || got_int || did_throw || ++ eap->errmsg = N_("E602: :endtry without :try"); ++ return; ++ } ++ ++ /* ++ * Don't do something after an error, interrupt or throw in the try ++ * block, catch clause, or finally clause preceding this ":endtry" or ++ * when an error or interrupt occurred after a ":continue", ":break", ++ * ":return", or ":finish" in a try block or catch clause preceding this ++ * ":endtry" or when the try block never got active (because of an ++ * inactive surrounding conditional or after an error or interrupt or ++ * throw) or when there is a surrounding conditional and it has been ++ * made inactive by a ":continue", ":break", ":return", or ":finish" in ++ * the finally clause. The latter case need not be tested since then ++ * anything pending has already been discarded. */ ++ skip = did_emsg || got_int || did_throw || + !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE); + +- if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) +- { +- eap->errmsg = get_end_emsg(cstack); +- // Find the matching ":try" and report what's missing. +- idx = cstack->cs_idx; +- do +- --idx; +- while (idx > 0 && !(cstack->cs_flags[idx] & CSF_TRY)); +- rewind_conditionals(cstack, idx, CSF_WHILE | CSF_FOR, +- &cstack->cs_looplevel); +- skip = TRUE; ++ if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) ++ { ++ eap->errmsg = get_end_emsg(cstack); + +- /* +- * If an exception is being thrown, discard it to prevent it from +- * being rethrown at the end of this function. It would be +- * discarded by the error message, anyway. Resets did_throw. +- * This does not affect the script termination due to the error +- * since "trylevel" is decremented after emsg() has been called. +- */ +- if (did_throw) +- discard_current_exception(); +- } +- else +- { +- idx = cstack->cs_idx; ++ // Find the matching ":try" and report what's missing. ++ rewind_conditionals(cstack, idx, CSF_WHILE | CSF_FOR, ++ &cstack->cs_looplevel); ++ skip = TRUE; + +- /* +- * If we stopped with the exception currently being thrown at this +- * try conditional since we didn't know that it doesn't have +- * a finally clause, we need to rethrow it after closing the try +- * conditional. +- */ +- if (did_throw && (cstack->cs_flags[idx] & CSF_TRUE) +- && !(cstack->cs_flags[idx] & CSF_FINALLY)) +- rethrow = TRUE; +- } ++ /* ++ * If an exception is being thrown, discard it to prevent it from ++ * being rethrown at the end of this function. It would be ++ * discarded by the error message, anyway. Resets did_throw. ++ * This does not affect the script termination due to the error ++ * since "trylevel" is decremented after emsg() has been called. ++ */ ++ if (did_throw) ++ discard_current_exception(); + +- // If there was no finally clause, show the user when debugging or +- // a breakpoint was encountered that the end of the try conditional has +- // been reached: display the debug prompt (if not already done). Do +- // this on normal control flow or when an exception was thrown, but not +- // on an interrupt or error not converted to an exception or when +- // a ":break", ":continue", ":return", or ":finish" is pending. These +- // actions are carried out immediately. +- if ((rethrow || (!skip +- && !(cstack->cs_flags[idx] & CSF_FINALLY) +- && !cstack->cs_pending[idx])) +- && dbg_check_skipped(eap)) +- { +- // Handle a ">quit" debug command as if an interrupt had occurred +- // before the ":endtry". That is, throw an interrupt exception and +- // set "skip" and "rethrow". +- if (got_int) +- { +- skip = TRUE; +- (void)do_intthrow(cstack); +- // The do_intthrow() call may have reset did_throw or +- // cstack->cs_pending[idx]. +- rethrow = FALSE; +- if (did_throw && !(cstack->cs_flags[idx] & CSF_FINALLY)) +- rethrow = TRUE; +- } +- } ++ } ++ else ++ { ++ idx = cstack->cs_idx; + + /* +- * If a ":return" is pending, we need to resume it after closing the +- * try conditional; remember the return value. If there was a finally +- * clause making an exception pending, we need to rethrow it. Make it +- * the exception currently being thrown. ++ * If we stopped with the exception currently being thrown at this ++ * try conditional since we didn't know that it doesn't have ++ * a finally clause, we need to rethrow it after closing the try ++ * conditional. + */ +- if (!skip) ++ if (did_throw && (cstack->cs_flags[idx] & CSF_TRUE) ++ && !(cstack->cs_flags[idx] & CSF_FINALLY)) ++ rethrow = TRUE; ++ } ++ ++ // If there was no finally clause, show the user when debugging or ++ // a breakpoint was encountered that the end of the try conditional has ++ // been reached: display the debug prompt (if not already done). Do ++ // this on normal control flow or when an exception was thrown, but not ++ // on an interrupt or error not converted to an exception or when ++ // a ":break", ":continue", ":return", or ":finish" is pending. These ++ // actions are carried out immediately. ++ if ((rethrow || (!skip && !(cstack->cs_flags[idx] & CSF_FINALLY) ++ && !cstack->cs_pending[idx])) ++ && dbg_check_skipped(eap)) ++ { ++ // Handle a ">quit" debug command as if an interrupt had occurred ++ // before the ":endtry". That is, throw an interrupt exception and ++ // set "skip" and "rethrow". ++ if (got_int) + { +- pending = cstack->cs_pending[idx]; +- cstack->cs_pending[idx] = CSTP_NONE; +- if (pending == CSTP_RETURN) +- rettv = cstack->cs_rettv[idx]; +- else if (pending & CSTP_THROW) +- current_exception = cstack->cs_exception[idx]; ++ skip = TRUE; ++ (void)do_intthrow(cstack); ++ // The do_intthrow() call may have reset did_throw or ++ // cstack->cs_pending[idx]. ++ rethrow = FALSE; ++ if (did_throw && !(cstack->cs_flags[idx] & CSF_FINALLY)) ++ rethrow = TRUE; + } ++ } + +- /* +- * Discard anything pending on an error, interrupt, or throw in the +- * finally clause. If there was no ":finally", discard a pending +- * ":continue", ":break", ":return", or ":finish" if an error or +- * interrupt occurred afterwards, but before the ":endtry" was reached. +- * If an exception was caught by the last of the catch clauses and there +- * was no finally clause, finish the exception now. This happens also +- * after errors except when this ":endtry" is not within a ":try". +- * Restore "emsg_silent" if it has been reset by this try conditional. +- */ +- (void)cleanup_conditionals(cstack, CSF_TRY | CSF_SILENT, TRUE); ++ /* ++ * If a ":return" is pending, we need to resume it after closing the ++ * try conditional; remember the return value. If there was a finally ++ * clause making an exception pending, we need to rethrow it. Make it ++ * the exception currently being thrown. ++ */ ++ if (!skip) ++ { ++ pending = cstack->cs_pending[idx]; ++ cstack->cs_pending[idx] = CSTP_NONE; ++ if (pending == CSTP_RETURN) ++ rettv = cstack->cs_rettv[idx]; ++ else if (pending & CSTP_THROW) ++ current_exception = cstack->cs_exception[idx]; ++ } + +- --cstack->cs_idx; +- --cstack->cs_trylevel; ++ /* ++ * Discard anything pending on an error, interrupt, or throw in the ++ * finally clause. If there was no ":finally", discard a pending ++ * ":continue", ":break", ":return", or ":finish" if an error or ++ * interrupt occurred afterwards, but before the ":endtry" was reached. ++ * If an exception was caught by the last of the catch clauses and there ++ * was no finally clause, finish the exception now. This happens also ++ * after errors except when this ":endtry" is not within a ":try". ++ * Restore "emsg_silent" if it has been reset by this try conditional. ++ */ ++ (void)cleanup_conditionals(cstack, CSF_TRY | CSF_SILENT, TRUE); + +- if (!skip) +- { +- report_resume_pending(pending, ++ --cstack->cs_idx; ++ --cstack->cs_trylevel; ++ ++ if (!skip) ++ { ++ report_resume_pending(pending, + (pending == CSTP_RETURN) ? rettv : + (pending & CSTP_THROW) ? (void *)current_exception : NULL); +- switch (pending) +- { +- case CSTP_NONE: +- break; ++ switch (pending) ++ { ++ case CSTP_NONE: ++ break; + +- // Reactivate a pending ":continue", ":break", ":return", +- // ":finish" from the try block or a catch clause of this try +- // conditional. This is skipped, if there was an error in an +- // (unskipped) conditional command or an interrupt afterwards +- // or if the finally clause is present and executed a new error, +- // interrupt, throw, ":continue", ":break", ":return", or +- // ":finish". +- case CSTP_CONTINUE: +- ex_continue(eap); +- break; +- case CSTP_BREAK: +- ex_break(eap); +- break; +- case CSTP_RETURN: +- do_return(eap, FALSE, FALSE, rettv); +- break; +- case CSTP_FINISH: +- do_finish(eap, FALSE); +- break; ++ // Reactivate a pending ":continue", ":break", ":return", ++ // ":finish" from the try block or a catch clause of this try ++ // conditional. This is skipped, if there was an error in an ++ // (unskipped) conditional command or an interrupt afterwards ++ // or if the finally clause is present and executed a new error, ++ // interrupt, throw, ":continue", ":break", ":return", or ++ // ":finish". ++ case CSTP_CONTINUE: ++ ex_continue(eap); ++ break; ++ case CSTP_BREAK: ++ ex_break(eap); ++ break; ++ case CSTP_RETURN: ++ do_return(eap, FALSE, FALSE, rettv); ++ break; ++ case CSTP_FINISH: ++ do_finish(eap, FALSE); ++ break; + +- // When the finally clause was entered due to an error, +- // interrupt or throw (as opposed to a ":continue", ":break", +- // ":return", or ":finish"), restore the pending values of +- // did_emsg, got_int, and did_throw. This is skipped, if there +- // was a new error, interrupt, throw, ":continue", ":break", +- // ":return", or ":finish". in the finally clause. +- default: +- if (pending & CSTP_ERROR) +- did_emsg = TRUE; +- if (pending & CSTP_INTERRUPT) +- got_int = TRUE; +- if (pending & CSTP_THROW) +- rethrow = TRUE; +- break; +- } ++ // When the finally clause was entered due to an error, ++ // interrupt or throw (as opposed to a ":continue", ":break", ++ // ":return", or ":finish"), restore the pending values of ++ // did_emsg, got_int, and did_throw. This is skipped, if there ++ // was a new error, interrupt, throw, ":continue", ":break", ++ // ":return", or ":finish". in the finally clause. ++ default: ++ if (pending & CSTP_ERROR) ++ did_emsg = TRUE; ++ if (pending & CSTP_INTERRUPT) ++ got_int = TRUE; ++ if (pending & CSTP_THROW) ++ rethrow = TRUE; ++ break; + } +- +- if (rethrow) +- // Rethrow the current exception (within this cstack). +- do_throw(cstack); + } ++ ++ if (rethrow) ++ // Rethrow the current exception (within this cstack). ++ do_throw(cstack); + } + + /* +-- +2.33.0 + diff --git a/vim.spec b/vim.spec index bfa24b58e0906da3884bd1d47ccc923f4c1645cc..6f2400b1c7ced7cd0ef60892f3ff2d79e7f1f337 100644 --- a/vim.spec +++ b/vim.spec @@ -12,7 +12,7 @@ Name: vim Epoch: 2 Version: 8.2 -Release: 67 +Release: 68 Summary: Vim is a highly configurable text editor for efficiently creating and changing any kind of text. License: Vim and MIT URL: http://www.vim.org @@ -188,6 +188,7 @@ Patch6146: backport-CVE-2022-3134.patch Patch6147: backport-CVE-2022-3234.patch Patch6148: backport-CVE-2022-3235.patch Patch6149: backport-CVE-2022-3256.patch +Patch6150: backport-CVE-2022-3296.patch BuildRequires: autoconf python3-devel ncurses-devel gettext perl-devel perl-generators gcc BuildRequires: perl(ExtUtils::Embed) perl(ExtUtils::ParseXS) libacl-devel gpm-devel file @@ -481,6 +482,7 @@ popd %{_bindir}/vim -c ":helptags %{_datadir}/%{name}/vimfiles/doc" -c :q &> /dev/null || : %check +export TERM=linux LC_ALL=en_US.UTF-8 make -j1 test %files common @@ -576,6 +578,12 @@ LC_ALL=en_US.UTF-8 make -j1 test %{_mandir}/man1/evim.* %changelog +* Sun Oct 09 2022 renhongxun - 2:8.2-68 +- Type:CVE +- ID:CVE-2022-3296 +- SUG:NA +- DESC:fix CVE-2022-3296 + * Fri Sep 23 2022 dongyuzhen - 2:8.2-67 - Type:CVE - ID:CVE-2022-3256