1 import logging, re, random 2 from autotest_lib.client.common_lib import error 3 from autotest_lib.client.virt import aexpect 4 5 6 def run_iofuzz(test, params, env): 7 """ 8 KVM iofuzz test: 9 1) Log into a guest 10 2) Enumerate all IO port ranges through /proc/ioports 11 3) On each port of the range: 12 * Read it 13 * Write 0 to it 14 * Write a random value to a random port on a random order 15 16 If the guest SSH session hangs, the test detects the hang and the guest 17 is then rebooted. The test fails if we detect the qemu process to terminate 18 while executing the process. 19 20 @param test: kvm test object 21 @param params: Dictionary with the test parameters 22 @param env: Dictionary with test environment. 23 """ 24 def outb(session, port, data): 25 """ 26 Write data to a given port. 27 28 @param session: SSH session stablished to a VM 29 @param port: Port where we'll write the data 30 @param data: Integer value that will be written on the port. This 31 value will be converted to octal before its written. 32 """ 33 logging.debug("outb(0x%x, 0x%x)", port, data) 34 outb_cmd = ("echo -e '\\%s' | dd of=/dev/port seek=%d bs=1 count=1" % 35 (oct(data), port)) 36 try: 37 session.cmd(outb_cmd) 38 except aexpect.ShellError, e: 39 logging.debug(e) 40 41 42 def inb(session, port): 43 """ 44 Read from a given port. 45 46 @param session: SSH session stablished to a VM 47 @param port: Port where we'll read data 48 """ 49 logging.debug("inb(0x%x)", port) 50 inb_cmd = "dd if=/dev/port seek=%d of=/dev/null bs=1 count=1" % port 51 try: 52 session.cmd(inb_cmd) 53 except aexpect.ShellError, e: 54 logging.debug(e) 55 56 57 def fuzz(session, inst_list): 58 """ 59 Executes a series of read/write/randwrite instructions. 60 61 If the guest SSH session hangs, an attempt to relogin will be made. 62 If it fails, the guest will be reset. If during the process the VM 63 process abnormally ends, the test fails. 64 65 @param inst_list: List of instructions that will be executed. 66 @raise error.TestFail: If the VM process dies in the middle of the 67 fuzzing procedure. 68 """ 69 for (op, operand) in inst_list: 70 if op == "read": 71 inb(session, operand[0]) 72 elif op == "write": 73 outb(session, operand[0], operand[1]) 74 else: 75 raise error.TestError("Unknown command %s" % op) 76 77 if not session.is_responsive(): 78 logging.debug("Session is not responsive") 79 if vm.process.is_alive(): 80 logging.debug("VM is alive, try to re-login") 81 try: 82 session = vm.wait_for_login(timeout=10) 83 except: 84 logging.debug("Could not re-login, reboot the guest") 85 session = vm.reboot(method="system_reset") 86 else: 87 raise error.TestFail("VM has quit abnormally during " 88 "%s: %s" % (op, operand)) 89 90 91 login_timeout = float(params.get("login_timeout", 240)) 92 vm = env.get_vm(params["main_vm"]) 93 vm.verify_alive() 94 session = vm.wait_for_login(timeout=login_timeout) 95 96 try: 97 ports = {} 98 r = random.SystemRandom() 99 100 logging.info("Enumerate guest devices through /proc/ioports") 101 ioports = session.cmd_output("cat /proc/ioports") 102 logging.debug(ioports) 103 devices = re.findall("(\w+)-(\w+)\ : (.*)", ioports) 104 105 skip_devices = params.get("skip_devices","") 106 fuzz_count = int(params.get("fuzz_count", 10)) 107 108 for (beg, end, name) in devices: 109 ports[(int(beg, base=16), int(end, base=16))] = name.strip() 110 111 for (beg, end) in ports.keys(): 112 name = ports[(beg, end)] 113 if name in skip_devices: 114 logging.info("Skipping device %s", name) 115 continue 116 117 logging.info("Fuzzing %s, port range 0x%x-0x%x", name, beg, end) 118 inst = [] 119 120 # Read all ports of the range 121 for port in range(beg, end + 1): 122 inst.append(("read", [port])) 123 124 # Write 0 to all ports of the range 125 for port in range(beg, end + 1): 126 inst.append(("write", [port, 0])) 127 128 # Write random values to random ports of the range 129 for seq in range(fuzz_count * (end - beg + 1)): 130 inst.append(("write", 131 [r.randint(beg, end), r.randint(0,255)])) 132 133 fuzz(session, inst) 134 135 finally: 136 session.close() 137