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_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())
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)
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())
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
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_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 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