Пример #1
0
def test_SignatureMatchWithUnicode():
    config = ProgramConfiguration('test', 'x86-64', 'linux')
    crashInfo = CrashInfo.fromRawCrashData(
        ["(«f => (generator.throw(f))», «undefined»)"], [], config)
    testSignature = CrashSignature(
        '{"symptoms": [{"src": "stdout", "type": "output", "value": "x"}]}')
    assert not testSignature.matches(crashInfo)
Пример #2
0
    def search(self, crashInfo):
        '''
        Searches within the local signature cache directory for a signature matching the
        given crash.

        @type crashInfo: CrashInfo
        @param crashInfo: CrashInfo instance obtained from L{CrashInfo.fromRawCrashData}

        @rtype: tuple
        @return: Tuple containing filename of the signature and metadata matching, or None if no match.
        '''

        cachedSigFiles = os.listdir(self.sigCacheDir)

        for sigFile in cachedSigFiles:
            if not sigFile.endswith('.signature'):
                continue

            sigFile = os.path.join(self.sigCacheDir, sigFile)
            if not os.path.isdir(sigFile):
                with open(sigFile) as f:
                    sigData = f.read()
                    crashSig = CrashSignature(sigData)
                    if crashSig.matches(crashInfo):
                        metadataFile = sigFile.replace('.signature', '.metadata')
                        metadata = None
                        if os.path.exists(metadataFile):
                            with open(metadataFile) as m:
                                metadata = json.loads(m.read())

                        return (sigFile, metadata)

        return (None, None)
Пример #3
0
    def search(self, crashInfo):
        '''
        Searches within the local signature cache directory for a signature matching the
        given crash.

        @type crashInfo: CrashInfo
        @param crashInfo: CrashInfo instance obtained from L{CrashInfo.fromRawCrashData}

        @rtype: tuple
        @return: Tuple containing filename of the signature and metadata matching, or None if no match.
        '''

        cachedSigFiles = os.listdir(self.sigCacheDir)

        for sigFile in cachedSigFiles:
            if not sigFile.endswith('.signature'):
                continue

            sigFile = os.path.join(self.sigCacheDir, sigFile)
            if not os.path.isdir(sigFile):
                with open(sigFile) as f:
                    sigData = f.read()
                    crashSig = CrashSignature(sigData)
                    if crashSig.matches(crashInfo):
                        metadataFile = sigFile.replace('.signature',
                                                       '.metadata')
                        metadata = None
                        if os.path.exists(metadataFile):
                            with open(metadataFile) as m:
                                metadata = json.loads(m.read())

                        return (sigFile, metadata)

        return (None, None)
Пример #4
0
def test_SignatureStackSizeTest():
    config = ProgramConfiguration("test", "x86-64", "linux")
    crashInfoPos = CrashInfo.fromRawCrashData([], [], config, auxCrashData=testAsanLongTrace.splitlines())

    # The test signature uses > 15 which was previously interpreted as 0x15
    # while the test crash data has 16 frames.
    testSig = CrashSignature(testSignatureStackSize)
    assert testSig.matches(crashInfoPos)
Пример #5
0
    def runTest(self):
        config = ProgramConfiguration("test", "x86-64", "linux")
        crashInfoPos = CrashInfo.fromRawCrashData([], [], config, auxCrashData=testAsanLongTrace.splitlines())

        # The test signature uses > 15 which was previously interpreted as 0x15
        # while the test crash data has 16 frames.
        testSig = CrashSignature(testSignatureStackSize)
        self.assertTrue(testSig.matches(crashInfoPos))
 def runTest(self):
     config = ProgramConfiguration('test', 'x86-64', 'linux')
     crashInfo = CrashInfo.fromRawCrashData(
         ["(«f => (generator.throw(f))», «undefined»)"], [], config)
     testSignature = CrashSignature(
         '{"symptoms": [{"src": "stdout", "type": "output", "value": "x"}]}'
     )
     self.assertFalse(testSignature.matches(crashInfo))
Пример #7
0
    def runTest(self):
        config = ProgramConfiguration("test", "x86", "linux")
        crashInfoNeg = CrashInfo.fromRawCrashData([], [], config, auxCrashData=testTraceHeapWithCrashAddress.splitlines())
        crashInfoPos = CrashInfo.fromRawCrashData([], [], config, auxCrashData=testTraceHeapWithoutCrashAddress.splitlines())

        testSigEmptyCrashAddress = CrashSignature(testSignatureEmptyCrashAddress)

        self.assertTrue(testSigEmptyCrashAddress.matches(crashInfoPos))
        self.assertFalse(testSigEmptyCrashAddress.matches(crashInfoNeg))
Пример #8
0
def test_SignatureStackFramesRegressionTest():
    config = ProgramConfiguration("test", "x86", "linux")
    crashInfoNeg = CrashInfo.fromRawCrashData([], [], config,
                                              auxCrashData=testTraceHeapWithCrashAddress.splitlines())
    crashInfoPos = CrashInfo.fromRawCrashData([], [], config,
                                              auxCrashData=testTraceHeapWithoutCrashAddress.splitlines())

    testSigEmptyCrashAddress = CrashSignature(testSignatureEmptyCrashAddress)

    assert testSigEmptyCrashAddress.matches(crashInfoPos)
    assert not testSigEmptyCrashAddress.matches(crashInfoNeg)
Пример #9
0
    def runTest(self):
        config = ProgramConfiguration("test", "x86", "linux")

        crashInfo = CrashInfo.fromRawCrashData([], [], config, auxCrashData=testTrace1.splitlines())

        testSig1 = CrashSignature(testSignatureStackFrames1)
        testSig2 = CrashSignature(testSignatureStackFrames2)
        testSig3 = CrashSignature(testSignatureStackFrames3)
        testSig4 = CrashSignature(testSignatureStackFrames4)
        testSig5 = CrashSignature(testSignatureStackFrames5)

        self.assertTrue(testSig1.matches(crashInfo))
        self.assertTrue(testSig2.matches(crashInfo))
        self.assertTrue(testSig3.matches(crashInfo))
        self.assertTrue(testSig4.matches(crashInfo))
        self.assertFalse(testSig5.matches(crashInfo))
Пример #10
0
    def runTest(self):
        config = ProgramConfiguration("test", "x86-64", "linux")

        crashSignature1 = '{ "symptoms" : [ { "type" : "output", "value" : "test" } ] }'
        crashSignature1Neg = '{ "symptoms" : [ { "type" : "output", "src" : "stderr", "value" : "test" } ] }'
        crashSignature2 = '{ "symptoms" : [ { "type" : "output", "src" : "stderr", "value" : { "value" : "^fest$", "matchType" : "pcre" } } ] }'

        outputSignature1 = CrashSignature(crashSignature1)
        outputSignature1Neg = CrashSignature(crashSignature1Neg)
        outputSignature2 = CrashSignature(crashSignature2)

        gdbOutput = []
        stdout = []
        stderr = []

        stdout.append("Foo")
        stdout.append("Bartester")
        stdout.append("Baz")
        stderr.append("hackfest")

        crashInfo = CrashInfo.fromRawCrashData(stdout,
                                               stderr,
                                               config,
                                               auxCrashData=gdbOutput)

        self.assertIsInstance(crashInfo, NoCrashInfo)

        # Ensure we match on stdout/err if nothing is specified
        self.assert_(outputSignature1.matches(crashInfo))

        # Don't match stdout if stderr is specified
        self.assertFalse(outputSignature1Neg.matches(crashInfo))

        # Check that we're really using PCRE
        self.assertFalse(outputSignature2.matches(crashInfo))

        # Add something the PCRE should match, then retry
        stderr.append("fest")
        crashInfo = CrashInfo.fromRawCrashData(stdout,
                                               stderr,
                                               config,
                                               auxCrashData=gdbOutput)
        self.assert_(outputSignature2.matches(crashInfo))
Пример #11
0
    def runTest(self):
        collector = Collector(self.tmpCacheDir,
                              serverHost='127.0.0.1',
                              serverPort='8000',
                              serverProtocol='http',
                              serverUser=testAuthCreds[0],
                              serverPass=testAuthCreds[1],
                              clientId='test-fuzzer1')

        collector.refresh()

        receivedSignatures = False

        for sigFile in os.listdir(self.tmpCacheDir):
            receivedSignatures = True
            CrashSignature.fromFile(os.path.join(self.tmpCacheDir, sigFile))

        if not receivedSignatures:
            self.skipTest("Server did not provide signatures")
Пример #12
0
 def runTest(self):
     collector = Collector(self.tmpCacheDir, 
                           serverHost='127.0.0.1', 
                           serverPort='8000',
                           serverProtocol='http',
                           serverUser=testAuthCreds[0],
                           serverPass=testAuthCreds[1],  
                           clientId='test-fuzzer1')
     
     collector.refresh()
     
     receivedSignatures = False
     
     for sigFile in os.listdir(self.tmpCacheDir):
         receivedSignatures = True
         CrashSignature.fromFile(os.path.join(self.tmpCacheDir, sigFile))
     
     if not receivedSignatures:
         self.skipTest("Server did not provide signatures")
Пример #13
0
def test_SignaturePCREShortTest():
    config = ProgramConfiguration("test", "x86", "linux")

    crashInfo = CrashInfo.fromRawCrashData([], [], config, auxCrashData=testTrace1.splitlines())

    testSig1 = CrashSignature(testSignaturePCREShort1)
    testSig2 = CrashSignature(testSignaturePCREShort2)

    assert testSig1.matches(crashInfo)
    assert not testSig2.matches(crashInfo)
Пример #14
0
    def runTest(self):
        config = ProgramConfiguration("test", "x86", "linux")

        crashInfo = CrashInfo.fromRawCrashData([], [], config, auxCrashData=testTrace1.splitlines())

        testSig1 = CrashSignature(testSignaturePCREShort1)
        testSig2 = CrashSignature(testSignaturePCREShort2)

        self.assertTrue(testSig1.matches(crashInfo))
        self.assertFalse(testSig2.matches(crashInfo))
Пример #15
0
    def runTest(self):
        config = ProgramConfiguration("test", "x86-64", "linux")

        crashSignature1 = '{ "symptoms" : [ { "type" : "crashAddress", "address" : "< 0x1000" } ] }'
        crashSignature1Neg = '{ "symptoms" : [ { "type" : "crashAddress", "address" : "0x1000" } ] }'
        addressSig1 = CrashSignature(crashSignature1)
        addressSig1Neg = CrashSignature(crashSignature1Neg)
        
        crashInfo1 = CrashInfo.fromRawCrashData([], [], config, auxCrashData=gdbSampleTrace1.splitlines())
        crashInfo3 = CrashInfo.fromRawCrashData([], [], config, auxCrashData=gdbSampleTrace3.splitlines())

        self.assertIsInstance(crashInfo1, GDBCrashInfo)
        
        self.assert_(addressSig1.matches(crashInfo1))
        self.assertFalse(addressSig1Neg.matches(crashInfo1))
        
        # For crashInfo3, we don't have a crash address. Ensure we don't match
        self.assertFalse(addressSig1.matches(crashInfo3))
        self.assertFalse(addressSig1Neg.matches(crashInfo3))
Пример #16
0
    def runTest(self):
        config = ProgramConfiguration("test", "x86-64", "linux")

        crashSignature1 = '{ "symptoms" : [ { "type" : "stackFrame", "functionName" : "internalAppend" } ] }'
        crashSignature1Neg = '{ "symptoms" : [ { "type" : "stackFrame", "functionName" : "foobar" } ] }'
        
        crashSignature2 = '{ "symptoms" : [ { "type" : "stackFrame", "functionName" : "js::ion::MBasicBlock::setBackedge", "frameNumber" : "<= 4" } ] }'
        crashSignature2Neg = '{ "symptoms" : [ { "type" : "stackFrame", "functionName" : "js::ion::MBasicBlock::setBackedge", "frameNumber" : "> 4" } ] }'
        
        stackFrameSig1 = CrashSignature(crashSignature1)
        stackFrameSig1Neg = CrashSignature(crashSignature1Neg)
        
        stackFrameSig2 = CrashSignature(crashSignature2)
        stackFrameSig2Neg = CrashSignature(crashSignature2Neg)
        
        crashInfo1 = CrashInfo.fromRawCrashData([], [], config, auxCrashData=gdbSampleTrace1.splitlines())
        
        self.assertIsInstance(crashInfo1, GDBCrashInfo)
        
        self.assert_(stackFrameSig1.matches(crashInfo1))
        self.assertFalse(stackFrameSig1Neg.matches(crashInfo1))
        
        self.assert_(stackFrameSig2.matches(crashInfo1))
        self.assertFalse(stackFrameSig2Neg.matches(crashInfo1))
Пример #17
0
    def runTest(self):
        config = ProgramConfiguration("test", "x86-64", "linux")

        crashSignature1 = '{ "symptoms" : [ { "type" : "stackSize", "size" : 8 } ] }'
        crashSignature1Neg = '{ "symptoms" : [ { "type" : "stackSize", "size" : 9 } ] }'
        
        crashSignature2 = '{ "symptoms" : [ { "type" : "stackSize", "size" : "< 10" } ] }'
        crashSignature2Neg = '{ "symptoms" : [ { "type" : "stackSize", "size" : "> 10" } ] }'
        
        stackSizeSig1 = CrashSignature(crashSignature1)
        stackSizeSig1Neg = CrashSignature(crashSignature1Neg)
        
        stackSizeSig2 = CrashSignature(crashSignature2)
        stackSizeSig2Neg = CrashSignature(crashSignature2Neg)
        
        crashInfo1 = CrashInfo.fromRawCrashData([], [], config, auxCrashData=gdbSampleTrace1.splitlines())
        
        self.assertIsInstance(crashInfo1, GDBCrashInfo)
        
        self.assert_(stackSizeSig1.matches(crashInfo1))
        self.assertFalse(stackSizeSig1Neg.matches(crashInfo1))
        
        self.assert_(stackSizeSig2.matches(crashInfo1))
        self.assertFalse(stackSizeSig2Neg.matches(crashInfo1))
Пример #18
0
 def runTest(self):
     config = ProgramConfiguration("test", "x86-64", "linux")
     
     crashSignature1 = '{ "symptoms" : [ { "type" : "output", "value" : "test" } ] }'
     crashSignature1Neg = '{ "symptoms" : [ { "type" : "output", "src" : "stderr", "value" : "test" } ] }'
     crashSignature2 = '{ "symptoms" : [ { "type" : "output", "src" : "stderr", "value" : { "value" : "^fest$", "matchType" : "pcre" } } ] }'
     
     outputSignature1 = CrashSignature(crashSignature1)
     outputSignature1Neg = CrashSignature(crashSignature1Neg)
     outputSignature2 = CrashSignature(crashSignature2)
     
     gdbOutput = []
     stdout = []
     stderr = []
     
     stdout.append("Foo")
     stdout.append("Bartester")
     stdout.append("Baz")
     stderr.append("hackfest")
     
     crashInfo = CrashInfo.fromRawCrashData(stdout, stderr, config, auxCrashData=gdbOutput)
     
     self.assertIsInstance(crashInfo, NoCrashInfo)
     
     # Ensure we match on stdout/err if nothing is specified
     self.assert_(outputSignature1.matches(crashInfo))
     
     # Don't match stdout if stderr is specified 
     self.assertFalse(outputSignature1Neg.matches(crashInfo))
     
     # Check that we're really using PCRE
     self.assertFalse(outputSignature2.matches(crashInfo))
     
     # Add something the PCRE should match, then retry
     stderr.append("fest")
     crashInfo = CrashInfo.fromRawCrashData(stdout, stderr, config, auxCrashData=gdbOutput)
     self.assert_(outputSignature2.matches(crashInfo))
Пример #19
0
 def getOptimizedSignature(self):
     return CrashSignature(self.optimizedSignature)
Пример #20
0
 def getSignature(self):
     return CrashSignature(self.signature)
Пример #21
0
class CrashInfo():
    '''
    Abstract base class that provides a method to instantiate the right sub class.
    It also supports generating a CrashSignature based on the stored information.
    '''
    __metaclass__ = ABCMeta

    def __init__(self):
        # Store the raw data
        self.rawStdout = []
        self.rawStderr = []
        self.rawCrashData = []

        # Store processed data
        self.backtrace = []
        self.registers = {}
        self.crashAddress = None
        self.crashInstruction = None

        # Store configuration data (platform, product, os, etc.)
        self.configuration = None

        # This is an optional testcase that is not stored with the crashInfo but
        # can be "attached" before matching signatures that might require the
        # testcase.
        self.testcase = None

        # This can be used to record failures during signature creation
        self.failureReason = None

    def __str__(self):
        buf = []
        buf.append("Crash trace:")
        buf.append("")
        for idx, frame in enumerate(self.backtrace):
            buf.append("# %02d    %s" % (idx, frame))
        buf.append("")

        if self.crashAddress:
            buf.append("Crash address: %s" % self.crashAddress)

        if self.crashInstruction:
            buf.append("Crash instruction: %s" % self.crashInstruction)

        if self.crashAddress or self.crashInstruction:
            buf.append("")

        buf.append("Last 5 lines on stderr:")
        buf.extend(self.rawStderr[-5:])

        return "\n".join(buf)

    def toCacheObject(self):
        '''
        Create a cache object for restoring the class instance later on without parsing
        the crash data again. This object includes all class fields except for the
        storage heavy raw objects like stdout, stderr and raw crashdata.

        @rtype: dict
        @return: Dictionary containing expensive class fields
        '''
        cacheObject = {}
        cacheObject['backtrace'] = self.backtrace
        cacheObject['registers'] = self.registers

        if self.crashAddress is not None:
            cacheObject['crashAddress'] = long(self.crashAddress)
        else:
            cacheObject['crashAddress'] = None

        cacheObject['crashInstruction'] = self.crashInstruction
        cacheObject['failureReason'] = self.failureReason

        return cacheObject

    @staticmethod
    def fromRawCrashData(stdout,
                         stderr,
                         configuration,
                         auxCrashData=None,
                         cacheObject=None):
        '''
        Create appropriate CrashInfo instance from raw crash data

        @type stdout: List of strings
        @param stdout: List of lines as they appeared on stdout
        @type stderr: List of strings
        @param stderr: List of lines as they appeared on stderr
        @type configuration: ProgramConfiguration
        @param configuration: Exact program configuration that is associated with the crash
        @type auxCrashData: List of strings
        @param auxCrashData: Optional additional crash output (e.g. GDB). If not specified, stderr is used.
        @type cacheObject: Dictionary
        @param cacheObject: The cache object that should be used to restore the class fields
                            instead of parsing the crash data. The appropriate object can be
                            created by calling the toCacheObject method.

        @rtype: CrashInfo
        @return: Crash information object
        '''

        assert stdout == None or isinstance(stdout, list) or isinstance(
            stdout, basestring)
        assert stderr == None or isinstance(stderr, list) or isinstance(
            stderr, basestring)
        assert auxCrashData == None or isinstance(
            auxCrashData, list) or isinstance(auxCrashData, basestring)

        assert isinstance(configuration, ProgramConfiguration)

        if isinstance(stdout, basestring):
            stdout = stdout.splitlines()

        if isinstance(stderr, basestring):
            stderr = stderr.splitlines()

        if isinstance(auxCrashData, basestring):
            auxCrashData = auxCrashData.splitlines()

        if cacheObject is not None:
            c = CrashInfo()

            if stdout != None:
                c.rawStdout.extend(stdout)

            if stderr != None:
                c.rawStderr.extend(stderr)

            if auxCrashData != None:
                c.rawCrashData.extend(auxCrashData)

            c.configuration = configuration
            c.backtrace = cacheObject['backtrace']
            c.registers = cacheObject['registers']
            c.crashAddress = cacheObject['crashAddress']
            c.crashInstruction = cacheObject['crashInstruction']
            c.failureReason = cacheObject['failureReason']

            return c

        asanString = "ERROR: AddressSanitizer:"
        gdbString = "Program received signal "
        gdbCoreString = "Program terminated with signal "
        ubsanString = "SUMMARY: AddressSanitizer: undefined-behavior"
        appleString = "OS Version:            Mac OS X"

        # Use two strings for detecting Minidumps to avoid false positives
        minidumpFirstString = "OS|"
        minidumpSecondString = "CPU|"
        minidumpFirstDetected = False

        # Search both crashData and stderr, but prefer crashData
        lines = []
        if auxCrashData != None:
            lines.extend(auxCrashData)
        if stderr != None:
            lines.extend(stderr)

        for line in lines:
            if ubsanString in line:
                return UBSanCrashInfo(stdout, stderr, configuration,
                                      auxCrashData)
            elif asanString in line:
                return ASanCrashInfo(stdout, stderr, configuration,
                                     auxCrashData)
            elif appleString in line:
                return AppleCrashInfo(stdout, stderr, configuration,
                                      auxCrashData)
            elif gdbString in line or gdbCoreString in line:
                return GDBCrashInfo(stdout, stderr, configuration,
                                    auxCrashData)
            elif not minidumpFirstDetected and minidumpFirstString in line:
                # Only match Minidump output if the *next* line also contains
                # the second search string defined above.
                minidumpFirstDetected = True
            elif minidumpFirstDetected and minidumpSecondString in line:
                return MinidumpCrashInfo(stdout, stderr, configuration,
                                         auxCrashData)
            elif minidumpFirstDetected:
                minidumpFirstDetected = False

        # Default fallback to be used if there is neither ASan nor GDB output.
        # This is still useful in case there is no crash but we want to match
        # e.g. stdout/stderr output with signatures.
        return NoCrashInfo(stdout, stderr, configuration, auxCrashData)

    def createShortSignature(self):
        '''
        @rtype: String
        @return: A string representing this crash (short signature)
        '''
        # See if we have an abort message and if so, use that as short signature
        abortMsg = AssertionHelper.getAssertion(self.rawStderr, True)
        if abortMsg != None:
            return abortMsg

        # See if we have an abort message in our crash data maybe, e.g. for UBSan
        if self.rawCrashData:
            abortMsg = AssertionHelper.getAssertion(self.rawCrashData, True)
            if abortMsg != None:
                return abortMsg

        if not len(self.backtrace):
            return "No crash detected"

        return "[@ %s]" % self.backtrace[0]

    def createCrashSignature(self,
                             forceCrashAddress=False,
                             forceCrashInstruction=False,
                             maxFrames=8,
                             minimumSupportedVersion=13):
        '''
        @param forceCrashAddress: If True, the crash address will be included in any case
        @type forceCrashAddress: bool
        @param forceCrashInstruction: If True, the crash instruction will be included in any case
        @type forceCrashInstruction: bool
        @param maxFrames: How many frames (at most) should be included in the signature
        @type maxFrames: int

        @param minimumSupportedVersion: The minimum crash signature standard version that the
                                        generated signature should be valid for (10 => 1.0, 13 => 1.3)
        @type minimumSupportedVersion: int

        @rtype: CrashSignature
        @return: A crash signature object
        '''
        # Determine the actual number of frames based on how many we got
        if len(self.backtrace) > maxFrames:
            numFrames = maxFrames
        else:
            numFrames = len(self.backtrace)

        # See if we have an abort message and if so, get a sanitized version of it
        abortMsg = AssertionHelper.getAssertion(self.rawStderr, True)
        abortMsgInCrashdata = False

        if abortMsg is None and minimumSupportedVersion >= 13:
            # Look for abort messages also inside crashdata (e.g. UBSan)
            # only on version 1.3 or higher, because the "crashdata" source
            # type for output matching was added in that version.
            abortMsg = AssertionHelper.getAssertion(self.rawCrashData, True)
            abortMsgInCrashdata = True

        if abortMsg != None:
            abortMsg = AssertionHelper.getSanitizedAssertionPattern(abortMsg)

        # Consider the first four frames as top stack
        topStackLimit = 4

        symptomArr = []

        if abortMsg != None:
            abortMsgSrc = "stderr"
            if abortMsgInCrashdata:
                abortMsgSrc = "crashdata"

            # Compose StringMatch object with PCRE pattern.
            # Versions below 1.2 only support the full object PCRE style,
            # for anything newer, use the short form with forward slashes
            # to increase the readability of the signatures.
            if minimumSupportedVersion < 12:
                stringObj = {"value": abortMsg, "matchType": "pcre"}
                symptomObj = {
                    "type": "output",
                    "src": abortMsgSrc,
                    "value": stringObj
                }
            else:
                symptomObj = {
                    "type": "output",
                    "src": abortMsgSrc,
                    "value": "/%s/" % abortMsg
                }
            symptomArr.append(symptomObj)
        # If we have less than topStackLimit frames available anyway, count the difference
        # between topStackLimit and the available frames already as missing.
        # E.g. if the trace has only three entries anyway, one will be considered missing
        # right from the start. This should prevent that very short stack frames are used
        # for signatures without additional crash information that narrows the signature.

        if numFrames >= topStackLimit:
            topStackMissCount = 0
        else:
            topStackMissCount = topStackLimit - numFrames

        # StackFramesSymptom is only supported in 1.2 and higher,
        # for everything else, use multiple stackFrame symptoms
        if minimumSupportedVersion < 12:
            for idx in range(0, numFrames):
                functionName = self.backtrace[idx]
                if not functionName == "??":
                    symptomObj = {
                        "type": "stackFrame",
                        "frameNumber": idx,
                        "functionName": functionName
                    }
                    symptomArr.append(symptomObj)
                elif idx < 4:
                    # If we're in the top 4, we count this as a miss
                    topStackMissCount += 1
        else:
            framesArray = []

            for idx in range(0, numFrames):
                functionName = self.backtrace[idx]
                if not functionName == "??":
                    framesArray.append(functionName)
                else:
                    framesArray.append("?")
                    if idx < 4:
                        # If we're in the top 4, we count this as a miss
                        topStackMissCount += 1

            lastSymbolizedFrame = None
            for frameIdx in range(0, len(framesArray)):
                if str(framesArray[frameIdx]) != '?':
                    lastSymbolizedFrame = frameIdx

            if lastSymbolizedFrame != None:
                # Remove all elements behind the last symbolized frame
                framesArray = framesArray[:lastSymbolizedFrame + 1]
            else:
                # We don't have a single symbolized frame, so it doesn't make sense
                # to keep any wildcards in case we added some for unsymbolized frames.
                framesArray = []

            if framesArray:
                symptomArr.append({
                    "type": "stackFrames",
                    "functionNames": framesArray
                })

        # Missing too much of the top stack frames, add additional crash information
        stackIsInsufficient = topStackMissCount >= 2 and abortMsg == None

        includeCrashAddress = stackIsInsufficient or forceCrashAddress
        includeCrashInstruction = (
            stackIsInsufficient
            and self.crashInstruction != None) or forceCrashInstruction

        if includeCrashAddress:
            if self.crashAddress == None:
                failureReason = self.failureReason
                self.failureReason = "No crash address available from crash data. Reason: %s" % failureReason
                return None

            if self.crashAddress != 0L and self.crashAddress < 0x100L:
                # Try to match crash addresses that are small but non-zero
                # with a generic range that is likely associated with null-deref.
                crashAddress = "< 0x100"
            else:
                crashAddress = hex(self.crashAddress).rstrip("L")

            crashAddressSymptomObj = {
                "type": "crashAddress",
                "address": crashAddress
            }
            symptomArr.append(crashAddressSymptomObj)

        if includeCrashInstruction:
            if self.crashInstruction == None:
                failureReason = self.failureReason
                self.failureReason = "No crash instruction available from crash data. Reason: %s" % failureReason
                return None

            crashInstructionSymptomObj = {
                "type": "instruction",
                "instructionName": self.crashInstruction
            }
            symptomArr.append(crashInstructionSymptomObj)

        sigObj = {"symptoms": symptomArr}

        return CrashSignature(json.dumps(sigObj, indent=2))
Пример #22
0
    def createCrashSignature(self,
                             forceCrashAddress=False,
                             forceCrashInstruction=False,
                             maxFrames=8,
                             minimumSupportedVersion=12):
        '''
        @param forceCrashAddress: If True, the crash address will be included in any case
        @type forceCrashAddress: bool
        @param forceCrashInstruction: If True, the crash instruction will be included in any case
        @type forceCrashInstruction: bool
        @param maxFrames: How many frames (at most) should be included in the signature
        @type maxFrames: int
        
        @param minimumSupportedVersion: The minimum crash signature standard version that the 
                                        generated signature should be valid for (10 => 1.0, 12 => 1.2)
        @type minimumSupportedVersion: int
        
        @rtype: CrashSignature
        @return: A crash signature object
        '''
        # Determine the actual number of frames based on how many we got
        if len(self.backtrace) > maxFrames:
            numFrames = maxFrames
        else:
            numFrames = len(self.backtrace)

        # See if we have an abort message and if so, get a sanitized version of it
        abortMsg = AssertionHelper.getAssertion(self.rawStderr, True)
        if abortMsg != None:
            abortMsg = AssertionHelper.getSanitizedAssertionPattern(abortMsg)

        # Consider the first four frames as top stack
        topStackLimit = 4

        symptomArr = []

        if abortMsg != None:
            # Compose StringMatch object with PCRE pattern.
            # Versions below 1.2 only support the full object PCRE style,
            # for anything newer, use the short form with forward slashes
            # to increase the readability of the signatures.
            if minimumSupportedVersion < 12:
                stringObj = {"value": abortMsg, "matchType": "pcre"}
                symptomObj = {
                    "type": "output",
                    "src": "stderr",
                    "value": stringObj
                }
            else:
                symptomObj = {
                    "type": "output",
                    "src": "stderr",
                    "value": "/%s/" % abortMsg
                }
            symptomArr.append(symptomObj)
        # If we have less than topStackLimit frames available anyway, count the difference
        # between topStackLimit and the available frames already as missing.
        # E.g. if the trace has only three entries anyway, one will be considered missing
        # right from the start. This should prevent that very short stack frames are used
        # for signatures without additional crash information that narrows the signature.

        if numFrames >= topStackLimit:
            topStackMissCount = 0
        else:
            topStackMissCount = topStackLimit - numFrames

        # StackFramesSymptom is only supported in 1.2 and higher,
        # for everything else, use multiple stackFrame symptoms
        if minimumSupportedVersion < 12:
            for idx in range(0, numFrames):
                functionName = self.backtrace[idx]
                if not functionName == "??":
                    symptomObj = {
                        "type": "stackFrame",
                        "frameNumber": idx,
                        "functionName": functionName
                    }
                    symptomArr.append(symptomObj)
                elif idx < 4:
                    # If we're in the top 4, we count this as a miss
                    topStackMissCount += 1
        else:
            framesArray = []

            for idx in range(0, numFrames):
                functionName = self.backtrace[idx]
                if not functionName == "??":
                    framesArray.append(functionName)
                else:
                    framesArray.append("?")
                    if idx < 4:
                        # If we're in the top 4, we count this as a miss
                        topStackMissCount += 1

            lastSymbolizedFrame = None
            for frameIdx in range(0, len(framesArray)):
                if str(framesArray[frameIdx]) != '?':
                    lastSymbolizedFrame = frameIdx

            if lastSymbolizedFrame != None:
                # Remove all elements behind the last symbolized frame
                framesArray = framesArray[:lastSymbolizedFrame + 1]
            else:
                # We don't have a single symbolized frame, so it doesn't make sense
                # to keep any wildcards in case we added some for unsymbolized frames.
                framesArray = []

            if framesArray:
                symptomArr.append({
                    "type": "stackFrames",
                    "functionNames": framesArray
                })

        # Missing too much of the top stack frames, add additional crash information
        stackIsInsufficient = topStackMissCount >= 2 and abortMsg == None

        includeCrashAddress = stackIsInsufficient or forceCrashAddress
        includeCrashInstruction = (
            stackIsInsufficient
            and self.crashInstruction != None) or forceCrashInstruction

        if includeCrashAddress:
            if self.crashAddress == None:
                failureReason = self.failureReason
                self.failureReason = "No crash address available from crash data. Reason: %s" % failureReason
                return None

            crashAddress = hex(self.crashAddress).rstrip("L")

            crashAddressSymptomObj = {
                "type": "crashAddress",
                "address": crashAddress
            }
            symptomArr.append(crashAddressSymptomObj)

        if includeCrashInstruction:
            if self.crashInstruction == None:
                failureReason = self.failureReason
                self.failureReason = "No crash instruction available from crash data. Reason: %s" % failureReason
                return None

            crashInstructionSymptomObj = {
                "type": "instruction",
                "instructionName": self.crashInstruction
            }
            symptomArr.append(crashInstructionSymptomObj)

        sigObj = {"symptoms": symptomArr}

        return CrashSignature(json.dumps(sigObj, indent=2))
Пример #23
0
    def runTest(self):
        config = ProgramConfiguration("test", "x86-64", "linux")

        crashSignature1 = '{ "symptoms" : [ { "type" : "instruction", "registerNames" : ["r14"] } ] }'
        crashSignature1Neg = '{ "symptoms" : [ { "type" : "instruction", "registerNames" : ["r14", "rax"] } ] }'
        crashSignature2 = '{ "symptoms" : [ { "type" : "instruction", "instructionName" : "mov" } ] }'
        crashSignature2Neg = '{ "symptoms" : [ { "type" : "instruction", "instructionName" : "cmp" } ] }'
        crashSignature3 = '{ "symptoms" : [ { "type" : "instruction", "instructionName" : "mov", "registerNames" : ["r14", "rbx"] } ] }'
        crashSignature3Neg = '{ "symptoms" : [ { "type" : "instruction", "instructionName" : "mov", "registerNames" : ["r14", "rax"] } ] }'

        instructionSig1 = CrashSignature(crashSignature1)
        instructionSig1Neg = CrashSignature(crashSignature1Neg)

        instructionSig2 = CrashSignature(crashSignature2)
        instructionSig2Neg = CrashSignature(crashSignature2Neg)

        instructionSig3 = CrashSignature(crashSignature3)
        instructionSig3Neg = CrashSignature(crashSignature3Neg)

        crashInfo2 = CrashInfo.fromRawCrashData(
            [], [], config, auxCrashData=gdbSampleTrace2.splitlines())
        crashInfo3 = CrashInfo.fromRawCrashData(
            [], [], config, auxCrashData=gdbSampleTrace3.splitlines())

        self.assertIsInstance(crashInfo2, GDBCrashInfo)
        self.assertIsInstance(crashInfo3, GDBCrashInfo)

        self.assert_(instructionSig1.matches(crashInfo2))
        self.assertFalse(instructionSig1Neg.matches(crashInfo2))

        self.assert_(instructionSig2.matches(crashInfo2))
        self.assertFalse(instructionSig2Neg.matches(crashInfo2))

        self.assert_(instructionSig3.matches(crashInfo2))
        self.assertFalse(instructionSig3Neg.matches(crashInfo2))

        # Crash info3 doesn't have register information, ensure we don't match any
        self.assertFalse(instructionSig1.matches(crashInfo3))
        self.assertFalse(instructionSig2.matches(crashInfo3))
        self.assertFalse(instructionSig3.matches(crashInfo3))
Пример #24
0
def test_SignatureStackFramesTest():
    config = ProgramConfiguration("test", "x86", "linux")

    crashInfo = CrashInfo.fromRawCrashData(
        [], [], config, auxCrashData=testTrace1.splitlines())

    testSig1 = CrashSignature(testSignatureStackFrames1)
    testSig2 = CrashSignature(testSignatureStackFrames2)
    testSig3 = CrashSignature(testSignatureStackFrames3)
    testSig4 = CrashSignature(testSignatureStackFrames4)
    testSig5 = CrashSignature(testSignatureStackFrames5)

    assert testSig1.matches(crashInfo)
    assert testSig2.matches(crashInfo)
    assert testSig3.matches(crashInfo)
    assert testSig4.matches(crashInfo)
    assert not testSig5.matches(crashInfo)
Пример #25
0
def test_SignatureTestCaseMatchTest():
    config = ProgramConfiguration("test", "x86", "linux")

    crashInfo = CrashInfo.fromRawCrashData(
        [], [], config, auxCrashData=testTrace1.splitlines())

    testSig3 = CrashSignature(testSignature3)
    testSig4 = CrashSignature(testSignature4)
    testSig5 = CrashSignature(testSignature5)
    testSig6 = CrashSignature(testSignature6)

    assert not testSig3.matchRequiresTest()
    assert testSig4.matchRequiresTest()
    assert testSig5.matchRequiresTest()

    # Must not match without testcase provided
    assert not testSig4.matches(crashInfo)
    assert not testSig5.matches(crashInfo)
    assert not testSig6.matches(crashInfo)

    # Attach testcase
    crashInfo.testcase = testCase1

    # Must match with testcase provided
    assert testSig4.matches(crashInfo)
    assert testSig5.matches(crashInfo)

    # This one does not match at all
    assert not testSig6.matches(crashInfo)
Пример #26
0
    def runTest(self):
        config = ProgramConfiguration("test", "x86-64", "linux")

        crashSignature1 = '{ "symptoms" : [ { "type" : "stackFrame", "functionName" : "internalAppend" } ] }'
        crashSignature1Neg = '{ "symptoms" : [ { "type" : "stackFrame", "functionName" : "foobar" } ] }'

        crashSignature2 = '{ "symptoms" : [ { "type" : "stackFrame", "functionName" : "js::ion::MBasicBlock::setBackedge", "frameNumber" : "<= 4" } ] }'
        crashSignature2Neg = '{ "symptoms" : [ { "type" : "stackFrame", "functionName" : "js::ion::MBasicBlock::setBackedge", "frameNumber" : "> 4" } ] }'

        stackFrameSig1 = CrashSignature(crashSignature1)
        stackFrameSig1Neg = CrashSignature(crashSignature1Neg)

        stackFrameSig2 = CrashSignature(crashSignature2)
        stackFrameSig2Neg = CrashSignature(crashSignature2Neg)

        crashInfo1 = CrashInfo.fromRawCrashData(
            [], [], config, auxCrashData=gdbSampleTrace1.splitlines())

        self.assertIsInstance(crashInfo1, GDBCrashInfo)

        self.assert_(stackFrameSig1.matches(crashInfo1))
        self.assertFalse(stackFrameSig1Neg.matches(crashInfo1))

        self.assert_(stackFrameSig2.matches(crashInfo1))
        self.assertFalse(stackFrameSig2Neg.matches(crashInfo1))
Пример #27
0
 def runTest(self):
     config = ProgramConfiguration("test", "x86-64", "linux")
     
     crashSignature1 = '{ "symptoms" : [ { "type" : "instruction", "registerNames" : ["r14"] } ] }'
     crashSignature1Neg = '{ "symptoms" : [ { "type" : "instruction", "registerNames" : ["r14", "rax"] } ] }'
     crashSignature2 = '{ "symptoms" : [ { "type" : "instruction", "instructionName" : "mov" } ] }'
     crashSignature2Neg = '{ "symptoms" : [ { "type" : "instruction", "instructionName" : "cmp" } ] }'
     crashSignature3 = '{ "symptoms" : [ { "type" : "instruction", "instructionName" : "mov", "registerNames" : ["r14", "rbx"] } ] }'
     crashSignature3Neg = '{ "symptoms" : [ { "type" : "instruction", "instructionName" : "mov", "registerNames" : ["r14", "rax"] } ] }'
     
     instructionSig1 = CrashSignature(crashSignature1)
     instructionSig1Neg = CrashSignature(crashSignature1Neg)
     
     instructionSig2 = CrashSignature(crashSignature2)
     instructionSig2Neg = CrashSignature(crashSignature2Neg)
     
     instructionSig3 = CrashSignature(crashSignature3)
     instructionSig3Neg = CrashSignature(crashSignature3Neg)
     
     crashInfo2 = CrashInfo.fromRawCrashData([], [], config, auxCrashData=gdbSampleTrace2.splitlines())
     crashInfo3 = CrashInfo.fromRawCrashData([], [], config, auxCrashData=gdbSampleTrace3.splitlines())
     
     self.assertIsInstance(crashInfo2, GDBCrashInfo)
     self.assertIsInstance(crashInfo3, GDBCrashInfo)
     
     self.assert_(instructionSig1.matches(crashInfo2))
     self.assertFalse(instructionSig1Neg.matches(crashInfo2))
     
     self.assert_(instructionSig2.matches(crashInfo2))
     self.assertFalse(instructionSig2Neg.matches(crashInfo2))
     
     self.assert_(instructionSig3.matches(crashInfo2))
     self.assertFalse(instructionSig3Neg.matches(crashInfo2))
     
     # Crash info3 doesn't have register information, ensure we don't match any
     self.assertFalse(instructionSig1.matches(crashInfo3))
     self.assertFalse(instructionSig2.matches(crashInfo3))
     self.assertFalse(instructionSig3.matches(crashInfo3))
Пример #28
0
    def runTest(self):
        config = ProgramConfiguration("test", "x86-64", "linux")

        crashSignature1 = '{ "symptoms" : [ { "type" : "stackSize", "size" : 8 } ] }'
        crashSignature1Neg = '{ "symptoms" : [ { "type" : "stackSize", "size" : 9 } ] }'

        crashSignature2 = '{ "symptoms" : [ { "type" : "stackSize", "size" : "< 10" } ] }'
        crashSignature2Neg = '{ "symptoms" : [ { "type" : "stackSize", "size" : "> 10" } ] }'

        stackSizeSig1 = CrashSignature(crashSignature1)
        stackSizeSig1Neg = CrashSignature(crashSignature1Neg)

        stackSizeSig2 = CrashSignature(crashSignature2)
        stackSizeSig2Neg = CrashSignature(crashSignature2Neg)

        crashInfo1 = CrashInfo.fromRawCrashData(
            [], [], config, auxCrashData=gdbSampleTrace1.splitlines())

        self.assertIsInstance(crashInfo1, GDBCrashInfo)

        self.assert_(stackSizeSig1.matches(crashInfo1))
        self.assertFalse(stackSizeSig1Neg.matches(crashInfo1))

        self.assert_(stackSizeSig2.matches(crashInfo1))
        self.assertFalse(stackSizeSig2Neg.matches(crashInfo1))
Пример #29
0
 def runTest(self):
     config = ProgramConfiguration('test', 'x86-64', 'linux')
     crashInfo = CrashInfo.fromRawCrashData(["(«f => (generator.throw(f))», «undefined»)"], [], config)
     testSignature = CrashSignature('{"symptoms": [{"src": "stdout", "type": "output", "value": "x"}]}')
     self.assertFalse(testSignature.matches(crashInfo))
Пример #30
0
    def runTest(self):
        config = ProgramConfiguration("test", "x86", "linux")

        crashInfo = CrashInfo.fromRawCrashData([], [], config, auxCrashData=testTrace1.splitlines())

        testSig3 = CrashSignature(testSignature3)
        testSig4 = CrashSignature(testSignature4)
        testSig5 = CrashSignature(testSignature5)
        testSig6 = CrashSignature(testSignature6)

        self.assertFalse(testSig3.matchRequiresTest())
        self.assertTrue(testSig4.matchRequiresTest())
        self.assertTrue(testSig5.matchRequiresTest())

        # Must not match without testcase provided
        self.assertFalse(testSig4.matches(crashInfo))
        self.assertFalse(testSig5.matches(crashInfo))
        self.assertFalse(testSig6.matches(crashInfo))

        # Attach testcase
        crashInfo.testcase = testCase1

        # Must match with testcase provided
        self.assertTrue(testSig4.matches(crashInfo))
        self.assertTrue(testSig5.matches(crashInfo))

        # This one does not match at all
        self.assertFalse(testSig6.matches(crashInfo))