awk: fix use-after-realloc (CVE-2021-42380), closes 15601

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
master
Denys Vlasenko 2023-05-26 19:36:58 +02:00
parent d7814f5727
commit 5dcc443dba
2 changed files with 75 additions and 6 deletions

View File

@ -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);

View File

@ -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