def main(): ''' Once the socket is bound the client is handled in another thread to allow for asynchronous input ''' print "Press ctrl-c to stop server..." listener_socket = SocketWrapper() #Serving local clients only for efficiancy purposes try: listener_socket.port_number = int(sys.argv[1]) except: print "Usage: mudserver.py PORT" sys.exit(1) #change hostname to inet address of computer the server is run on listener_socket.host_name = '' listener_socket.queue_size = 2 listener_socket.buffer_size = 4096 listener_socket.startListening() while 1: communication_socket = \ SocketWrapper("<<EOC", listener_socket.awaitConnection()) thread.start_new_thread(threadHandler, (communication_socket,)) listener_socket.closeConnection()
def __init__(self, conf): self.conf = conf self.queue = Queue() if self.conf.online: settings = configparser.RawConfigParser() settings.read('settings.conf') interface = settings.get("Datasets", "stream_interface") ip_address = get_ip_address(interface) addr_tuple = (ip_address, 3885) self.server = SocketWrapper( socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM), addr_tuple, self._cb_server) self.server.start() print("Listening for sample streams at %s" % str(addr_tuple))
def __init__(self, loop): self.loop = loop self.loop.add_coroutine(self.run_server_forever()) # create socket s = socket.socket() s.bind(("127.0.0.1", 8999)) s.listen() self.listen_socket = SocketWrapper(s, loop)
def connect(self): self.server_socket.settimeout(5.0) try: sock, addr = self.server_socket.accept() except socket.timeout: logging.error("Aislinn client was not started") return False self.socket = SocketWrapper(sock) self.socket.set_no_delay() self.server_socket.close() self.server_socket = None return True
class StreamServer(): def __init__(self, conf): self.conf = conf self.queue = Queue() if self.conf.online: settings = configparser.RawConfigParser() settings.read('settings.conf') interface = settings.get("Datasets", "stream_interface") ip_address = get_ip_address(interface) addr_tuple = (ip_address, 3885) self.server = SocketWrapper( socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM), addr_tuple, self._cb_server) self.server.start() print("Listening for sample streams at %s" % str(addr_tuple)) def _cb_server(self, client_socket, client_address, data): if len(data) < 5: # Not enough for TLV return 0 else: pkt_type, payload_len = struct.unpack(">BI", data[0:5]) payload = data[5:] if len(payload) < payload_len: return 0 # Not enough for payload else: # Depickle and add to queue # TODO: Check for correctness. EMcap is Python2 (because it needs to) # use GNU Radio. Therefore the pickling format is different, which # we need to make sure doesn't cause any differences. trace_set = pickle.loads(payload, encoding='latin1', fix_imports=True) logger.debug("Stream: got %d traces" % len(trace_set.traces)) self.queue.put(trace_set) return payload_len + 5
if __name__ == '__main__': app = QApplication(sys.argv) main_window = QWidget() main_window.setWindowTitle('lab 1 task 4') main_window.setLayout(QVBoxLayout()) server_ip = IPWidget("Server IP:", main_window) receiver_ip = IPWidget("Receiver IP:", main_window) instance_panel = QWidget() instance_panel.setLayout(QHBoxLayout()) port_field = QLineEdit() server_socket = SocketWrapper(server_ip, receiver_ip, port_field) server_socket.start() conn_panel = QWidget() conn_panel.setLayout(QHBoxLayout()) conn_btn = QPushButton("Connect") conn_btn.clicked.connect(server_socket.sock_init) disconnect_btn = QPushButton("Disconnect") disconnect_btn.clicked.connect(server_socket.close) user_list_btn = QPushButton("User list") user_list_btn.clicked.connect(lambda x: server_socket.msg_send("", True)) status_label = QLabel("not connected")
def process_ctrl_packet(self, pkt_type, payload): if pkt_type == CtrlPacketType.SIGNAL_START: logger.debug("Starting for payload: %s" % binary_to_hex(payload)) self.parse_ies(payload) self.sdr.start() # Spinlock until data timeout = 3 current_time = 0.0 while len(self.stored_data) <= self.wait_num_chunks: sleep(0.0001) current_time += 0.0001 if current_time >= timeout: logger.warning("Timeout while waiting for data. Did the SDR crash? Reinstantiating...") del self.sdr self.data_socket.socket.close() self.data_socket = SocketWrapper(socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM), ('127.0.0.1', 3884), self.cb_data) self.data_socket.start() self.sdr = SDR(**self.cap_kwargs) self.process_ctrl_packet(pkt_type, payload) elif pkt_type == CtrlPacketType.SIGNAL_END: # self.sdr.sdr_source.stop() self.sdr.stop() self.sdr.wait() logger.debug("Stopped after receiving %d chunks" % len(self.stored_data)) #sleep(0.5) #logger.debug("After sleep we have %d chunks" % len(self.stored_data)) # Successful capture (no errors or timeouts) if len(self.stored_data) > 0: # We have more than 1 chunk # Data to file np_data = np.fromstring(b"".join(self.stored_data), dtype=np.complex64) self.trace_set.append(np_data) self.plaintexts.append(self.stored_plaintext) self.keys.append(self.stored_key) if len(self.trace_set) >= self.kwargs['traces_per_set']: assert(len(self.trace_set) == len(self.plaintexts)) assert(len(self.trace_set) == len(self.keys)) np_trace_set = np.array(self.trace_set) np_plaintexts = np.array(self.plaintexts, dtype=np.uint8) np_keys = np.array(self.keys, dtype=np.uint8) if not self.online is None: # Stream online ts = TraceSet(name="online %d" % self.online_counter, traces=np_trace_set, plaintexts=np_plaintexts, ciphertexts=None, keys=np_keys) logger.info("Pickling") ts_p = pickle.dumps(ts) logger.info("Size is %d" % len(ts_p)) stream_payload = ts_p stream_payload_len = len(stream_payload) logger.info("Streaming trace set of %d bytes to server" % stream_payload_len) stream_hdr = struct.pack(">BI", 0, stream_payload_len) self.emma_client.send(stream_hdr + stream_payload) self.online_counter += 1 else: # Save to disk if not self.kwargs['dry']: # Write metadata to sigmf file # if sigmf #with open(test_meta_path, 'w') as f: # test_sigmf = SigMFFile(data_file=test_data_path, global_info=copy.deepcopy(self.global_meta)) # test_sigmf.add_capture(0, metadata=capture_meta) # test_sigmf.dump(f, pretty=True) # elif chipwhisperer: logger.info("Dumping %d traces to file" % len(self.trace_set)) filename = str(datetime.utcnow()).replace(" ","_").replace(".","_") output_dir = self.kwargs['output_dir'] np.save(os.path.join(output_dir, "%s_traces.npy" % filename), np_trace_set) # TODO abstract this in trace_set class np.save(os.path.join(output_dir, "%s_textin.npy" % filename), np_plaintexts) np.save(os.path.join(output_dir, "%s_knownkey.npy" % filename), np_keys) if self.compress: logger.info("Calling emcap-compress...") subprocess.call(['/usr/bin/python', 'emcap-compress.py', os.path.join(output_dir, "%s_traces.npy" % filename)]) self.limit_counter += len(self.trace_set) if self.limit_counter >= self.limit: print("Done") exit(0) # Clear results self.trace_set = [] self.plaintexts = [] self.keys = [] # Clear self.stored_data = [] self.stored_plaintext = []
def __init__(self, cap_kwargs={}, kwargs={}, ctrl_socket_type=None): # Set up data socket self.data_socket = SocketWrapper(socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM), ('127.0.0.1', 3884), self.cb_data) self.online = kwargs['online'] # Set up sockets self.ctrl_socket_type = ctrl_socket_type if ctrl_socket_type == CtrlType.DOMAIN: unix_domain_socket = '/tmp/emma.socket' self.clear_domain_socket(unix_domain_socket) self.ctrl_socket = SocketWrapper(socket.socket(family=socket.AF_UNIX, type=socket.SOCK_STREAM), unix_domain_socket, self.cb_ctrl) elif ctrl_socket_type == CtrlType.UDP: self.ctrl_socket = SocketWrapper(socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM), ('172.18.15.21', 3884), self.cb_ctrl) elif ctrl_socket_type == CtrlType.SERIAL: self.ctrl_socket = TTYWrapper("/dev/ttyUSB0", self.cb_ctrl) else: logger.error("Unknown ctrl_socket_type") exit(1) if not self.online is None: try: self.emma_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.emma_client.connect((self.online, 3885)) except Exception as e: print(e) exit(1) self.sdr = SDR(**cap_kwargs) self.cap_kwargs = cap_kwargs self.kwargs = kwargs self.store = False self.stored_plaintext = [] self.stored_key = [] self.stored_data = [] self.trace_set = [] self.plaintexts = [] self.keys = [] self.online_counter = 0 self.limit_counter = 0 self.limit = kwargs['limit'] #self.manifest = kwargs['manifest'] self.compress = kwargs['compress'] if self.sdr.hw == 'usrp': self.wait_num_chunks = 0 else: self.wait_num_chunks = 50 # Bug in rtl-sdr? self.global_meta = { "core:datatype": "cf32_le", "core:version": "0.0.1", "core:license": "CC0", "core:hw": self.sdr.hw, "core:sample_rate": self.sdr.samp_rate, "core:author": "Pieter Robyns" } self.capture_meta = { "core:sample_start": 0, "core:frequency": self.sdr.freq, "core:datetime": str(datetime.utcnow()), }
class EMCap(): def __init__(self, cap_kwargs={}, kwargs={}, ctrl_socket_type=None): # Set up data socket self.data_socket = SocketWrapper(socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM), ('127.0.0.1', 3884), self.cb_data) self.online = kwargs['online'] # Set up sockets self.ctrl_socket_type = ctrl_socket_type if ctrl_socket_type == CtrlType.DOMAIN: unix_domain_socket = '/tmp/emma.socket' self.clear_domain_socket(unix_domain_socket) self.ctrl_socket = SocketWrapper(socket.socket(family=socket.AF_UNIX, type=socket.SOCK_STREAM), unix_domain_socket, self.cb_ctrl) elif ctrl_socket_type == CtrlType.UDP: self.ctrl_socket = SocketWrapper(socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM), ('172.18.15.21', 3884), self.cb_ctrl) elif ctrl_socket_type == CtrlType.SERIAL: self.ctrl_socket = TTYWrapper("/dev/ttyUSB0", self.cb_ctrl) else: logger.error("Unknown ctrl_socket_type") exit(1) if not self.online is None: try: self.emma_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.emma_client.connect((self.online, 3885)) except Exception as e: print(e) exit(1) self.sdr = SDR(**cap_kwargs) self.cap_kwargs = cap_kwargs self.kwargs = kwargs self.store = False self.stored_plaintext = [] self.stored_key = [] self.stored_data = [] self.trace_set = [] self.plaintexts = [] self.keys = [] self.online_counter = 0 self.limit_counter = 0 self.limit = kwargs['limit'] #self.manifest = kwargs['manifest'] self.compress = kwargs['compress'] if self.sdr.hw == 'usrp': self.wait_num_chunks = 0 else: self.wait_num_chunks = 50 # Bug in rtl-sdr? self.global_meta = { "core:datatype": "cf32_le", "core:version": "0.0.1", "core:license": "CC0", "core:hw": self.sdr.hw, "core:sample_rate": self.sdr.samp_rate, "core:author": "Pieter Robyns" } self.capture_meta = { "core:sample_start": 0, "core:frequency": self.sdr.freq, "core:datetime": str(datetime.utcnow()), } def clear_domain_socket(self, address): try: os.unlink(address) except OSError: if os.path.exists(address): raise def cb_timeout(self): logger.warning("Timeout on capture, skipping...") self.sdr.stop() def cb_data(self, client_socket, client_address, data): self.stored_data.append(data) return len(data) def cb_ctrl(self, client_socket, client_address, data): logger.log(logging.NOTSET, "Control packet: %s" % binary_to_hex(data)) if len(data) < 5: # Not enough for TLV return 0 else: pkt_type, payload_len = struct.unpack(">BI", data[0:5]) payload = data[5:] if len(payload) < payload_len: return 0 # Not enough for payload else: self.process_ctrl_packet(pkt_type, payload) # Send ack if self.ctrl_socket_type == CtrlType.SERIAL: client_socket.write(b"k") else: client_socket.sendall("k") return payload_len + 5 def parse_ies(self, payload): while len(payload) >= 5: # Extract IE header ie_type, ie_len = struct.unpack(">BI", payload[0:5]) payload = payload[5:] # Extract IE data ie = payload[0:ie_len] payload = payload[ie_len:] logger.debug("IE type %d of len %d: %s" % (ie_type, ie_len, binary_to_hex(ie))) # Determine what to do with IE if ie_type == InformationElementType.PLAINTEXT: self.stored_plaintext = [ord(c) for c in ie] elif ie_type == InformationElementType.KEY: self.stored_key = [ord(c) for c in ie] else: logger.warning("Unknown IE type: %d" % ie_type) def process_ctrl_packet(self, pkt_type, payload): if pkt_type == CtrlPacketType.SIGNAL_START: logger.debug("Starting for payload: %s" % binary_to_hex(payload)) self.parse_ies(payload) self.sdr.start() # Spinlock until data timeout = 3 current_time = 0.0 while len(self.stored_data) <= self.wait_num_chunks: sleep(0.0001) current_time += 0.0001 if current_time >= timeout: logger.warning("Timeout while waiting for data. Did the SDR crash? Reinstantiating...") del self.sdr self.data_socket.socket.close() self.data_socket = SocketWrapper(socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM), ('127.0.0.1', 3884), self.cb_data) self.data_socket.start() self.sdr = SDR(**self.cap_kwargs) self.process_ctrl_packet(pkt_type, payload) elif pkt_type == CtrlPacketType.SIGNAL_END: # self.sdr.sdr_source.stop() self.sdr.stop() self.sdr.wait() logger.debug("Stopped after receiving %d chunks" % len(self.stored_data)) #sleep(0.5) #logger.debug("After sleep we have %d chunks" % len(self.stored_data)) # Successful capture (no errors or timeouts) if len(self.stored_data) > 0: # We have more than 1 chunk # Data to file np_data = np.fromstring(b"".join(self.stored_data), dtype=np.complex64) self.trace_set.append(np_data) self.plaintexts.append(self.stored_plaintext) self.keys.append(self.stored_key) if len(self.trace_set) >= self.kwargs['traces_per_set']: assert(len(self.trace_set) == len(self.plaintexts)) assert(len(self.trace_set) == len(self.keys)) np_trace_set = np.array(self.trace_set) np_plaintexts = np.array(self.plaintexts, dtype=np.uint8) np_keys = np.array(self.keys, dtype=np.uint8) if not self.online is None: # Stream online ts = TraceSet(name="online %d" % self.online_counter, traces=np_trace_set, plaintexts=np_plaintexts, ciphertexts=None, keys=np_keys) logger.info("Pickling") ts_p = pickle.dumps(ts) logger.info("Size is %d" % len(ts_p)) stream_payload = ts_p stream_payload_len = len(stream_payload) logger.info("Streaming trace set of %d bytes to server" % stream_payload_len) stream_hdr = struct.pack(">BI", 0, stream_payload_len) self.emma_client.send(stream_hdr + stream_payload) self.online_counter += 1 else: # Save to disk if not self.kwargs['dry']: # Write metadata to sigmf file # if sigmf #with open(test_meta_path, 'w') as f: # test_sigmf = SigMFFile(data_file=test_data_path, global_info=copy.deepcopy(self.global_meta)) # test_sigmf.add_capture(0, metadata=capture_meta) # test_sigmf.dump(f, pretty=True) # elif chipwhisperer: logger.info("Dumping %d traces to file" % len(self.trace_set)) filename = str(datetime.utcnow()).replace(" ","_").replace(".","_") output_dir = self.kwargs['output_dir'] np.save(os.path.join(output_dir, "%s_traces.npy" % filename), np_trace_set) # TODO abstract this in trace_set class np.save(os.path.join(output_dir, "%s_textin.npy" % filename), np_plaintexts) np.save(os.path.join(output_dir, "%s_knownkey.npy" % filename), np_keys) if self.compress: logger.info("Calling emcap-compress...") subprocess.call(['/usr/bin/python', 'emcap-compress.py', os.path.join(output_dir, "%s_traces.npy" % filename)]) self.limit_counter += len(self.trace_set) if self.limit_counter >= self.limit: print("Done") exit(0) # Clear results self.trace_set = [] self.plaintexts = [] self.keys = [] # Clear self.stored_data = [] self.stored_plaintext = [] def capture(self, to_skip=0, timeout=1.0): # Start listening for signals self.data_socket.start() self.ctrl_socket.start() # Wait until supplicant signals end of acquisition while self.ctrl_socket.is_alive(): self.ctrl_socket.join(timeout=1.0) logging.info("Supplicant disconnected on control channel. Stopping...")
def main(): client_socket = SocketWrapper('<<EOC') try: client_socket.host_name = sys.argv[1] client_socket.port_number = int(sys.argv[2]) except: print "Usage: mudclient.py HOSTNAME PORT" sys.exit(1) client_socket.buffer_size = 4096 #servers bind clients connect client_socket.connectToServer() #recieve and print intro message print client_socket.recieveData() while(1): message = raw_input("Enter Command: ") message += '<<EOC' client_socket.sendMessage(message) data = client_socket.recieveData() if message.lower() == "quit<<eoc": break print data client_socket.closeConnection()
class Controller: """ The main class for controlling AVT - Aislinn Valgrind Tool Terminology: client - a verified process client's memory - a memory visible to a verified process buffer - a memory allocated in AVT by controller; invisible to client """ # TODO: Universal architecture detection POINTER_SIZE = 8 INT_SIZE = 4 FUNCTION_INT = 0 FUNCTION_4_POINTER = 1 FUNCTION_2_INT_2_POINTER = 2 FUNCTION_2_INT_4_POINTER = 3 debug = False debug_by_valgrind_tool = None stdout_file = None stderr_file = None profile = False extra_env = None heap_size = None redzone_size = None verbose = None name = "" # For debug purpose def __init__(self, valgrind_bin, args, cwd=None): self.process = None self.socket = None self.recv_buffer = "" self.args = tuple(args) self.cwd = cwd self.server_socket = None self.running = False self.valgrind_bin = valgrind_bin def start(self, capture_syscalls=()): """ Start Valgrind with Aislinn plugin (AVT) and initilizes connection """ assert self.process is None # Nothing is running assert self.socket is None self.server_socket = self._start_server() port = self.server_socket.getsockname()[1] self._start_valgrind(port, capture_syscalls) def connect(self): """ Connect to AVT """ self.server_socket.settimeout(5.0) try: sock, addr = self.server_socket.accept() except socket.timeout: logging.error("Aislinn client was not started") return False self.socket = SocketWrapper(sock) self.socket.set_no_delay() self.server_socket.close() self.server_socket = None return True # User has to call receive_line after calling this method # But it may take some time to initialize vgclient, hence # it is not build in in connect to allow polling def start_and_connect(self, *args, **kw): """ Calls 'start' and 'connect' and receives the first line, returns None if connection failed""" self.start(*args, **kw) if not self.connect(): return None return self.receive_line() def kill(self): """ Kills running AVT """ if self.process and self.process.poll() is None: self.process.kill() self.process = None def set_capture_syscall(self, syscall, value): """ Switches on/off a capturing a syscall """ self.send_and_receive_ok( "SET syscall {0} {1}\n".format(syscall, "on" if value else "off")) def save_state(self): """ Save a current process state """ return self.send_and_receive_int("SAVE\n") def restore_state(self, state_id): """ Restores a saved process state """ self.send_and_receive_ok("RESTORE {0}\n".format(state_id)) def free_state(self, state_id): """ Frees a saved state """ self.send_command("FREE {0}\n".format(state_id)) def run_process(self): """ Resumes the paused process and wait until new event, then returns the event """ return self.send_and_receive("RUN\n") def run_drop_syscall(self, return_value): """ When process is paused in syscall, it skips the syscall and then behaves as 'run' """ return self.send_and_receive( "RUN_DROP_SYSCALL {0}\n".format(return_value)) def run_process_async(self): """ Asynchronous version of 'run'. It does not wait for the next event and returns immediately """ self.running = True self.send_command("RUN\n") def run_drop_syscall_async(self, return_value): """ Asynchornous version of 'run_drop_syscall'. It does not wait for the next event and retusn immediately. """ self.running = True self.send_command("RUN_DROP_SYSCALL {0}\n".format(return_value)) def finish_async(self): """ Finishes an asynchronous call """ assert self.running self.running = False return self.receive_line() def run_function(self, fn_pointer, fn_type, *args): """ Executes a function in client """ command = "RUN_FUNCTION {0} {1} {2} {3} \n".format( fn_pointer, fn_type, len(args), " ".join(map(str, args))) return self.send_and_receive(command) def client_malloc(self, size): """ Calls "malloc" in client, i.e. allocate a memory that is visible for the verified process """ return self.send_and_receive_int("CLIENT_MALLOC {0}\n".format(size)) def client_free(self, mem): """ Calls "free" in client (an opposite function to client_malloc) """ self.send_and_receive_ok("CLIENT_FREE {0}\n".format(mem)) def client_malloc_from_buffer(self, buffer_id): """ Allocate a client's memory with the same size as buffer and copy buffer into this memory. """ return self.send_and_receive_int( "CLIENT_MALLOC_FROM_BUFFER {0}\n".format(buffer_id)) def memcpy(self, addr, source, size, check=True): """ Copies a non-overlapping block memory """ self.send_and_receive_ok("WRITE {0} {1} addr {2} {3}\n" .format(check_str(check), addr, source, size)) def write_into_buffer(self, buffer_id, index, addr, size): """ Writes a client memory into a buffer """ # Copy a memory from client addres to the buffer self.send_and_receive_ok("WRITE_BUFFER {0} {1} {2} {3}\n" .format(buffer_id, index, addr, size)) def write_data(self, addr, data, check=True): """ Writes data (str) into client's memory """ size = len(data) if size == 0: return # TODO: the following constant should be benchmarked if size < 8192: command = "WRITE {0} {1} mem {2}\n{3}" \ .format(check_str(check), addr, len(data), data) self.send_data_and_receive_ok(command) else: command = "WRITE {0} {1} mem {2}" \ .format(check_str(check), addr, len(data)) self.send_command(command) self.send_data_and_receive_ok(data) def write_data_into_buffer(self, buffer_addr, index, data): """ Writes data (str) into buffer """ size = len(data) if size == 0: return # TODO: the following constant should be benchmarked if size < 8192: self.send_data_and_receive_ok( "WRITE_BUFFER_DATA {0} {1} {2}\n{3}" .format(buffer_addr, index, len(data), data)) else: self.send_command("WRITE_BUFFER_DATA {0} {1} {2}\n" .format(buffer_addr, index, len(data))) self.send_data_and_receive_ok(data) def write_buffer(self, addr, buffer_addr, index=None, size=None, check=True): """ Copies a buffer into client's memory """ if index is None or size is None: self.send_and_receive_ok( "WRITE {0} {1} buffer {2}\n" .format(check_str(check), addr, buffer_addr)) else: assert size is not None if size == 0: return self.send_and_receive_ok( "WRITE {0} {1} buffer-part {2} {3} {4}\n" .format(check_str(check), addr, buffer_addr, index, size)) def write_int(self, addr, value, check=True): """ Writes int into client's memory """ self.send_and_receive_ok("WRITE {0} {1} int {2}\n" .format(check_str(check), addr, value)) def write_string(self, addr, value, check=True): """ Writes string into client's memory """ self.send_and_receive_ok("WRITE {0} {1} string {2}\n" .format(check_str(check), addr, value)) def write_pointer(self, addr, value, check=True): """ Writes pointer into client's memory """ self.send_and_receive_ok("WRITE {0} {1} pointer {2}\n" .format(check_str(check), addr, value)) def write_ints(self, addr, values, check=True): """ Writes an array of ints into client's memory """ self.send_and_receive_ok( "WRITE {0} {1} ints {2} {3}\n" .format(check_str(check), addr, len(values), " ".join(map(str, values)))) def read_mem(self, addr, size): """ Reads client's memory """ return self.send_and_receive_data("READ {0} mem {1}\n" .format(addr, size)) def read_int(self, addr): """ Reads int from client's memory """ return self.send_and_receive_int("READ {0} int\n".format(addr)) def read_pointer(self, addr): """ Reads pointer from client's memory """ return self.send_and_receive_int("READ {0} pointer\n".format(addr)) def read_ints(self, addr, count): """ Reads an array of ints from client's memory """ line = self.send_and_receive("READ {0} ints {1}\n".format(addr, count)) results = map(int, line.split()) assert len(results) == count return results def read_pointers(self, addr, count): """ Reads an array of pointers from client's memory """ line = self.send_and_receive("READ {0} pointers {1}\n" .format(addr, count)) results = map(int, line.split()) assert len(results) == count return results def read_string(self, addr): """ Reads a string from client's memory """ return self.send_and_receive_data("READ {0} string\n".format(addr)) def read_buffer(self, buffer_id): """ Reads a buffer """ return self.send_and_receive_data("READ_BUFFER {0}\n" .format(buffer_id)) def hash_state(self): """ Hashes current process state """ h = self.send_and_receive("HASH\n") return h def hash_buffer(self, buffer_id): """ Hashes a buffer """ return self.send_and_receive("HASH_BUFFER {0}\n".format(buffer_id)) def get_stacktrace(self): """ Returns stack trace (each item separeted by ';') """ return self.send_and_receive("STACKTRACE\n") def get_stats(self): """ Gets internal statistic from client (number of states, buffers, etc ...) """ self.send_command("STATS\n") result = {} for entry in self.receive_line().split("|"): name, value = entry.split() result[name] = int(value) return result def is_writable(self, addr, size): """ Returns True if an client's address is writable """ return self.send_and_receive("CHECK write {0} {1}\n" .format(addr, size)) def is_readable(self, addr, size): """ Returns True if an client's address is readable """ return self.send_and_receive("CHECK read {0} {1}\n".format(addr, size)) def lock_memory(self, addr, size): """ Marks a client's memory as read only """ self.send_and_receive_ok("LOCK {0} {1}\n".format(addr, size)) def unlock_memory(self, addr, size): """ Marks a client's memory as defined """ self.send_and_receive_ok("UNLOCK {0} {1}\n".format(addr, size)) def get_allocations(self): """ Get list of client's allocations on heap """ return self.send_and_receive("ALLOCATIONS\n") def interconn_listen(self): """ Clients start to listen for a connection on a free port, that is returned from the method. This blocks AVT but not controller. Method 'interconn_listen_finish' has to be called after this method """ port = self.send_and_receive_int("CONN_LISTEN\n") self.running = True return port def interconn_listen_finish(self): """ This has to be called after interconn_listen. It blocks until the client is not connected and then returns socket id """ return int(self.finish_async()) def interconn_connect(self, host): """ Initializes a connection to another AVT that is listening by 'interconn_listen'. This has be followed by 'interconn_connect_finish'. """ self.running = True return self.send_command("CONN_CONNECT {0}\n".format(host)) def interconn_connect_finish(self): """ This method has to follow 'interconn_connect'. Blocks until connection is not finished. Returns socket id.""" return int(self.finish_async()) def push_state(self, socket, state_id): """ Send a state through an AVT interconnection """ self.send_command("CONN_PUSH_STATE {0} {1}\n".format(socket, state_id)) def pull_state(self, socket): """ Receives a state through an AVT interconnection """ return self.send_and_receive_int("CONN_PULL_STATE {0}\n" .format(socket)) def send_command(self, command): """ Send a command to AVT """ assert command[-1] == "\n", "Command does not end with new line" self.socket.send_data(command) def send_data(self, data): """ Send data to AVT """ self.socket.send_data(data) def receive_line(self): """ Receives a line (string) from AVT """ line = self.socket.read_line() if line.startswith("Error:"): raise Exception("Received line: " + line) return line def receive_data(self): """ Receives a data from AVT """ args = self.socket.read_line().split() return self.socket.read_data(int(args[1])) def send_and_receive(self, command): """ Sends a command and waits for the answer.""" self.send_command(command) assert not self.running return self.receive_line() def send_and_receive_data(self, command): """ Sends a command and waits for the answer as data.""" self.send_command(command) assert not self.running return self.receive_data() def send_and_receive_ok(self, command): """ Sends a command and waits for its confirmation (string "Ok\n") """ self.send_command(command) assert not self.running r = self.receive_line() if r != "Ok": raise self.on_unexpected_output(r) def send_data_and_receive_ok(self, data): """ Sends data and waits for its confirmation (string "Ok\n") """ self.send_data(data) assert not self.running r = self.receive_line() if r != "Ok": raise self.on_unexpected_output(r) def on_unexpected_output(self, line): """ This method is called when unexpected output is received, by default it throws UnexpectedOutput exception""" raise UnexpectedOutput(line) def receive_until_ok(self): """ Receives lines until "Ok" is not received """ result = [] line = self.receive_line() while line != "Ok": result.append(line) line = self.receive_line() return result def send_and_receive_int(self, command): """ Sends a command and waits for int """ return int(self.send_and_receive(command)) def debug_compare(self, state_id1, state_id2): """ Compares two saved states in AVT """ self.send_and_receive_ok("DEBUG_COMPARE {0} {1}\n" .format(state_id1, state_id2)) def debug_dump_state(self, state_id): """ Dumps a saved state on stderr """ self.send_and_receive_ok("DEBUG_DUMP_STATE {0}\n" .format(state_id)) def make_buffer(self, buffer_id, size): """ Creates a new buffer """ self.send_and_receive_ok("NEW_BUFFER {0} {1}\n" .format(buffer_id, size)) def free_buffer(self, buffer_id): """ Frees a buffer """ self.send_command("FREE_BUFFER {0}\n".format(buffer_id)) def _start_valgrind(self, port, capture_syscalls): args = ( self.valgrind_bin, "-q", "--tool=aislinn", "--port={0}".format(port), "--identification={0}".format(self.name), ) + tuple(["--capture-syscall=" + name for name in capture_syscalls]) if self.profile: args += ("--profile=yes",) if self.heap_size is not None: args += ("--heap-size={0}".format(self.heap_size),) if self.redzone_size is not None: args += ("--alloc-redzone-size={0}".format(self.redzone_size),) if self.verbose is not None: args += ("--verbose={0}".format(self.verbose),) args += self.args if self.debug_by_valgrind_tool: args = ( "valgrind", "--tool=" + self.debug_by_valgrind_tool, "--sim-hints=enable-outer", "--trace-children=yes", "--smc-check=all-non-file", "--run-libc-freeres=no") + args logging.debug("Starting valgrind with %s", args) if self.extra_env: env = os.environ.copy() for v in self.extra_env: env[v] = self.extra_env[v] else: env = None self.process = subprocess.Popen( args, cwd=self.cwd, env=env, stdout=self.stdout_file, stderr=self.stderr_file) def _start_server(self): HOST = "127.0.0.1" # Connection only from localhost PORT = 0 # Alloc arbirary empty port s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind((HOST, PORT)) s.listen(1) return s def __repr__(self): return "<Controller '{0}'>".format(self.name)
class Controller: # TODO: Universal architecture detection POINTER_SIZE = 8 INT_SIZE = 4 FUNCTION_INT = 0 FUNCTION_4_POINTER = 1 FUNCTION_2_INT_2_POINTER = 2 FUNCTION_2_INT_4_POINTER = 3 debug_by_valgrind_tool = None stdout_arg = None buffer_server_port = None profile = False name = "" # For debug purpose def __init__(self, args, cwd=None): self.process = None self.socket = None self.recv_buffer = "" self.args = tuple(args) self.cwd = cwd self.valgrind_args = () self.server_socket = None self.running = False def start(self, capture_syscalls=()): assert self.process is None # Nothing is running assert self.socket is None self.server_socket = self._start_server() port = self.server_socket.getsockname()[1] self._start_valgrind(port, capture_syscalls) def start_and_connect(self, *args, **kw): self.start(*args, **kw) self.connect() return self.receive_line() def connect(self): self.server_socket.settimeout(5.0) try: sock, addr = self.server_socket.accept() except socket.timeout: logging.error("Aislinn client was not started") return False self.socket = SocketWrapper(sock) self.socket.set_no_delay() self.server_socket.close() self.server_socket = None return True # User has to call receive_line after calling this method # But it may take some time to initialize vgclient, hence # it is not build in in connect to allow polling def kill(self): if self.process and self.process.poll() is None: self.process.kill() self.process = None def run_process(self): return self.send_and_receive("RUN\n") def run_drop_syscall(self): return self.send_and_receive("RUN_DROP_SYSCALL\n") def run_process_async(self): self.running = True self.send_command("RUN\n") def run_drop_syscall_async(self): self.running = True self.send_command("RUN_DROP_SYSCALL\n") def run_function(self, fn_pointer, fn_type, *args): command = "RUN_FUNCTION {0} {1} {2} {3} \n".format( fn_pointer, fn_type, len(args), " ".join(map(str, args))) return self.send_and_receive(command) def client_malloc(self, size): return self.send_and_receive_int("CLIENT_MALLOC {0}\n".format(size)) def client_free(self, mem): self.send_and_receive_ok("CLIENT_FREE {0}\n".format(mem)) def client_malloc_from_buffer(self, buffer_id): return self.send_and_receive_int( "CLIENT_MALLOC_FROM_BUFFER {0}\n".format(buffer_id)) def memcpy(self, addr, source, size, check=True): self.send_and_receive_ok("WRITE {0} {1} addr {2} {3}\n" \ .format(check_str(check), addr, source, size)) def write_into_buffer(self, buffer_addr, index, addr, size): # Copy a memory from client addres to the buffer self.send_and_receive_ok("WRITE_BUFFER {0} {1} {2} {3}\n" \ .format(buffer_addr, index, addr, size)) def write_data_into_buffer(self, buffer_addr, index, data): # Write a literal data into the buffer size = len(data) if size == 0: return # TODO: the following constant should be benchmarked if size < 8192: self.send_data_and_receive_ok( "WRITE_BUFFER_DATA {0} {1} {2}\n{3}" \ .format(buffer_addr, index, len(data), data)) else: self.send_command("WRITE_BUFFER_DATA {0} {1} {2}\n" \ .format(buffer_addr, index, len(data))) self.send_data_and_receive_ok(data) def write_buffer(self, addr, buffer_addr, index=None, size=None, check=True): if index is None or size is None: self.send_and_receive_ok("WRITE {0} {1} buffer {2}\n" \ .format(check_str(check), addr, buffer_addr)) else: assert size is not None if size == 0: return self.send_and_receive_ok("WRITE {0} {1} buffer-part {2} {3} {4}\n" \ .format(check_str(check), addr, buffer_addr, index, size)) def write_int(self, addr, value, check=True): self.send_and_receive_ok("WRITE {0} {1} int {2}\n" \ .format(check_str(check), addr, value)) def write_string(self, addr, value, check=True): self.send_and_receive_ok("WRITE {0} {1} string {2}\n" \ .format(check_str(check), addr, value)) def write_pointer(self, addr, value, check=True): self.send_and_receive_ok("WRITE {0} {1} pointer {2}\n" \ .format(check_str(check), addr, value)) def write_ints(self, addr, values, check=True): self.send_and_receive_ok("WRITE {0} {1} ints {2} {3}\n" \ .format(check_str(check), addr, len(values), " ".join(map(str, values)))) def read_mem(self, addr, size): return self.send_and_receive_data("READ {0} mem {1}\n" \ .format(addr, size)) def read_int(self, addr): return self.send_and_receive_int("READ {0} int\n".format(addr)) def read_pointer(self, addr): return self.send_and_receive_int("READ {0} pointer\n".format(addr)) def read_ints(self, addr, count): line = self.send_and_receive("READ {0} ints {1}\n".format(addr, count)) results = map(int, line.split()) assert len(results) == count return results def read_pointers(self, addr, count): line = self.send_and_receive("READ {0} pointers {1}\n" \ .format(addr, count)) results = map(int, line.split()) assert len(results) == count return results def read_string(self, addr): return self.send_and_receive_data("READ {0} string\n".format(addr)) def hash_state(self): #s = time.time() h = self.send_and_receive("HASH\n") #e = time.time() #print e - s return h def hash_buffer(self, buffer_id): return self.send_and_receive("HASH_BUFFER {0}\n".format(buffer_id)) def get_stacktrace(self): return self.send_and_receive("STACKTRACE\n") def get_stats(self): self.send_command("STATS\n") result = {} for entry in self.receive_line().split("|"): name, value = entry.split() result[name] = int(value) return result def is_writable(self, addr, size): return self.send_and_receive("CHECK write {0} {1}\n".format(addr, size)) def is_readable(self, addr, size): return self.send_and_receive("CHECK read {0} {1}\n".format(addr, size)) def lock_memory(self, addr, size): self.send_and_receive_ok("LOCK {0} {1}\n".format(addr, size)) def unlock_memory(self, addr, size): self.send_and_receive_ok("UNLOCK {0} {1}\n".format(addr, size)) def get_allocations(self): return self.send_and_receive("ALLOCATIONS\n"); ### Semi-internal functions def send_command(self, command): assert command[-1] == "\n", "Command does not end with new line" self.socket.send_data(command) def send_data(self, data): self.socket.send_data(data) def receive_line(self): line = self.socket.read_line() if line.startswith("Error:"): raise Exception("Received line: " + line) return line def finish_async(self): assert self.running self.running = False return self.receive_line() def receive_data(self): args = self.socket.read_line().split() return self.socket.read_data(int(args[1])) def send_and_receive(self, command): self.send_command(command) assert not self.running return self.receive_line() def send_and_receive_data(self, command): self.send_command(command) assert not self.running return self.receive_data() def send_and_receive_ok(self, command): self.send_command(command) assert not self.running r = self.receive_line() if r != "Ok": raise self.on_unexpected_output(r) def send_data_and_receive_ok(self, data): self.send_data(data) assert not self.running r = self.receive_line() if r != "Ok": raise self.on_unexpected_output(r) def on_unexpected_output(self, line): raise UnexpectedOutput(line) def receive_until_ok(self): result = [] line = self.receive_line() while line != "Ok": result.append(line) line = self.receive_line() return result def send_and_receive_int(self, command): return int(self.send_and_receive(command)) def debug_compare(self, state_id1, state_id2): self.send_and_receive_ok( "DEBUG_COMPARE {0} {1}\n".format(state_id1, state_id2)) def set_capture_syscall(self, syscall, value): self.send_and_receive_ok( "SET syscall {0} {1}\n".format(syscall, "on" if value else "off")) def save_state(self): return self.send_and_receive_int("SAVE\n") def restore_state(self, state_id): self.send_and_receive_ok("RESTORE {0}\n".format(state_id)) def make_buffer(self, buffer_id, size): self.send_and_receive_ok( "NEW_BUFFER {0} {1}\n".format(buffer_id, size)) def start_remote_buffer(self, buffer_id): self.send_command("START_REMOTE_BUFFER {0}\n".format(buffer_id)) def finish_remote_buffer(self): self.send_and_receive_ok("FINISH_REMOTE_BUFFER\n") def remote_buffer_upload(self, addr, size): self.send_command("UPLOAD {0} {1}\n".format(addr, size)) def remote_buffer_download(self, buffer_id): self.send_command("DOWNLOAD {0}\n".format(buffer_id)) def free_state(self, state_id): self.send_command("FREE {0}\n".format(state_id)) def free_buffer(self, buffer_id): self.send_command("FREE_BUFFER {0}\n".format(buffer_id)) def _start_valgrind(self, port, capture_syscalls): args = ( paths.VALGRIND_BIN, "-q", "--tool=aislinn", "--port={0}".format(port), "--identification={0}".format(self.name), ) + tuple([ "--capture-syscall=" + name for name in capture_syscalls ]) if self.buffer_server_port is not None: args += ("--bs-port={0}".format(self.buffer_server_port),) if self.profile: args += ("--profile=yes",) args += tuple(self.valgrind_args) + tuple(self.args) if self.debug_by_valgrind_tool: args = ( "valgrind", "--tool=" + self.debug_by_valgrind_tool, "--sim-hints=enable-outer", "--trace-children=yes", "--smc-check=all-non-file", "--run-libc-freeres=no") + args logging.debug("Starting valgrind with %s", args) self.process = subprocess.Popen( args, cwd=self.cwd, stdout=self.stdout_arg) def _start_server(self): HOST = "127.0.0.1" # Connection only from localhost PORT = 0 # Alloc arbirary empty port s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind((HOST, PORT)) s.listen(1) return s def __repr__(self): return "<Controller '{0}'>".format(self.name)