From 5b1deb2b98a0513b101c600e856d64edd9d47a2e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 26 May 2023 18:52:52 +0200 Subject: [PATCH] awk: fix use-after-realloc (CVE-2021-42380), closes 15601 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Denys Vlasenko --- editors/awk.c | 26 ++++++++++++++++----- 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/editors/awk.c b/editors/awk.c index 728ee8685..2af823808 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -555,7 +555,7 @@ struct globals { const char *g_progname; int g_lineno; int nfields; - int maxfields; /* used in fsrealloc() only */ + unsigned maxfields; var *Fields; char *g_pos; char g_saved_ch; @@ -1931,9 +1931,9 @@ static void fsrealloc(int size) { int i, newsize; - if (size >= maxfields) { - /* Sanity cap, easier than catering for overflows */ - if (size > 0xffffff) + if ((unsigned)size >= maxfields) { + /* Sanity cap, easier than catering for over/underflows */ + if ((unsigned)size > 0xffffff) bb_die_memory_exhausted(); i = maxfields; @@ -2891,6 +2891,7 @@ static var *evaluate(node *op, var *res) uint32_t opinfo; int opn; node *op1; + var *old_Fields_ptr; opinfo = op->info; opn = (opinfo & OPNMASK); @@ -2899,10 +2900,16 @@ static var *evaluate(node *op, var *res) debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn); /* execute inevitable things */ + old_Fields_ptr = NULL; if (opinfo & OF_RES1) { if ((opinfo & OF_REQUIRED) && !op1) syntax_error(EMSG_TOO_FEW_ARGS); L.v = evaluate(op1, TMPVAR0); + /* Does L.v point to $n variable? */ + if ((size_t)(L.v - Fields) < maxfields) { + /* yes, remember where Fields[] is */ + old_Fields_ptr = Fields; + } if (opinfo & OF_STR1) { L.s = getvar_s(L.v); debug_printf_eval("L.s:'%s'\n", L.s); @@ -2921,8 +2928,15 @@ static var *evaluate(node *op, var *res) */ if (opinfo & OF_RES2) { R.v = evaluate(op->r.n, TMPVAR1); - //TODO: L.v may be invalid now, set L.v to NULL to catch bugs? - //L.v = NULL; + /* Seen in $5=$$5=$0: + * Evaluation of R.v ($$5=$0 expression) + * made L.v ($5) invalid. It's detected here. + */ + if (old_Fields_ptr) { + //if (old_Fields_ptr != Fields) + // debug_printf_eval("L.v moved\n"); + L.v += Fields - old_Fields_ptr; + } if (opinfo & OF_STR2) { R.s = getvar_s(R.v); debug_printf_eval("R.s:'%s'\n", R.s);