]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
tac: fix mem corruption when failing to read non seekable inputs
authorPádraig Brady <P@draigBrady.com>
Sun, 27 Nov 2016 15:09:53 +0000 (15:09 +0000)
committerPádraig Brady <P@draigBrady.com>
Mon, 28 Nov 2016 13:19:24 +0000 (13:19 +0000)
This was detected with ASAN, but can also be seen without ASAN with:
  $ tac - - <&-
  tac: standard input: read error: Bad file descriptor
  *** Error in `tac': malloc(): memory corruption: 0x...

* src/tac.c (copy_to_temp): Don't close our output stream on
(possibly transient) output error, or on input error.
(temp_stream): clearerr() on the stream about to be reused,
to ensure future stream use is not impacted by transient errors.
* tests/misc/tac-2-nonseekable.sh: Add a test case.
* NEWS: Mention the bug fix.
Fixes http://bugs.gnu.org/25041

NEWS
src/tac.c
tests/misc/tac-2-nonseekable.sh

diff --git a/NEWS b/NEWS
index 2e3096822acc406d661dfad1cf5bfdb2266c02e1..6f7505f82dc5ba06cb187ee40d6de6f707d84029 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -50,6 +50,9 @@ GNU coreutils NEWS                                    -*- outline -*-
   seq now immediately exits upon write errors.
   [This bug was present in "the beginning".]
 
+  tac no longer crashes when there are issues reading from non-seekable inputs.
+  [bug introduced in coreutils-8.15]
+
   tail -F now continues to process initially untailable files that are replaced
   by a tailable file.  This was handled correctly when inotify was available,
   and is now handled correctly in all cases.
index 2e820fa07716794d502ebe9682d55bf4f91b3896..c1b6003daa2f73d46142866004587e3aac4eab72 100644 (file)
--- a/src/tac.c
+++ b/src/tac.c
@@ -477,6 +477,7 @@ temp_stream (FILE **fp, char **file_name)
     }
   else
     {
+      clearerr (tmp_fp);
       if (fseeko (tmp_fp, 0, SEEK_SET) < 0
           || ftruncate (fileno (tmp_fp), 0) < 0)
         {
@@ -512,13 +513,13 @@ copy_to_temp (FILE **g_tmp, char **g_tempfile, int input_fd, char const *file)
       if (bytes_read == SAFE_READ_ERROR)
         {
           error (0, errno, _("%s: read error"), quotef (file));
-          goto Fail;
+          return -1;
         }
 
       if (fwrite (G_buffer, 1, bytes_read, fp) != bytes_read)
         {
           error (0, errno, _("%s: write error"), quotef (file_name));
-          goto Fail;
+          return -1;
         }
 
       /* Implicitly <= OFF_T_MAX due to preceding fwrite(),
@@ -530,16 +531,12 @@ copy_to_temp (FILE **g_tmp, char **g_tempfile, int input_fd, char const *file)
   if (fflush (fp) != 0)
     {
       error (0, errno, _("%s: write error"), quotef (file_name));
-      goto Fail;
+      return -1;
     }
 
   *g_tmp = fp;
   *g_tempfile = file_name;
   return bytes_copied;
-
- Fail:
-  fclose (fp);
-  return -1;
 }
 
 /* Copy INPUT_FD to a temporary, then tac that file.
index 47e7849adf51be074a2a637a75ff5c62de8437b1..d148218c19e7daeb8973b65c322a595e319c0ed6 100755 (executable)
@@ -36,4 +36,7 @@ for file in /proc/version /sys/kernel/profiling; do
   fi
 done
 
+# This failed due to heap corruption from v8.15-v8.25 inclusive.
+returns_ 1 tac - - <&- 2>err || fail=1
+
 Exit $fail