shithub: trueawk

Download patch

ref: 829f5258e66609a91efebe72e18d7cd5e80987f9
parent: d11704b3c3ce8ce47d4b839529fc54ae7f18bc29
parent: dd2f1c63518aa68b606921dd3ccb01db6b9cf31a
author: ozan yigit <ozan.yigit@gmail.com>
date: Fri May 3 11:50:54 EDT 2024

merge todd's ARGV use-after-free fixes into staging

--- a/lib.c
+++ b/lib.c
@@ -335,14 +335,16 @@
 
 char *getargv(int n)	/* get ARGV[n] */
 {
+	Array *ap;
 	Cell *x;
 	char *s, temp[50];
-	extern Array *ARGVtab;
+	extern Cell *ARGVcell;
 
+	ap = (Array *)ARGVcell->sval;
 	snprintf(temp, sizeof(temp), "%d", n);
-	if (lookup(temp, ARGVtab) == NULL)
+	if (lookup(temp, ap) == NULL)
 		return NULL;
-	x = setsymtab(temp, "", 0.0, STR, ARGVtab);
+	x = setsymtab(temp, "", 0.0, STR, ap);
 	s = getsval(x);
 	DPRINTF("getargv(%d) returns |%s|\n", n, s);
 	return s;
--- a/testdir/T.argv
+++ b/testdir/T.argv
@@ -148,3 +148,17 @@
                 printf("ARGV[%d] is %s\n", i, ARGV[i])
 }' >foo2
 diff foo1 foo2 || echo 'BAD: T.argv delete ARGV[2]'
+
+# deleting ARGV used to trigger a use-after-free crash when awk
+# iterates over it to read files.
+printf '' >foo1
+$awk 'BEGIN {
+	delete ARGV
+	ARGV[0] = "awk"
+	ARGV[1] = "/dev/null"
+	ARGC = 2
+} {
+	# this should not be executed
+	print "bad"
+}' foo bar baz >foo2
+diff foo1 foo2 || echo 'BAD: T.argv delete ARGV'
--- a/tran.c
+++ b/tran.c
@@ -57,8 +57,7 @@
 Cell	*ofsloc;	/* OFS */
 Cell	*orsloc;	/* ORS */
 Cell	*rsloc;		/* RS */
-Array	*ARGVtab;	/* symbol table containing ARGV[...] */
-Array	*ENVtab;	/* symbol table containing ENVIRON[...] */
+Cell	*ARGVcell;	/* cell with symbol table containing ARGV[...] */
 Cell	*rstartloc;	/* RSTART */
 Cell	*rlengthloc;	/* RLENGTH */
 Cell	*subseploc;	/* SUBSEP */
@@ -107,6 +106,7 @@
 
 void arginit(int ac, char **av)	/* set up ARGV and ARGC */
 {
+	Array *ap;
 	Cell *cp;
 	int i;
 	char temp[50];
@@ -113,30 +113,32 @@
 
 	ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
 	cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
-	ARGVtab = makesymtab(NSYMTAB);	/* could be (int) ARGC as well */
+	ap = makesymtab(NSYMTAB);	/* could be (int) ARGC as well */
 	free(cp->sval);
-	cp->sval = (char *) ARGVtab;
+	cp->sval = (char *) ap;
 	for (i = 0; i < ac; i++) {
 		double result;
 
 		sprintf(temp, "%d", i);
 		if (is_number(*av, & result))
-			setsymtab(temp, *av, result, STR|NUM, ARGVtab);
+			setsymtab(temp, *av, result, STR|NUM, ap);
 		else
-			setsymtab(temp, *av, 0.0, STR, ARGVtab);
+			setsymtab(temp, *av, 0.0, STR, ap);
 		av++;
 	}
+	ARGVcell = cp;
 }
 
 void envinit(char **envp)	/* set up ENVIRON variable */
 {
+	Array *ap;
 	Cell *cp;
 	char *p;
 
 	cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
-	ENVtab = makesymtab(NSYMTAB);
+	ap = makesymtab(NSYMTAB);
 	free(cp->sval);
-	cp->sval = (char *) ENVtab;
+	cp->sval = (char *) ap;
 	for ( ; *envp; envp++) {
 		double result;
 
@@ -146,9 +148,9 @@
 			continue;
 		*p++ = 0;	/* split into two strings at = */
 		if (is_number(p, & result))
-			setsymtab(*envp, p, result, STR|NUM, ENVtab);
+			setsymtab(*envp, p, result, STR|NUM, ap);
 		else
-			setsymtab(*envp, p, 0.0, STR, ENVtab);
+			setsymtab(*envp, p, 0.0, STR, ap);
 		p[-1] = '=';	/* restore in case env is passed down to a shell */
 	}
 }
--