Package FuzzManager :: Package FTB :: Module AssertionHelper
[hide private]
[frames] | no frames]

Source Code for Module FuzzManager.FTB.AssertionHelper

  1  ''' 
  2  AssertionHelper 
  3   
  4  Provides various functions around assertion handling and processing 
  5   
  6  @author:     Christian Holler (:decoder) 
  7   
  8  @license: 
  9   
 10  This Source Code Form is subject to the terms of the Mozilla Public 
 11  License, v. 2.0. If a copy of the MPL was not distributed with this 
 12  file, You can obtain one at http://mozilla.org/MPL/2.0/. 
 13   
 14  @contact:    choller@mozilla.com 
 15  ''' 
 16   
 17  import re 
 18   
 19   
20 -def getAssertion(output, onlyProgramAssertions=False):
21 ''' 22 This helper class provides a way to extract and process the 23 different types of assertions from a given buffer. 24 The problem here is that pretty much every software has its 25 own type of assertions with different output formats. 26 27 The "onlyProgramAssertions" boolean is to indicate that we 28 are only interested in output from the program itself. 29 Some aborts, like ASan or glibc, are not desirable in some 30 cases, like signature generation and lead to incompatible 31 signatures. 32 33 @type output: list 34 @param output: List of strings to be searched 35 36 @type onlyProgramAssertions: bool 37 @param onlyProgramAssertions: Boolean, see above 38 ''' 39 lastLine = None 40 addNext = False 41 42 # Use this to ignore the ASan head line in case of an assertion 43 haveFatalAssertion = False 44 45 for line in output: 46 # Remove any PID output at the beginning of the line 47 line = re.sub("^\\[\\d+\\]\\s+", "", line, count=1) 48 49 if addNext: 50 lastLine += " " 51 lastLine += line 52 elif line.startswith("Assertion failure"): 53 # Firefox fatal assertion (MOZ_ASSERT, JS_ASSERT) 54 lastLine = line 55 haveFatalAssertion = True 56 elif line.startswith("# Fatal error in"): 57 # Support v8 non-standard multi-line assertion output 58 lastLine = line 59 haveFatalAssertion = True 60 addNext = True 61 elif not onlyProgramAssertions and not haveFatalAssertion and "ERROR: AddressSanitizer" in line: 62 lastLine = line 63 elif "Assertion" in line and "failed" in line: 64 # Firefox ANGLE assertion 65 lastLine = line 66 elif ": failed assertion" in line: 67 # Firefox Skia assertion (SkASSERT) 68 lastLine = line 69 haveFatalAssertion = True 70 elif not onlyProgramAssertions and "glibc detected" in line: 71 # Aborts caused by glibc runtime error detection 72 lastLine = line 73 elif "MOZ_CRASH" in line and re.search("Hit MOZ_CRASH\(.+\)", line): 74 # MOZ_CRASH line, but with a message (we should only look at these) 75 lastLine = line 76 elif "runtime error" in line and re.search(":\\d+:\\d+: runtime error: ", line): 77 # UBSan error. Even though this is not a program assertion, we should 78 # really include it in the signature because what UBSan reports here 79 # is not really a crash. 80 lastLine = line 81 elif line.startswith("[Non-crash bug] "): 82 # Magic string "added" to stderr by some fuzzers. 83 lastLine = line 84 85 return lastLine
86 87
88 -def getSanitizedAssertionPattern(msg):
89 ''' 90 This method provides a way to strip out unwanted dynamic information 91 from assertions and replace it with pattern matching elements, e.g. 92 for use in signature matching. 93 94 @type msg: string 95 @param msg: Assertion message to be sanitized 96 97 @rtype: string 98 @return: Sanitized assertion message (regular expression) 99 ''' 100 assert msg != None 101 102 sanitizedMsg = escapePattern(msg) 103 104 replacementPatterns = [] 105 106 # Replace everything that looks like a memory address 107 replacementPatterns.append("0x[0-9a-fA-F]+") 108 109 # Strip line numbers as they can easily change across versions 110 replacementPatterns.append(":[0-9]+") 111 replacementPatterns.append(", line [0-9]+") 112 113 # Strip full path 114 replacementPatterns.append(" /.+/") 115 116 # Replace larger numbers, assuming that 1-digit numbers are likely 117 # some constant that doesn't need sanitizing. 118 replacementPatterns.append("[0-9]{2,}") 119 120 for replacementPattern in replacementPatterns: 121 sanitizedMsg = re.sub(replacementPattern, replacementPattern, sanitizedMsg) 122 123 return sanitizedMsg
124 125
126 -def escapePattern(msg):
127 ''' 128 This method escapes regular expression characters in the string. 129 And no, this is not re.escape, which would escape many more characters. 130 131 @type msg: string 132 @param msg: String that needs to be quoted 133 134 @rtype: string 135 @return: Escaped string for use in regular expressions 136 ''' 137 138 escapedStr = msg 139 140 activeChars = [ "\\", "[", "]", "{", "}", "(", ")", "*", "+", "-", "?", "^", "$", ".", "|" ] 141 142 for activeChar in activeChars: 143 escapedStr = escapedStr.replace(activeChar, "\\" + activeChar) 144 145 return escapedStr
146