def handle_socketcall(syscall_id, syscall_object, entering, pid): """ <Purpose> Validate the subcall (NOT SYSCALL!) id of the socket subcall against the subcall name we expect based on the current system call object. Then, hand off responsibility to the appropriate subcall handler. <Returns> None """ subcall_handlers = { ('socket', True): socket_handlers.socket_entry_handler, #('socket', False): socket_exit_handler, ('accept', True): socket_handlers.accept_subcall_entry_handler, ('accept4', True): socket_handlers.accept_subcall_entry_handler, #('accept', False): accept_subcall_entry_handler, ('bind', True): socket_handlers.bind_entry_handler, #('bind', False): bind_exit_handler, ('listen', True): socket_handlers.listen_entry_handler, #('listen', False): listen_exit_handler, ('recv', True): recv_handlers.recv_subcall_entry_handler, #('recvfrom', True): recvfrom_subcall_entry_handler, ('setsockopt', True): socket_handlers.setsockopt_entry_handler, ('send', True): send_handlers.send_entry_handler, #('send', False): send_exit_handler, ('connect', True): socket_handlers.connect_entry_handler, #('connect', False): connect_exit_handler, ('getsockopt', True): socket_handlers.getsockopt_entry_handler, ## ('sendmmsg', True): sendmmsg_entry_handler, #('sendto', True): sendto_entry_handler, #('sendto', False): sendto_exit_handler, ('shutdown', True): socket_handlers.shutdown_subcall_entry_handler, #('recvmsg', True): recvmsg_entry_handler, #('recvmsg', False): recvmsg_exit_handler, ('getsockname', True): socket_handlers.getsockname_entry_handler, ('getpeername', True): socket_handlers.getpeername_entry_handler } # The subcall id of the socket subcall is located in the EBX register # according to our Linux's convention. subcall_id = syscallreplay.peek_register(pid, syscallreplay.EBX) util.validate_subcall(subcall_id, syscall_object) try: subcall_handlers[(syscall_object.name, entering)](syscall_id, syscall_object, pid) except KeyError: raise NotImplementedError('No handler for socket subcall %s %s', syscall_object.name, 'entry' if entering else 'exit')
def main(): # initialize parser parser = argparse.ArgumentParser() parser.add_argument('config', metavar='config', nargs=1, type=str, help="path to configuration file") parser.add_argument('-v', '--verbosity', dest='loglevel', type=int, default=40, help='flag for displaying debug information') # parser arguments args = parser.parse_args() # Add simple logging for verbosity logger.setLevel(level=args.loglevel) if int(args.loglevel) == 10: syscallreplay.enable_debug_output(10) # Sets up syscallreplay.injected_state['config'] config = "".join(args.config) consume_configuration(config) # Configure various locals from the config section of our injected state config_dict = syscallreplay.injected_state pid = int(config_dict['pid']) rec_pid = config_dict['rec_pid'] event_number = config_dict['event'] apply_mmap_backing_files() # create trace object pickle_file = consts.DEFAULT_CONFIG_PATH + "syscall_definitions.pickle" trace = Trace.Trace(config_dict['trace_file'], pickle_file) syscallreplay.syscalls = trace.syscalls syscallreplay.syscall_index = int(config_dict['trace_start']) syscallreplay.syscall_index_end = int(config_dict['trace_end']) # Set up checker and mutator checker = None mutator = None # pylint: disable=eval-used if 'checker' in syscallreplay.injected_state: checker = eval(syscallreplay.injected_state['checker']) if 'mutator' in syscallreplay.injected_state: mutator = eval(syscallreplay.injected_state['mutator']) mutator.mutate_syscalls(syscallreplay.syscalls) # pylint: enable=eval-used # Requires kernel.yama.ptrace_scope = 0 # in /etc/sysctl.d/10-ptrace.conf # on modern Ubuntu logger.debug('Injecting %d', pid) syscallreplay.attach(pid) _, status = os.waitpid(pid, 0) logger.debug('Attached %d', pid) logger.debug('Requesting stop at next system call entry using SIGCONT') syscallreplay.syscall(pid, signal.SIGCONT) _, status = os.waitpid(pid, 0) # We need an additional call to PTRACE_SYSCALL here in order to skip # past an rr syscall buffering related injected system call logger.debug('Second sigcont %d', pid) syscallreplay.syscall(pid, 0) _, status = os.waitpid(pid, 0) # main system call handling loop logger.debug('Entering system call handling loop') syscallreplay.entering_syscall = True while not os.WIFEXITED(status): syscall_object = syscallreplay.syscalls[syscallreplay.syscall_index] try: syscall_id = syscallreplay.peek_register(pid, syscallreplay.ORIG_EAX) debug_handle_syscall(pid, syscall_id, syscall_object, syscallreplay.entering_syscall) except: exit_with_status(pid, 1, str(mutator), event_number, syscallreplay.syscall_index) # call transition() if checker is implemented if checker: checker.transition(syscall_object) # incremenent syscall_index if not entering if not syscallreplay.entering_syscall: syscallreplay.syscall_index += 1 syscallreplay.entering_syscall = not syscallreplay.entering_syscall syscallreplay.syscall(pid, 0) _, status = os.waitpid(pid, 0) if syscallreplay.syscall_index == syscallreplay.syscall_index_end: if checker: print('#### Checker Status ####') if checker.is_accepting(): print('{} accepted'.format(checker)) else: print('{} not accepted'.format(checker)) print('#### End Checker Status ####') exit_with_status(pid, 0, str(mutator), event_number)