make: fix use-after-free in modifier ':@'

Without memory allocator debugging, the newly added test doesn't show
any obvious failure.

With memory allocator debugging enabled, all make versions since
2016.02.27.16.20.06 crash with a segmentation fault.
This commit is contained in:
rillig 2021-12-05 15:20:13 +00:00
parent 05762b361e
commit 412424cefd
7 changed files with 51 additions and 34 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: mi,v 1.1173 2021/11/28 16:20:13 rillig Exp $
# $NetBSD: mi,v 1.1174 2021/12/05 15:20:13 rillig Exp $
#
# Note: don't delete entries from here - mark them as "obsolete" instead.
#
@ -5985,6 +5985,8 @@
./usr/tests/usr.bin/make/unit-tests/varmod-l-name-to-value.mk tests-usr.bin-tests compattestfile,atf
./usr/tests/usr.bin/make/unit-tests/varmod-localtime.exp tests-usr.bin-tests compattestfile,atf
./usr/tests/usr.bin/make/unit-tests/varmod-localtime.mk tests-usr.bin-tests compattestfile,atf
./usr/tests/usr.bin/make/unit-tests/varmod-loop-delete.exp tests-usr.bin-tests compattestfile,atf
./usr/tests/usr.bin/make/unit-tests/varmod-loop-delete.mk tests-usr.bin-tests compattestfile,atf
./usr/tests/usr.bin/make/unit-tests/varmod-loop-varname.exp tests-usr.bin-tests compattestfile,atf
./usr/tests/usr.bin/make/unit-tests/varmod-loop-varname.mk tests-usr.bin-tests compattestfile,atf
./usr/tests/usr.bin/make/unit-tests/varmod-loop.exp tests-usr.bin-tests compattestfile,atf

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.285 2021/12/05 14:57:36 rillig Exp $
# $NetBSD: Makefile,v 1.286 2021/12/05 15:20:13 rillig Exp $
#
# Unit tests for make(1)
#
@ -351,6 +351,7 @@ TESTS+= varmod-indirect
TESTS+= varmod-l-name-to-value
TESTS+= varmod-localtime
TESTS+= varmod-loop
TESTS+= varmod-loop-delete
TESTS+= varmod-loop-varname
TESTS+= varmod-match
TESTS+= varmod-match-escape

View File

@ -0,0 +1,4 @@
make: "varmod-loop-delete.mk" line 19: Cannot delete variable "VAR" while it is used.
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1

View File

@ -0,0 +1,33 @@
# $NetBSD: varmod-loop-delete.mk,v 1.1 2021/12/05 15:20:13 rillig Exp $
#
# Tests for the variable modifier ':@', which as a side effect allows to
# delete an arbitrary variable.
# A side effect of the modifier ':@' is that the loop variable is created as
# an actual variable in the current evaluation scope (Command/Global/target),
# and at the end of the loop, this variable is deleted. Before var.c 1.963
# from 2021-12-05, a variable could be deleted while it was in use, leading to
# a use-after-free bug.
#
# See Var_Parse, comment 'the value of the variable must not change'.
# Set up the variable that deletes itself when it is evaluated.
VAR= ${:U:@VAR@@} rest of the value
# In an assignment, the scope is 'Global'. Since the variable 'VAR' is
# defined in the global scope, it deletes itself.
EVAL:= ${VAR}
.if ${EVAL} != " rest of the value"
. error
.endif
VAR= ${:U:@VAR@@} rest of the value
all: .PHONY
# In the command that is associated with a target, the scope is the
# one from the target. That scope only contains a few variables like
# '.TARGET', '.ALLSRC', '.IMPSRC'. Make does not expect that these
# variables get modified from the outside.
#
# There is no variable named 'VAR' in the local scope, so nothing
# happens.
: $@: '${VAR}'

View File

@ -13,5 +13,4 @@ mod-loop-dollar:$3$:
mod-loop-dollar:$${word}$$:
mod-loop-dollar:$$5$$:
mod-loop-dollar:$$${word}$$$:
: all: ' rest of the value'
exit status 0

View File

@ -1,4 +1,4 @@
# $NetBSD: varmod-loop.mk,v 1.17 2021/12/05 15:01:04 rillig Exp $
# $NetBSD: varmod-loop.mk,v 1.18 2021/12/05 15:20:13 rillig Exp $
#
# Tests for the :@var@...${var}...@ variable modifier.
@ -186,32 +186,4 @@ CMDLINE= global # needed for deleting the environment
. error # 'CMDLINE' is gone now from all scopes
.endif
# A side effect of the modifier ':@' is that the loop variable is created as
# an actual variable in the current evaluation scope (Command/Global/target),
# and at the end of the loop, this variable is deleted. Before var.c 1.TODO
# from 2021-12-05, a variable could be deleted while it was in use, leading to
# a use-after-free bug.
#
# See Var_Parse, comment 'the value of the variable must not change'.
# Set up the variable that deletes itself when it is evaluated.
VAR= ${:U:@VAR@@} rest of the value
# In an assignment, the scope is 'Global'. Since the variable 'VAR' is
# defined in the global scope, it deletes itself.
EVAL:= ${:U rest of the value} #${VAR} # FIXME: use-after-free
.if ${EVAL} != " rest of the value"
. error
.endif
VAR= ${:U:@VAR@@} rest of the value
all: .PHONY
# In the command that is associated with a target, the scope is the
# one from the target. That scope only contains a few variables like
# '.TARGET', '.ALLSRC', '.IMPSRC'. Make does not expect that these
# variables get modified from the outside.
#
# There is no variable named 'VAR' in the local scope, so nothing
# happens.
: $@: '${VAR}'

View File

@ -1,4 +1,4 @@
/* $NetBSD: var.c,v 1.962 2021/12/05 12:17:49 rillig Exp $ */
/* $NetBSD: var.c,v 1.963 2021/12/05 15:20:13 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@ -140,7 +140,7 @@
#include "metachar.h"
/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */
MAKE_RCSID("$NetBSD: var.c,v 1.962 2021/12/05 12:17:49 rillig Exp $");
MAKE_RCSID("$NetBSD: var.c,v 1.963 2021/12/05 15:20:13 rillig Exp $");
/*
* Variables are defined using one of the VAR=value assignments. Their
@ -496,6 +496,12 @@ Var_Delete(GNode *scope, const char *varname)
DEBUG2(VAR, "%s:delete %s\n", scope->name, varname);
v = he->value;
if (v->inUse) {
Parse_Error(PARSE_FATAL,
"Cannot delete variable \"%s\" while it is used.",
v->name.str);
return;
}
if (v->exported)
unsetenv(v->name.str);
if (strcmp(v->name.str, MAKE_EXPORTED) == 0)