diff options
author | Wladimir J. van der Laan <laanwj@protonmail.com> | 2019-10-10 13:25:08 +0200 |
---|---|---|
committer | fanquake <fanquake@gmail.com> | 2019-10-19 13:58:18 -0400 |
commit | dc0fe7ae1f941a2aafc29a0c7b7068e160583ef4 (patch) | |
tree | ef0c138ae32acc2ac1d95c6761c074fc96ed0df4 /src | |
parent | ba46f394182dc2ac85ea7e0a7b6141312180de73 (diff) |
util: Filter control characters out of log messages
Belts and suspenders: make sure outgoing log messages don't contain
potentially suspicious characters, such as terminal control codes.
This escapes control characters except newline ('\n') in C syntax.
It escapes instead of removes them to still allow for troubleshooting
issues where they accidentally end up in strings.
Github-Pull: #17095
Rebased-From: d7820a1250070f3640246ae497e049bee0b3516f
Diffstat (limited to 'src')
-rw-r--r-- | src/logging.cpp | 24 | ||||
-rw-r--r-- | src/test/util_tests.cpp | 18 |
2 files changed, 41 insertions, 1 deletions
diff --git a/src/logging.cpp b/src/logging.cpp index dc2d130a2a..60ab486198 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -224,10 +224,32 @@ std::string BCLog::Logger::LogTimestampStr(const std::string& str) return strStamped; } +namespace BCLog { + /** Belts and suspenders: make sure outgoing log messages don't contain + * potentially suspicious characters, such as terminal control codes. + * + * This escapes control characters except newline ('\n') in C syntax. + * It escapes instead of removes them to still allow for troubleshooting + * issues where they accidentally end up in strings. + */ + std::string LogEscapeMessage(const std::string& str) { + std::string ret; + for (char ch_in : str) { + uint8_t ch = (uint8_t)ch_in; + if ((ch >= 32 || ch == '\n') && ch != '\x7f') { + ret += ch_in; + } else { + ret += strprintf("\\x%02x", ch); + } + } + return ret; + } +} + void BCLog::Logger::LogPrintStr(const std::string& str) { std::lock_guard<std::mutex> scoped_lock(m_cs); - std::string str_prefixed = str; + std::string str_prefixed = LogEscapeMessage(str); if (m_log_threadnames && m_started_new_line) { str_prefixed.insert(0, "[" + util::ThreadGetInternalName() + "] "); diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index d0cd4b0a03..dda6241a7b 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -25,6 +25,11 @@ #include <boost/test/unit_test.hpp> +/* defined in logging.cpp */ +namespace BCLog { + std::string LogEscapeMessage(const std::string& str); +} + BOOST_FIXTURE_TEST_SUITE(util_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(util_criticalsection) @@ -1572,4 +1577,17 @@ BOOST_AUTO_TEST_CASE(test_Capitalize) BOOST_CHECK_EQUAL(Capitalize("\x00\xfe\xff"), "\x00\xfe\xff"); } +BOOST_AUTO_TEST_CASE(test_LogEscapeMessage) +{ + // ASCII and UTF-8 must pass through unaltered. + BOOST_CHECK_EQUAL(BCLog::LogEscapeMessage("Valid log message貓"), "Valid log message貓"); + // Newlines must pass through unaltered. + BOOST_CHECK_EQUAL(BCLog::LogEscapeMessage("Message\n with newlines\n"), "Message\n with newlines\n"); + // Other control characters are escaped in C syntax. + BOOST_CHECK_EQUAL(BCLog::LogEscapeMessage("\x01\x7f Corrupted log message\x0d"), R"(\x01\x7f Corrupted log message\x0d)"); + // Embedded NULL characters are escaped too. + const std::string NUL("O\x00O", 3); + BOOST_CHECK_EQUAL(BCLog::LogEscapeMessage(NUL), R"(O\x00O)"); +} + BOOST_AUTO_TEST_SUITE_END() |