Skip to content

Commit

Permalink
Prevent accidental DoS on malformed stacktraces (#3980)
Browse files Browse the repository at this point in the history
Enormous stacktraces containing a giant array on a single line is
causing bots to freeze.
Although fuzztest really should not be printing an input this large,
let's try to be resilient when it misbehaves.

Fixes: #3978
  • Loading branch information
jonathanmetzman committed May 8, 2024
1 parent db23f2c commit 66f2069
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3744,6 +3744,12 @@ def test_split_stacktrace(self):

self.assertEqual(actual_split_stacktrace, expected_split_stacktrace)

def test_split_stacktrace_no_dos(self):
"""Tests that split_stacktrace wont search forever unless there's a very
well crafted input."""
stacktrace = "S text\n" + " 42 " * 100000 + "j text\n"
StackParser.split_stacktrace(stacktrace)

def test_jazzer_js_javascript(self):
"""Test Jazzer.js JS stacktrace."""
data = self._read_test_data('jazzer_js_javascript.txt')
Expand Down
4 changes: 4 additions & 0 deletions src/clusterfuzz/stacktraces/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1407,6 +1407,10 @@ def should_ignore_line_for_crash_processing(line, state):
if SAN_DEADLYSIGNAL_REGEX.match(line):
return True

if len(line) > 1024**2:
logs.log_error('Line is too long for a stacktrace.')
return True

return False


Expand Down
10 changes: 8 additions & 2 deletions src/clusterfuzz/stacktraces/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,11 @@
# The 'assertion .* failed' is suffixed with the failure reason. E.g.,
# 'assertion __dest < len() failed: sample_array[] index out of bounds',
# 'assertion !full() failed: sample_function() called on an empty vector'
# Add the lookahead group to prevent DoS, see
# https://github.com/google/clusterfuzz/issues/3978.
ASSERT_REGEX_GLIBC_SUFFIXED = re.compile(
r'.*\S.*\/.*:\d+:\s*assertion .* failed:\s*(\S.*)')
r'(?=.*assertion .* failed:.).*.*\S.*\/.*:\d+:\s*assertion .* failed:\s*(\S.*)' # pylint: disable=line-too-long
)
ASSERT_NOT_REACHED_REGEX = re.compile(r'^\s*SHOULD NEVER BE REACHED\s*$')
CENTIPEDE_TIMEOUT_REGEX = re.compile(r'(?:%s)' % '|'.join([
r'========= Timeout of \d+ seconds exceeded; exiting',
Expand Down Expand Up @@ -200,8 +203,11 @@
r'[ ]*([^ ]*|Atomic [^ ]*) of size ([^ ]*) at ([^ ]*)')
SAN_DEADLYSIGNAL_REGEX = re.compile(
r'(Address|Leak|Memory|UndefinedBehavior|Thread)Sanitizer:DEADLYSIGNAL')
# Use the lookahead group to prevent DoS, see
# https://github.com/google/clusterfuzz/issues/3978.
CONCATENATED_SAN_DEADLYSIGNAL_REGEX = re.compile(
r'\n([^\n]*\S[^\n]*)(' + SAN_DEADLYSIGNAL_REGEX.pattern + r')\n')
r'\n(?=.*Sanitizer\:DEADLYSIGNAL.*)([^\n]*\S[^\n]*)(' +
SAN_DEADLYSIGNAL_REGEX.pattern + r')\n')
SPLIT_CONCATENATED_SAN_DEADLYSIGNAL_REGEX = r'\n\1\n\2\n'
SAN_FPE_REGEX = re.compile(r'.*[a-zA-Z]+Sanitizer: FPE ')
SAN_ILL_REGEX = re.compile(r'.*[a-zA-Z]+Sanitizer: ILL ')
Expand Down

0 comments on commit 66f2069

Please sign in to comment.