diff options
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | src/tac.c | 6 | ||||
-rwxr-xr-x | tests/misc/tac | 6 |
3 files changed, 13 insertions, 2 deletions
@@ -11,6 +11,9 @@ GNU coreutils NEWS -*- outline -*- du -H and -L now consistently count pointed-to files instead of symbolic links, and correctly diagnose dangling symlinks. + tac would perform a double-free when given an input line longer than 16KiB. + [bug introduced in coreutils-8.3] + ** New features cp now accepts the --attributes-only option to not copy file data, @@ -633,7 +633,6 @@ main (int argc, char **argv) if (! (read_size < half_buffer_size && half_buffer_size < G_buffer_size)) xalloc_die (); G_buffer = xmalloc (G_buffer_size); - void *buf = G_buffer; if (sentinel_length) { strcpy (G_buffer, separator); @@ -666,6 +665,9 @@ main (int argc, char **argv) error (0, errno, "-"); ok = false; } - free (buf); + + size_t offset = sentinel_length ? sentinel_length : 1; + free (G_buffer - offset); + exit (ok ? EXIT_SUCCESS : EXIT_FAILURE); } diff --git a/tests/misc/tac b/tests/misc/tac index 763104993..4130c004d 100755 --- a/tests/misc/tac +++ b/tests/misc/tac @@ -24,6 +24,9 @@ my $prog = 'tac'; my $bad_dir = 'no/such/dir'; +# This must be longer than 16KiB to trigger the double free in coreutils-8.5. +my $long_line = 'o' x (16 * 1024 + 1); + my @Tests = ( ['segfault', '-r', {IN=>"a\n"}, {IN=>"b\n"}, {OUT=>"a\nb\n"}], @@ -67,6 +70,9 @@ my @Tests = {ERR_SUBST => "s,`$bad_dir': .*,...,"}, {ERR => "$prog: cannot create temporary file in ...\n"}, {EXIT => 1}], + + # coreutils-8.5's tac would double-free its primary buffer. + ['double-free', {IN=>$long_line}, {OUT=>$long_line}], ); @Tests = triple_test \@Tests; |