summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Meyering <meyering@redhat.com>2010-08-28 17:45:29 +0200
committerJim Meyering <meyering@redhat.com>2010-08-28 19:28:20 +0200
commit777024889c0043004962834f4d9353cfa6847dd6 (patch)
treeab597978663b93ef1134cdcaa57ab921dd1d21f0
parentc984948ff5db81b760a8a1d9d5d9512754fc30c2 (diff)
downloadcoreutils-777024889c0043004962834f4d9353cfa6847dd6.tar.xz
tac: avoid double free
* src/tac.c (main): Reading a line longer than 16KiB would cause tac to realloc its primary buffer. Then, just before exit, tac would mistakenly free the original (now free'd) buffer. This bug was introduced by commit be6c13e7, "maint: always free a buffer, to avoid even semblance of a leak". * NEWS (Bug fixes): Mention it. * tests/misc/tac (double-free): New test, to exercise this. Reported by Salvo Tomaselli in <http://bugs.debian.org/594666>.
-rw-r--r--NEWS3
-rw-r--r--src/tac.c6
-rwxr-xr-xtests/misc/tac6
3 files changed, 13 insertions, 2 deletions
diff --git a/NEWS b/NEWS
index 93a1f96b4..3eb28b1e3 100644
--- a/NEWS
+++ b/NEWS
@@ -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,
diff --git a/src/tac.c b/src/tac.c
index cec973601..859e0067a 100644
--- a/src/tac.c
+++ b/src/tac.c
@@ -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;