]> git.ipfire.org Git - thirdparty/make.git/commitdiff
[SV 64124] Avoid use-after-free in expand_variable_buf()
authorDmitry Goncharov <dgoncharov@users.sf.net>
Sun, 30 Apr 2023 13:39:04 +0000 (09:39 -0400)
committerPaul Smith <psmith@gnu.org>
Sun, 30 Apr 2023 13:41:02 +0000 (09:41 -0400)
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.

src/expand.c
tests/scripts/features/expand [new file with mode: 0644]

index 3c97f387a7f3d993acb34db43caa2408124869d4..3ca5950597c975f8b5d63695069d2074522d707c 100644 (file)
@@ -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 (file)
index 0000000..64b9a89
--- /dev/null
@@ -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;