Module Name:    src
Committed By:   rillig
Date:           Fri Jun 25 16:10:07 UTC 2021

Modified Files:
        src/usr.bin/make: for.c
        src/usr.bin/make/unit-tests: directive-for-escape.exp
            directive-for-escape.mk

Log Message:
make: prevent newline injection in .for loops

When a value of a .for loop contained a literal newline, such as from
the expression ${.newline}, that newline was passed verbatim to the
"expanded current body" of the .for loop.  There it was interpreted as a
literal newline, which ended the current line and started a new one.
This resulted in several syntax errors.

In cases like these, print a more precise error message.


To generate a diff of this commit:
cvs rdiff -u -r1.143 -r1.144 src/usr.bin/make/for.c
cvs rdiff -u -r1.10 -r1.11 \
    src/usr.bin/make/unit-tests/directive-for-escape.exp
cvs rdiff -u -r1.9 -r1.10 src/usr.bin/make/unit-tests/directive-for-escape.mk

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/make/for.c
diff -u src/usr.bin/make/for.c:1.143 src/usr.bin/make/for.c:1.144
--- src/usr.bin/make/for.c:1.143	Thu Jun 24 23:19:52 2021
+++ src/usr.bin/make/for.c	Fri Jun 25 16:10:07 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: for.c,v 1.143 2021/06/24 23:19:52 rillig Exp $	*/
+/*	$NetBSD: for.c,v 1.144 2021/06/25 16:10:07 rillig Exp $	*/
 
 /*
  * Copyright (c) 1992, The Regents of the University of California.
@@ -58,7 +58,7 @@
 #include "make.h"
 
 /*	"@(#)for.c	8.1 (Berkeley) 6/6/93"	*/
-MAKE_RCSID("$NetBSD: for.c,v 1.143 2021/06/24 23:19:52 rillig Exp $");
+MAKE_RCSID("$NetBSD: for.c,v 1.144 2021/06/25 16:10:07 rillig Exp $");
 
 
 /* One of the variables to the left of the "in" in a .for loop. */
@@ -325,7 +325,8 @@ NeedsEscapes(const char *value, char end
 	const char *p;
 
 	for (p = value; *p != '\0'; p++) {
-		if (*p == ':' || *p == '$' || *p == '\\' || *p == endc)
+		if (*p == ':' || *p == '$' || *p == '\\' || *p == endc ||
+		    *p == '\n')
 			return true;
 	}
 	return false;
@@ -360,6 +361,10 @@ Buf_AddEscaped(Buffer *cmds, const char 
 			Buf_AddByte(cmds, '\\');
 		} else if (ch == ':' || ch == '\\' || ch == endc)
 			Buf_AddByte(cmds, '\\');
+		else if (ch == '\n') {
+			Parse_Error(PARSE_FATAL, "newline in .for value");
+			ch = ' ';	/* prevent newline injection */
+		}
 		Buf_AddByte(cmds, ch);
 	}
 }

Index: src/usr.bin/make/unit-tests/directive-for-escape.exp
diff -u src/usr.bin/make/unit-tests/directive-for-escape.exp:1.10 src/usr.bin/make/unit-tests/directive-for-escape.exp:1.11
--- src/usr.bin/make/unit-tests/directive-for-escape.exp:1.10	Fri Jun 25 15:56:02 2021
+++ src/usr.bin/make/unit-tests/directive-for-escape.exp	Fri Jun 25 16:10:07 2021
@@ -80,17 +80,13 @@ make: "directive-for-escape.mk" line 118
 make: "directive-for-escape.mk" line 119: eight dollardollardollardollar and no cents.
 make: "directive-for-escape.mk" line 128: eight  and no cents.
 For: end for 1
+make: "directive-for-escape.mk" line 135: newline in .for value
+make: "directive-for-escape.mk" line 135: newline in .for value
 For: loop body:
-.  info short: ${:U"
-"}
-.  info long: ${:U"
-"}
-make: Unclosed variable expression, expecting '}' for modifier "U"" of variable "" with value """
-make: "directive-for-escape.mk" line 134: short: "
-make: "directive-for-escape.mk" line 135: Invalid line type
-make: Unclosed variable expression, expecting '}' for modifier "U"" of variable "" with value """
-make: "directive-for-escape.mk" line 136: long: "
-make: "directive-for-escape.mk" line 137: Invalid line type
+.  info short: ${:U" "}
+.  info long: ${:U" "}
+make: "directive-for-escape.mk" line 136: short: " "
+make: "directive-for-escape.mk" line 137: long: " "
 make: Fatal errors encountered -- cannot continue
 make: stopped in unit-tests
 exit status 1

Index: src/usr.bin/make/unit-tests/directive-for-escape.mk
diff -u src/usr.bin/make/unit-tests/directive-for-escape.mk:1.9 src/usr.bin/make/unit-tests/directive-for-escape.mk:1.10
--- src/usr.bin/make/unit-tests/directive-for-escape.mk:1.9	Fri Jun 25 15:56:02 2021
+++ src/usr.bin/make/unit-tests/directive-for-escape.mk	Fri Jun 25 16:10:07 2021
@@ -1,4 +1,4 @@
-# $NetBSD: directive-for-escape.mk,v 1.9 2021/06/25 15:56:02 rillig Exp $
+# $NetBSD: directive-for-escape.mk,v 1.10 2021/06/25 16:10:07 rillig Exp $
 #
 # Test escaping of special characters in the iteration values of a .for loop.
 # These values get expanded later using the :U variable modifier, and this
@@ -128,8 +128,10 @@ ${closing-brace}=	<closing-brace>	# alte
 .info eight ${$}${$}${$}${$} and no cents.
 
 # What happens if the values from the .for loop contain a literal newline?
-# Oops, the newline is added verbatim to the loop body, where it is later
-# interpreted as an ordinary newline.
+# Before for.c 1.144 from 2021-06-25, the newline was passed verbatim to the
+# body of the .for loop, where it was then interpreted as a literal newline,
+# leading to syntax errors such as "Unclosed variable expression" in the upper
+# line and "Invalid line type" in the lower line.
 .for i in "${.newline}"
 .  info short: $i
 .  info long: ${i}

Reply via email to