Example #1
0
    def test_equal(self):
        # Arrange
        cflow_line = 'getchar()'
        test_call_1 = Call.from_cflow(cflow_line)
        test_call_2 = Call.from_cflow(cflow_line)

        # Assert
        self.assertEqual(test_call_1, test_call_2)
    def test_equal(self):
        # Arrange
        cflow_line = 'getchar()'
        test_call_1 = Call.from_cflow(cflow_line)
        test_call_2 = Call.from_cflow(cflow_line)

        # Assert
        self.assertEqual(test_call_1, test_call_2)
Example #3
0
    def test_not_equal(self):
        # Arrange
        cflow_line_1 = 'getchar()'
        cflow_line_2 = (
            'xstrdup() <char *xstrdup (const char *str) at ./cyrus/lib/xmalloc'
            '.c:89> (R):')
        test_call_1 = Call.from_cflow(cflow_line_1)
        test_call_2 = Call.from_cflow(cflow_line_2)

        # Assert
        self.assertNotEqual(test_call_1, test_call_2)
    def test_not_equal(self):
        # Arrange
        cflow_line_1 = 'getchar()'
        cflow_line_2 = (
            'xstrdup() <char *xstrdup (const char *str) at ./cyrus/lib/xmalloc'
            '.c:89> (R):'
        )
        test_call_1 = Call.from_cflow(cflow_line_1)
        test_call_2 = Call.from_cflow(cflow_line_2)

        # Assert
        self.assertNotEqual(test_call_1, test_call_2)
    def test_is_output(self):
        # Arrange
        cflow_line = 'printf()'
        test_call = Call.from_cflow(cflow_line)

        # Assert
        self.assertTrue(test_call.is_output())
Example #6
0
    def test_function_signature_only_name(self):
        # Arrange
        cflow_line = 'printf()'
        test_call = Call.from_cflow(cflow_line)

        # Assert
        self.assertEqual('', test_call.function_signature)
    def test_is_not_input(self):
        # Arrange
        cflow_line = 'printf()'
        test_call = Call.from_cflow(cflow_line)

        # Assert
        self.assertFalse(test_call.is_input())
    def test_is_input(self):
        # Arrange
        cflow_line = 'getchar()'
        test_call = Call.from_cflow(cflow_line)

        # Assert
        self.assertTrue(test_call.is_input())
    def test_identity_function_name(self):
        # Arrange
        cflow_line = 'printf()'
        test_call = Call.from_cflow(cflow_line)

        # Assert
        self.assertEqual('printf', test_call.identity)
Example #10
0
    def test_is_input(self):
        # Arrange
        cflow_line = 'getchar()'
        test_call = Call.from_cflow(cflow_line)

        # Assert
        self.assertTrue(test_call.is_input())
Example #11
0
    def test_is_not_input(self):
        # Arrange
        cflow_line = 'printf()'
        test_call = Call.from_cflow(cflow_line)

        # Assert
        self.assertFalse(test_call.is_input())
    def test_in_stdlib(self):
        # Arrange
        cflow_line = 'printf()'
        test_call = Call.from_cflow(cflow_line)

        # Assert
        self.assertTrue(test_call.in_stdlib())
    def test_identity_function_name_file_granularity(self):
        # Arrange
        cflow_line = 'printf()'
        test_call = Call.from_cflow(cflow_line, granularity=Granularity.FILE)

        # Assert
        self.assertEqual('', test_call.identity)
    def test_is_not_output(self):
        # Arrange
        cflow_line = 'getchar()'
        test_call = Call.from_cflow(cflow_line)

        # Assert
        self.assertFalse(test_call.is_output())
Example #15
0
    def test_is_output(self):
        # Arrange
        cflow_line = 'printf()'
        test_call = Call.from_cflow(cflow_line)

        # Assert
        self.assertTrue(test_call.is_output())
    def test_function_signature_only_name(self):
        # Arrange
        cflow_line = 'printf()'
        test_call = Call.from_cflow(cflow_line)

        # Assert
        self.assertEqual('', test_call.function_signature)
Example #17
0
    def test_is_not_output(self):
        # Arrange
        cflow_line = 'getchar()'
        test_call = Call.from_cflow(cflow_line)

        # Assert
        self.assertFalse(test_call.is_output())
Example #18
0
    def test_identity_function_name(self):
        # Arrange
        cflow_line = 'printf()'
        test_call = Call.from_cflow(cflow_line)

        # Assert
        self.assertEqual('printf', test_call.identity)
    def load_call_graph(self):
        """
            Generates the Call Graph as a networkx.DiGraph object.

            Invokes the call grap generation software (cflow) and creates a networkx.DiGraph instance that represents
            the analyzed source code's Call Graph.

            Args:
                is_reverse: Boolean specifying whether the graph generation software (cflow) should use the reverse
                    algorithm.

            Returns:
                None
        """
        call_graph = nx.DiGraph()
        is_first_line = True
        parent = Stack()

        if os.path.isfile(self.source):
            raw_call_graph = open(self.source)
            readline = lambda: raw_call_graph.readline()

        elif os.path.isdir(self.source):
            raw_call_graph = self._exec_cflow(self.is_reverse)
            readline = lambda: raw_call_graph.stdout.readline().decode(encoding='UTF-8')

        while True:
            line = readline()

            if line == '':
                break

            current = Call.from_cflow(line)

            if not is_first_line:
                if current.level > previous.level:
                    parent.push(previous)
                elif current.level < previous.level:
                    for t in range(previous.level - current.level):
                        parent.pop()

                if parent.top:
                    call_graph.add_node(current, {'tested': False})
                    call_graph.add_node(parent.top, {'tested': False})

                    # Edge weight can be any arbitrary number greater than 
                    #   that used as the weight for the edges in the gprof 
                    #   call graph.

                    if not self.is_reverse:
                        call_graph.add_edge(parent.top, current, 
                            {'cflow': 'cflow'}, weight=1)
                    else:
                        call_graph.add_edge(current, parent.top, 
                            {'cflow': 'cflow'}, weight=1)

            previous = current
            is_first_line = False

        return call_graph
Example #20
0
    def test_identity_function_name_file_granularity(self):
        # Arrange
        cflow_line = 'printf()'
        test_call = Call.from_cflow(cflow_line, granularity=Granularity.FILE)

        # Assert
        self.assertEqual('', test_call.identity)
Example #21
0
    def test_in_stdlib(self):
        # Arrange
        cflow_line = 'printf()'
        test_call = Call.from_cflow(cflow_line)

        # Assert
        self.assertTrue(test_call.in_stdlib())
Example #22
0
    def test_identity_full(self):
        # Arrange
        cflow_line = (
            'xstrdup() <char *xstrdup (const char *str) at ./cyrus/lib/xmalloc'
            '.c:89> (R):')
        test_call = Call.from_cflow(cflow_line)

        # Assert
        self.assertEqual('xstrdup ./cyrus/lib/xmalloc.c', test_call.identity)
Example #23
0
    def test_identity_full_file_granularity(self):
        # Arrange
        cflow_line = (
            'xstrdup() <char *xstrdup (const char *str) at ./cyrus/lib/xmalloc'
            '.c:89> (R):')
        test_call = Call.from_cflow(cflow_line, granularity=Granularity.FILE)

        # Assert
        self.assertEqual('./cyrus/lib/xmalloc.c', test_call.identity)
Example #24
0
    def test_is_not_input_no_leaf(self):
        # Arrange
        cflow_line = (
            'xstrdup() <char *xstrdup (const char *str) at ./cyrus/lib/xmalloc'
            '.c:89> (R):')
        test_call = Call.from_cflow(cflow_line)

        # Assert
        self.assertFalse(test_call.is_input())
Example #25
0
    def test_function_signature_full(self):
        # Arrange
        cflow_line = (
            'xstrdup() <char *xstrdup (const char *str) at ./cyrus/lib/xmalloc'
            '.c:89> (R):')
        test_call = Call.from_cflow(cflow_line)

        # Assert
        self.assertEqual('./cyrus/lib/xmalloc.c', test_call.function_signature)
    def test_identity_full(self):
        # Arrange
        cflow_line = (
            'xstrdup() <char *xstrdup (const char *str) at ./cyrus/lib/xmalloc'
            '.c:89> (R):'
        )
        test_call = Call.from_cflow(cflow_line)

        # Assert
        self.assertEqual('xstrdup ./cyrus/lib/xmalloc.c', test_call.identity)
    def test_identity_full_file_granularity(self):
        # Arrange
        cflow_line = (
            'xstrdup() <char *xstrdup (const char *str) at ./cyrus/lib/xmalloc'
            '.c:89> (R):'
        )
        test_call = Call.from_cflow(cflow_line, granularity=Granularity.FILE)

        # Assert
        self.assertEqual('./cyrus/lib/xmalloc.c', test_call.identity)
    def test_function_signature_full(self):
        # Arrange
        cflow_line = (
            'xstrdup() <char *xstrdup (const char *str) at ./cyrus/lib/xmalloc'
            '.c:89> (R):'
        )
        test_call = Call.from_cflow(cflow_line)

        # Assert
        self.assertEqual('./cyrus/lib/xmalloc.c', test_call.function_signature)
    def test_is_not_input_no_leaf(self):
        # Arrange
        cflow_line = (
            'xstrdup() <char *xstrdup (const char *str) at ./cyrus/lib/xmalloc'
            '.c:89> (R):'
        )
        test_call = Call.from_cflow(cflow_line)

        # Assert
        self.assertFalse(test_call.is_input())
    def load_call_graph(self, granularity=Granularity.FUNC):
        """Load a call graph generated by cflow.

        If necessary, the static call graph generation utility (cflow) is
        invoked to generate the call graph before attempting to load it.

        Parameters
        ----------
        granularity : str
            The granularity at which the call graph must be loaded. See
            attacksurfacemeter.granularity.Granularity for available choices.

        Returns
        -------
        call_graph : networkx.DiGraph
            An object representing the call graph.
        """
        call_graph = nx.DiGraph()
        parent = Stack()

        raw_call_graph = None
        if os.path.isfile(self.source):
            raw_call_graph = open(self.source)
        elif os.path.isdir(self.source):
            raw_call_graph = self._exec_cflow()

        try:
            previous = Call.from_cflow(raw_call_graph.readline(), granularity)
            for line in raw_call_graph:
                current = Call.from_cflow(line, granularity)

                if current.level > previous.level:
                    parent.push(previous)
                elif current.level < previous.level:
                    for t in range(previous.level - current.level):
                        parent.pop()

                if parent.top:
                    caller = callee = None
                    entry = exit = dangerous = defense = False
                    if self.is_reverse:
                        caller = current
                        callee = parent.top
                    else:
                        caller = parent.top
                        callee = current

                    (caller_attrs, callee_attrs) = utilities.get_node_attrs(
                        'cflow', caller, callee, self.defenses,
                        self.vulnerabilities
                    )

                    call_graph.add_node(caller, caller_attrs)

                    if callee_attrs is not None:
                        call_graph.add_node(callee, callee_attrs)

                        # Adding the edge caller --  callee
                        attrs = {'cflow': None, 'call': None}
                        call_graph.add_edge(caller, callee, attrs)

                        # Adding the edge callee -- caller with the assumption
                        #   that every call must return
                        attrs = {'cflow': None, 'return': None}
                        call_graph.add_edge(callee, caller, attrs)

                previous = current
        finally:
            if raw_call_graph:
                raw_call_graph.close()

        return call_graph