summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Goncharov <dgoncharov@users.sf.net>2023-04-30 09:39:04 -0400
committerPaul Smith <psmith@gnu.org>2023-04-30 09:41:02 -0400
commit06c75a35b93ac6ceacf0474e8b3a23d494fcea07 (patch)
tree3895563959fcc5e3f10bf58e091aea5b4ac2b3ec
parentebe0a1c9f1d1529a3f2c64d628686f500d460b0e (diff)
downloadmake-git-06c75a35b93ac6ceacf0474e8b3a23d494fcea07.tar.gz
[SV 64124] Avoid use-after-free in expand_variable_buf()
When the expanded value of the variable in buf occupies more space than available in variable_buffer, function variable_buffer_output reallocates variable_buffer: return a pointer into the new memory, not the old memory. * src/expand.c (expand_variable_buf): Preserve the offset of buf and return that offset into the (potentially reallocated) buffer. * tests/scripts/features/expand: Add tests.
-rw-r--r--src/expand.c16
-rw-r--r--tests/scripts/features/expand26
2 files changed, 39 insertions, 3 deletions
diff --git a/src/expand.c b/src/expand.c
index 3c97f387..3ca59505 100644
--- a/src/expand.c
+++ b/src/expand.c
@@ -255,17 +255,27 @@ expand_variable_output (char *ptr, const char *name, size_t length)
/* Expand a simple reference to variable NAME, which is LENGTH chars long.
The result is written to BUF which must point into the variable_buffer.
If BUF is NULL, start at the beginning of the current variable_buffer.
- Returns BUF, or the beginning of the buffer if BUF is NULL. */
+ Returns a pointer to the START of the expanded value of the variable.
+ The returned value is located inside variable_buffer.
+ The returned value is valid until the next call to one of the functions
+ which use variable_buffer. expand_variable_buf may reallocate
+ variable_buffer and render the passed-in BUF invalid. */
+
char *
expand_variable_buf (char *buf, const char *name, size_t length)
{
+ size_t offs;
+
if (!buf)
buf = initialize_variable_output ();
- expand_variable_output (buf, name, length);
+ assert (buf >= variable_buffer);
+ assert (buf < variable_buffer + variable_buffer_length);
+ offs = buf - variable_buffer;
- return buf;
+ expand_variable_output (buf, name, length);
+ return variable_buffer + offs;
}
/* Expand a simple reference to variable NAME, which is LENGTH chars long.
diff --git a/tests/scripts/features/expand b/tests/scripts/features/expand
new file mode 100644
index 00000000..64b9a890
--- /dev/null
+++ b/tests/scripts/features/expand
@@ -0,0 +1,26 @@
+# -*-perl-*-
+
+$description = "Test variable expansion.";
+
+# sv 64124.
+# Expand a variable whose value exceeds 200 bytes.
+# 200 is the initial size of variable_buffer.
+# Value bigger than 200 bytes causes a realloc of variable_buffer.
+# In this test the variable being expanded is MAKEFLAGS and its value occupies
+# 11, 550 and 110000 bytes.
+
+my $s = "hello_world";
+my @mult = (1, 50, 10000);
+
+for my $m (@mult) {
+ my $answer = $s x $m;
+ $ENV{'MAKEFLAGS'} = " -- hello=$answer";
+ run_make_test(q!
+$(info x$(hello)y)
+all:
+!,
+ '', "x${answer}y\n#MAKE#: Nothing to be done for 'all'.\n");
+}
+
+# This tells the test driver that the perl test script executed properly.
+1;