diff options
author | ozan yigit <ozan.yigit@gmail.com> | 2024-05-03 15:50:54 -0400 |
---|---|---|
committer | ozan yigit <ozan.yigit@gmail.com> | 2024-05-03 15:50:54 -0400 |
commit | 829f5258e66609a91efebe72e18d7cd5e80987f9 (patch) | |
tree | 5e30da22841dceb001c73b7821ebba1279e6a5c1 | |
parent | d11704b3c3ce8ce47d4b839529fc54ae7f18bc29 (diff) | |
parent | dd2f1c63518aa68b606921dd3ccb01db6b9cf31a (diff) | |
download | one-true-awk-829f5258e66609a91efebe72e18d7cd5e80987f9.tar.gz |
merge todd's ARGV use-after-free fixes into staging
-rw-r--r-- | lib.c | 8 | ||||
-rwxr-xr-x | testdir/T.argv | 14 | ||||
-rw-r--r-- | tran.c | 22 |
3 files changed, 31 insertions, 13 deletions
@@ -335,14 +335,16 @@ int readcsvrec(char **pbuf, int *pbufsize, FILE *inf, bool newflag) /* csv can h 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; diff --git a/testdir/T.argv b/testdir/T.argv index 55e2754..48ef826 100755 --- a/testdir/T.argv +++ b/testdir/T.argv @@ -148,3 +148,17 @@ END { 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' @@ -57,8 +57,7 @@ Cell *fnrloc; /* FNR */ 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,36 +106,39 @@ void syminit(void) /* initialize symbol table with builtin vars */ void arginit(int ac, char **av) /* set up ARGV and ARGC */ { + Array *ap; Cell *cp; int i; char temp[50]; 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 @@ void envinit(char **envp) /* set up ENVIRON variable */ 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 */ } } |