### BEGIN LICENSE ###
### Use of the triage tools and related source code is subject to the terms
### of the license below.
###
### ------------------------------------------------------------------------
### Copyright (C) 2011 Carnegie Mellon University. All Rights Reserved.
### Portions Copyright 2013 BlackBerry Ltd. All Rights Reserved.
### ------------------------------------------------------------------------
### Redistribution and use in source and binary forms, with or without
### modification, are permitted provided that the following conditions are
### met:
###
### 1. Redistributions of source code must retain the above copyright
###    notice, this list of conditions and the following acknowledgments
###    and disclaimers.
###
### 2. Redistributions in binary form must reproduce the above copyright
###    notice, this list of conditions and the following disclaimer in the
###    documentation and/or other materials provided with the distribution.
###
### 3. All advertising materials for third-party software mentioning
###    features or use of this software must display the following
###    disclaimer:
###
###    "Neither Carnegie Mellon University nor its Software Engineering
###     Institute have reviewed or endorsed this software"
###
### 4. The names "Department of Homeland Security," "Carnegie Mellon
###    University," "CERT" and/or "Software Engineering Institute" shall
###    not be used to endorse or promote products derived from this software
###    without prior written permission. For written permission, please
###    contact permission@sei.cmu.edu.
###
### 5. Products derived from this software may not be called "CERT" nor
###    may "CERT" appear in their names without prior written permission of
###    permission@sei.cmu.edu.
###
### 6. Redistributions of any form whatsoever must retain the following
###    acknowledgment:
###
###    "This product includes software developed by CERT with funding
###     and support from the Department of Homeland Security under
###     Contract No. FA 8721-05-C-0003."
###
### THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND
### CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER
### EXPRESS OR IMPLIED, AS TO ANY MATTER, AND ALL SUCH WARRANTIES, INCLUDING
### WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE
### EXPRESSLY DISCLAIMED. WITHOUT LIMITING THE GENERALITY OF THE FOREGOING,
### CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND
### RELATING TO EXCLUSIVITY, INFORMATIONAL CONTENT, ERROR-FREE OPERATION,
### RESULTS TO BE OBTAINED FROM USE, FREEDOM FROM PATENT, TRADEMARK AND
### COPYRIGHT INFRINGEMENT AND/OR FREEDOM FROM THEFT OF TRADE SECRETS.
### END LICENSE ###
'''
Contains analyzers used to match rules that are used to classify the state
of an "ASAN" Linux GDB inferior and some helper functions.

NOTE: This logic is used in a workflow by a specific user and has not been
tested by the maintainer. 
'''

import re
import signal

from lib.tools import memoized


class ASanAnalyzer(object):

    def __init__(self, target):
        self.target = target

    # EXPLOITABLE matching methods follow

    @memoized
    def isBranchAvNotNearNull(self):
        return False

    @memoized
    def isReturnAv(self):
        return False

    @memoized
    def isSegFaultOnPcNotNearNull(self):
        return False

    @memoized
    def isErrorWhileExecutingFromStack(self):
        return False

    @memoized
    def isStackBufferOverflow(self):
        asan_stack_errs = ["stack-buffer-overflow", "stack-buffer-underflow", "stack-use-after-return",
                           "stack-use-after-scope", "dynamic-stack-buffer-overflow"]
        return self.target.asan_reason in asan_stack_errs

    @memoized
    def isPossibleStackCorruption(self):
        return False

    @memoized
    def isDestAvNotNearNull(self):
        return False

    @memoized
    def isHeapError(self):
        asan_heap_errs = ["double-free", "bad-free", "alloc-dealloc-mismatch", "unknown-crash",
                            "heap-buffer-overflow", "heap-use-after-free", "global-buffer-overflow",
                          "use-after-poison", "container-overflow", "intra-object-overflow"]
        return self.target.asan_reason in asan_heap_errs

    # PROBABLY_EXPLOITABLE matching methods follow

    @memoized
    def isStackOverflow(self):
        return False

    @memoized
    def isMalformedInstructionSignal(self):
        return False

    @memoized
    def isSegFaultOnPcNearNull(self):
        return False

    @memoized
    def isBranchAvNearNull(self):
        return False

    _re_blk_mov = re.compile("^rep.*mov")

    @memoized
    def isBlockMove(self):
        return False

    @memoized
    def isDestAvNearNull(self):
        return False

    # PROBABLY_NOT_EXPLOITABLE matching methods follow

    @memoized
    def isBenignSignal(self):
        return False

    @memoized
    def isSourceAvNotNearNull(self):
        return False

    @memoized
    def isFloatingPointException(self):
        return self.target.asan_reason == "FPE"

    # UNKNOWN matching methods follow

    @memoized
    def isSourceAvNearNull(self):
        return False

    @memoized
    def isAbortSignal(self):
        return self.target.asan_reason == "ABRT"

    @memoized
    def isAccessViolationSignal(self):
        return self.isSignalInList(["SEGV", "BUS"])

    @memoized
    def isUncategorizedSignal(self):
        return self.target.asan_reason in ["UNKNOWN", "NOTRACE"]

    '''
    Helpers
    The following functions are called by multiple analyzers and are not 
    directly associated with a rule.
    '''

    @memoized
    def isOnSignal(self):
        return self.target.asan_reason in ["ABRT", "SEGV", "ILL", "FPE", "BUS"]

    @memoized
    def isSignalInList(self, siglist):
        if not self.isOnSignal():
            return False
        return self.target.asan_reason in siglist

    def isNearNull(self, addr):
        return False

    @memoized
    def isInBacktrace(self, fnames, region=None):
        return False

    @memoized
    def isFaNearNull(self):
        return False

    @memoized
    def isBenign(self):
        return False

    @memoized
    def isJumpInstruction(self):
        return False

    @memoized
    def isBranchAv(self):
        return False

    @memoized
    def faultingAddress(self):
        if self.isJumpInstruction():
            # si_addr does not always contain a valid faulting address, but
            # jump instructions always access the dest op and GDB always displays
            # the absolute addr, so we can use the dest op instead of si_addr here.
            return self.target.current_instruction().operands[0].eval()
        return self.target.si_addr()

    @memoized
    def isSegFaultOnPc(self):
        return False

    @memoized
    def isDestAv(self):
        return self.target.asan_operation == "WRITE"

    @memoized
    def isSourceAv(self):
        return self.target.asan_operation == "READ"

    @memoized
    def isUseAfterFree(self):
        return self.target.asan_reason == "heap-use-after-free"

