From 06c75a35b93ac6ceacf0474e8b3a23d494fcea07 Mon Sep 17 00:00:00 2001 From: Dmitry Goncharov Date: Sun, 30 Apr 2023 09:39:04 -0400 Subject: [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. --- src/expand.c | 16 +++++++++++++--- tests/scripts/features/expand | 26 ++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 tests/scripts/features/expand 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; -- cgit v1.2.1