From abe7196c53f23186f06e1c56a406ec4c9a75a4f7 Mon Sep 17 00:00:00 2001 From: Alexander Færøy Date: Thu, 9 Jul 2020 02:16:11 +0000 Subject: Strip '\r' characters when reading text files on Unix. This patch ensures that we strip "\r" characters on both Windows as well as Unix when we read text files. This should prevent the issue where some Tor state files have been moved from a Windows machine, and thus contains CRLF line ending, to a Unix machine where only \n is needed. We add a test-case to ensure that we handle this properly on all our platforms. See: https://bugs.torproject.org/tpo/core/tor/33781 --- changes/bug33781 | 7 +++++++ src/lib/fs/files.c | 5 ++--- src/test/test_util.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 changes/bug33781 diff --git a/changes/bug33781 b/changes/bug33781 new file mode 100644 index 0000000000..9f63ab0a2c --- /dev/null +++ b/changes/bug33781 @@ -0,0 +1,7 @@ + o Minor bugfixes (compatibility): + - Strip '\r' characters when reading text files on Unix platforms. + This should resolve an issue where a relay operator migrates a relay from + Windows to Unix, but does not change the line ending of Tor's various state + files to match the platform, the CRLF line endings from Windows ends up leaking + into other files such as the extra-info document. Fixes bug 33781; bugfix on + 0.0.9pre5. diff --git a/src/lib/fs/files.c b/src/lib/fs/files.c index b98a51a287..55d5f1bf8c 100644 --- a/src/lib/fs/files.c +++ b/src/lib/fs/files.c @@ -685,7 +685,6 @@ read_file_to_str, (const char *filename, int flags, struct stat *stat_out)) } string[r] = '\0'; /* NUL-terminate the result. */ -#if defined(_WIN32) || defined(__CYGWIN__) if (!bin && strchr(string, '\r')) { log_debug(LD_FS, "We didn't convert CRLF to LF as well as we hoped " "when reading %s. Coping.", @@ -695,8 +694,7 @@ read_file_to_str, (const char *filename, int flags, struct stat *stat_out)) } if (!bin) { statbuf.st_size = (size_t) r; - } else -#endif /* defined(_WIN32) || defined(__CYGWIN__) */ + } else { if (r != statbuf.st_size) { /* Unless we're using text mode on win32, we'd better have an exact * match for size. */ @@ -708,6 +706,7 @@ read_file_to_str, (const char *filename, int flags, struct stat *stat_out)) errno = save_errno; return NULL; } + } close(fd); if (stat_out) { memcpy(stat_out, &statbuf, sizeof(struct stat)); diff --git a/src/test/test_util.c b/src/test/test_util.c index 3a0eb15157..06ea8191a2 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -173,6 +173,54 @@ test_util_read_file_eof_zero_bytes(void *arg) test_util_read_until_eof_impl("tor_test_fifo_empty", 0, 10000); } +static void +test_util_read_file_endlines(void *arg) +{ + (void)arg; + + char *fname = NULL; + char *read_content = NULL; + int r = -1; + + /* Write a file that contains both \n and \r\n as line ending. */ + const char *file_content = "foo bar\n" + "foo bar baz\r\n" + "foo bar\r\n"; + + const char *expected_file_content = "foo bar\n" + "foo bar baz\n" + "foo bar\n"; + + fname = tor_strdup(get_fname("file_with_crlf_ending")); + + r = write_bytes_to_file(fname, file_content, strlen(file_content), 1); + tt_int_op(r, OP_EQ, 0); + + /* Read the file in text mode: we strip \r's from the files on both Windows + * and UNIX. */ + read_content = read_file_to_str(fname, 0, NULL); + + tt_ptr_op(read_content, OP_NE, NULL); + tt_int_op(strlen(read_content), OP_EQ, strlen(expected_file_content)); + tt_str_op(read_content, OP_EQ, expected_file_content); + + tor_free(read_content); + + /* Read the file in binary mode: we should preserve the \r here. */ + read_content = read_file_to_str(fname, RFTS_BIN, NULL); + + tt_ptr_op(read_content, OP_NE, NULL); + tt_int_op(strlen(read_content), OP_EQ, strlen(file_content)); + tt_str_op(read_content, OP_EQ, file_content); + + tor_free(read_content); + + done: + unlink(fname); + tor_free(fname); + tor_free(read_content); +} + /* Test the basic expected behaviour for write_chunks_to_file. * NOTE: This will need to be updated if we ever change the tempfile location * or extension */ @@ -6508,6 +6556,7 @@ struct testcase_t util_tests[] = { UTIL_TEST(read_file_eof_two_loops, 0), UTIL_TEST(read_file_eof_two_loops_b, 0), UTIL_TEST(read_file_eof_zero_bytes, 0), + UTIL_TEST(read_file_endlines, 0), UTIL_TEST(write_chunks_to_file, 0), UTIL_TEST(mathlog, 0), UTIL_TEST(fraction, 0), -- cgit v1.2.3-54-g00ecf From 623af0155e0664f46adb1fcc218bc193a9d15916 Mon Sep 17 00:00:00 2001 From: Alexander Færøy Date: Tue, 14 Jul 2020 17:34:38 +0000 Subject: Update docstring for read_file_to_str() on stripping of CR characters. See: https://bugs.torproject.org/tpo/core/tor/33781 --- src/lib/fs/files.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/fs/files.c b/src/lib/fs/files.c index 55d5f1bf8c..ec7dbca0e9 100644 --- a/src/lib/fs/files.c +++ b/src/lib/fs/files.c @@ -607,6 +607,9 @@ read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, size_t *sz_out) * If flags & RFTS_BIN, open the file in binary mode. * If flags & RFTS_IGNORE_MISSING, don't warn if the file * doesn't exist. + * + * Unless the RFTS_BIN flag is set in flags, this function will strip + * any CR characters in the return value on all platforms. */ /* * This function may return an erroneous result if the file -- cgit v1.2.3-54-g00ecf