From: Pádraig Brady
Date: Sun, 27 Nov 2016 15:09:53 +0000 (+0000) Subject: tac: fix mem corruption when failing to read non seekable inputs X-Git-Tag: v8.26~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a39641cbb8f37c5a19dd4820c6f6719c82d3e633;p=thirdparty%2Fcoreutils.git tac: fix mem corruption when failing to read non seekable inputs 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 --- diff --git a/NEWS b/NEWS index 2e3096822a..6f7505f82d 100644 --- 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. diff --git a/src/tac.c b/src/tac.c index 2e820fa077..c1b6003daa 100644 --- 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. diff --git a/tests/misc/tac-2-nonseekable.sh b/tests/misc/tac-2-nonseekable.sh index 47e7849adf..d148218c19 100755 --- a/tests/misc/tac-2-nonseekable.sh +++ b/tests/misc/tac-2-nonseekable.sh @@ -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