summaryrefslogtreecommitdiff
path: root/usr.bin/make
diff options
context:
space:
mode:
authorrillig <rillig@NetBSD.org>2021-12-05 15:20:13 +0000
committerrillig <rillig@NetBSD.org>2021-12-05 15:20:13 +0000
commit45327533f6d548f030dcc3a1578c232f1bb3b421 (patch)
tree9d476b6eb725f36687efa28f4185f262159e7c1d /usr.bin/make
parent415154514fb2cc1a5083d76cdfa88ad4895c8cf7 (diff)
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.
Diffstat (limited to 'usr.bin/make')
-rw-r--r--usr.bin/make/unit-tests/Makefile3
-rw-r--r--usr.bin/make/unit-tests/varmod-loop-delete.exp4
-rw-r--r--usr.bin/make/unit-tests/varmod-loop-delete.mk33
-rw-r--r--usr.bin/make/unit-tests/varmod-loop.exp1
-rw-r--r--usr.bin/make/unit-tests/varmod-loop.mk30
-rw-r--r--usr.bin/make/var.c10
6 files changed, 48 insertions, 33 deletions
diff --git a/usr.bin/make/unit-tests/Makefile b/usr.bin/make/unit-tests/Makefile
index efccf85fd38..8ee7eb8b816 100644
--- a/usr.bin/make/unit-tests/Makefile
+++ b/usr.bin/make/unit-tests/Makefile
@@ -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
diff --git a/usr.bin/make/unit-tests/varmod-loop-delete.exp b/usr.bin/make/unit-tests/varmod-loop-delete.exp
new file mode 100644
index 00000000000..5df1cea5603
--- /dev/null
+++ b/usr.bin/make/unit-tests/varmod-loop-delete.exp
@@ -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
diff --git a/usr.bin/make/unit-tests/varmod-loop-delete.mk b/usr.bin/make/unit-tests/varmod-loop-delete.mk
new file mode 100644
index 00000000000..98c14992086
--- /dev/null
+++ b/usr.bin/make/unit-tests/varmod-loop-delete.mk
@@ -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}'
diff --git a/usr.bin/make/unit-tests/varmod-loop.exp b/usr.bin/make/unit-tests/varmod-loop.exp
index bf28f2ba180..d05b870d5b5 100644
--- a/usr.bin/make/unit-tests/varmod-loop.exp
+++ b/usr.bin/make/unit-tests/varmod-loop.exp
@@ -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
diff --git a/usr.bin/make/unit-tests/varmod-loop.mk b/usr.bin/make/unit-tests/varmod-loop.mk
index c9a4aa9d15d..82046ff95d7 100644
--- a/usr.bin/make/unit-tests/varmod-loop.mk
+++ b/usr.bin/make/unit-tests/varmod-loop.mk
@@ -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}'
diff --git a/usr.bin/make/var.c b/usr.bin/make/var.c
index da058439bd4..4af23e0de46 100644
--- a/usr.bin/make/var.c
+++ b/usr.bin/make/var.c
@@ -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)