Skip to content

Commit

Permalink
util: Filter control characters out of log messages
Browse files Browse the repository at this point in the history
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: d7820a1
  • Loading branch information
laanwj authored and fanquake committed Oct 19, 2019
1 parent ac30fc4 commit 0b18ea6
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 1 deletion.
25 changes: 24 additions & 1 deletion src/logging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,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::string strTimestamped = LogTimestampStr(str);
std::string strEscaped = LogEscapeMessage(str);
std::string strTimestamped = LogTimestampStr(strEscaped);

if (m_print_to_console) {
// print to console
Expand Down
18 changes: 18 additions & 0 deletions src/test/util_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,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)
Expand Down Expand Up @@ -1256,4 +1261,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()

0 comments on commit 0b18ea6

Please sign in to comment.