From 5dcc443dba039b305a510c01883e9f34e42656ae Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Fri, 26 May 2023 19:36:58 +0200
Subject: [PATCH] awk: fix use-after-realloc (CVE-2021-42380), closes 15601

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>

CVE: CVE-2021-42380
Upstream-Status: Backport [https://git.busybox.net/busybox/commit/?id=5dcc443dba039b305a510c01883e9f34e42656ae]
Signed-off-by: Peter Marko <peter.marko@siemens.com>
---
 editors/awk.c       | 26 ++++++++++++++++-----
 testsuite/awk.tests | 55 +++++++++++++++++++++++++++++++++++++++++++++
 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);
diff --git a/testsuite/awk.tests b/testsuite/awk.tests
index bbf0fbff1..ddc51047b 100755
--- a/testsuite/awk.tests
+++ b/testsuite/awk.tests
@@ -485,4 +485,59 @@ testing 'awk assign while test' \
 	"" \
 	"foo"
 
+# User-supplied bug (SEGV) example, was causing use-after-realloc
+testing 'awk assign while assign' \
+	"awk '\$5=\$\$5=\$0'; echo \$?" \
+	"\
+─ process timing ────────────────────────────────────┬─ ─ process timing ────────────────────────────────────┬─ overall results ────┐ results ────┐
+│ run time : │        run time : 0 days, 0 hrs, 0 min, 56 sec      │  cycles done : 0     │ days, 0 hrs, 0 min, 56 sec │ cycles done : 0 │
+│ last new find │   last new find : 0 days, 0 hrs, 0 min, 1 sec       │ corpus count : 208   │ 0 days, 0 hrs, 0 min, 1 sec │ corpus count : 208 │
+│last saved crash : │last saved crash : none seen yet                     │saved crashes : 0     │ seen yet │saved crashes : 0 │
+│ last saved hang │ last saved hang : none seen yet                     │  saved hangs : 0     │ none seen yet │ saved hangs : 0 │
+├─ cycle progress ─────────────────────┬─ ├─ cycle progress ─────────────────────┬─ map coverage┴──────────────────────┤ coverage┴──────────────────────┤
+│ now processing : │  now processing : 184.1 (88.5%)      │    map density : 0.30% / 0.52%      │ (88.5%) │ map density : 0.30% / 0.52% │                                                                                                                                                                          │  now processing : 184.1 (88.5%)      │    map density : 0.30% / 0.52%      │
+│ runs timed out │  runs timed out : 0 (0.00%)          │ count coverage : 2.18 bits/tuple    │ 0 (0.00%) │ count coverage : 2.18 bits/tuple │
+├─ stage progress ─────────────────────┼─ ├─ stage progress ─────────────────────┼─ findings in depth ─────────────────┤ in depth ─────────────────┤
+│ now trying : │  now trying : havoc                  │ favored items : 43 (20.67%)         │ │ favored items : 43 (20.67%) │
+│ stage execs : │ stage execs : 11.2k/131k (8.51%)     │  new edges on : 52 (25.00%)         │ (8.51%) │ new edges on │ stage execs : 11.2k/131k (8.51%)     │  new edges on : 52 (25.00%)         │ 52 (25.00%) │
+│ total execs : │ total execs : 179k                   │ total crashes : 0 (0 saved)         │ │ total crashes : 0 (0 saved) │                                                                                                                                                                      │ total execs : 179k                   │ total crashes : 0 (0 saved)         │
+│ exec speed : │  exec speed : 3143/sec               │  total tmouts : 0 (0 saved)         │ │ total tmouts : 0 (0 saved) │                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          │  exec speed : 3143/sec               │  total tmouts : 0 (0 saved)         │
+├─ fuzzing strategy yields ├─ fuzzing strategy yields ────────────┴─────────────┬─ item geometry ───────┤ item geometry ───────┤
+│ bit flips : │   bit flips : 11/648, 4/638, 5/618                 │    levels : 4         │ 4/638, 5/618 │ levels : │   bit flips : 11/648, 4/638, 5/618                 │    levels : 4         │ │
+│ byte flips : │  byte flips : 0/81, 0/71, 0/52                     │   pending : 199       │ 0/71, 0/52 │ pending : 199 │
+│ arithmetics : 11/4494, │ arithmetics : 11/4494, 0/1153, 0/0                 │  pend fav : 35        │ 0/0 │ pend fav : 35 │
+│  known ints : 1/448, 0/1986, 0/2288                │ own finds : 207       │ known ints : │  known ints : 1/448, 0/1986, 0/2288                │ own finds : 207       │ 0/1986, 0/2288 │ own finds : 207 │
+│ dictionary : 0/0, │  dictionary : 0/0, 0/0, 0/0, 0/0                   │  imported : 0         │ 0/0, 0/0 │ imported : 0 │
+│havoc/splice : 142/146k, 23/7616 │havoc/splice : 142/146k, 23/7616                    │ stability : 100.00%   │ stability : 100.00% │
+│py/custom/rq : unused, unused, │py/custom/rq : unused, unused, unused, unused       ├───────────────────────┘ unused ├───────────────────────┘
+│ trim/eff : 57.02%/26, │    trim/eff : 57.02%/26, 0.00%                     │          [cpu000:100%] │ [cpu000:100%]
+└────────────────────────────────────────────────────┘^C    └────────────────────────────────────────────────────┘^C
+0
+" \
+	"" \
+	"\
+─ process timing ────────────────────────────────────┬─ overall results ────┐
+│        run time : 0 days, 0 hrs, 0 min, 56 sec      │  cycles done : 0     │
+│   last new find : 0 days, 0 hrs, 0 min, 1 sec       │ corpus count : 208   │
+│last saved crash : none seen yet                     │saved crashes : 0     │
+│ last saved hang : none seen yet                     │  saved hangs : 0     │
+├─ cycle progress ─────────────────────┬─ map coverage┴──────────────────────┤
+│  now processing : 184.1 (88.5%)      │    map density : 0.30% / 0.52%      │
+│  runs timed out : 0 (0.00%)          │ count coverage : 2.18 bits/tuple    │
+├─ stage progress ─────────────────────┼─ findings in depth ─────────────────┤
+│  now trying : havoc                  │ favored items : 43 (20.67%)         │
+│ stage execs : 11.2k/131k (8.51%)     │  new edges on : 52 (25.00%)         │
+│ total execs : 179k                   │ total crashes : 0 (0 saved)         │
+│  exec speed : 3143/sec               │  total tmouts : 0 (0 saved)         │
+├─ fuzzing strategy yields ────────────┴─────────────┬─ item geometry ───────┤
+│   bit flips : 11/648, 4/638, 5/618                 │    levels : 4         │
+│  byte flips : 0/81, 0/71, 0/52                     │   pending : 199       │
+│ arithmetics : 11/4494, 0/1153, 0/0                 │  pend fav : 35        │
+│  known ints : 1/448, 0/1986, 0/2288                │ own finds : 207       │
+│  dictionary : 0/0, 0/0, 0/0, 0/0                   │  imported : 0         │
+│havoc/splice : 142/146k, 23/7616                    │ stability : 100.00%   │
+│py/custom/rq : unused, unused, unused, unused       ├───────────────────────┘
+│    trim/eff : 57.02%/26, 0.00%                     │          [cpu000:100%]
+└────────────────────────────────────────────────────┘^C"
+
 exit $FAILCOUNT
-- 
2.30.2

