136 lines
4.7 KiB
Python
136 lines
4.7 KiB
Python
import logging, re, random
|
|
from autotest_lib.client.common_lib import error
|
|
from autotest_lib.client.virt import aexpect
|
|
|
|
|
|
def run_iofuzz(test, params, env):
|
|
"""
|
|
KVM iofuzz test:
|
|
1) Log into a guest
|
|
2) Enumerate all IO port ranges through /proc/ioports
|
|
3) On each port of the range:
|
|
* Read it
|
|
* Write 0 to it
|
|
* Write a random value to a random port on a random order
|
|
|
|
If the guest SSH session hangs, the test detects the hang and the guest
|
|
is then rebooted. The test fails if we detect the qemu process to terminate
|
|
while executing the process.
|
|
|
|
@param test: kvm test object
|
|
@param params: Dictionary with the test parameters
|
|
@param env: Dictionary with test environment.
|
|
"""
|
|
def outb(session, port, data):
|
|
"""
|
|
Write data to a given port.
|
|
|
|
@param session: SSH session stablished to a VM
|
|
@param port: Port where we'll write the data
|
|
@param data: Integer value that will be written on the port. This
|
|
value will be converted to octal before its written.
|
|
"""
|
|
logging.debug("outb(0x%x, 0x%x)", port, data)
|
|
outb_cmd = ("echo -e '\\%s' | dd of=/dev/port seek=%d bs=1 count=1" %
|
|
(oct(data), port))
|
|
try:
|
|
session.cmd(outb_cmd)
|
|
except aexpect.ShellError, e:
|
|
logging.debug(e)
|
|
|
|
|
|
def inb(session, port):
|
|
"""
|
|
Read from a given port.
|
|
|
|
@param session: SSH session stablished to a VM
|
|
@param port: Port where we'll read data
|
|
"""
|
|
logging.debug("inb(0x%x)", port)
|
|
inb_cmd = "dd if=/dev/port seek=%d of=/dev/null bs=1 count=1" % port
|
|
try:
|
|
session.cmd(inb_cmd)
|
|
except aexpect.ShellError, e:
|
|
logging.debug(e)
|
|
|
|
|
|
def fuzz(session, inst_list):
|
|
"""
|
|
Executes a series of read/write/randwrite instructions.
|
|
|
|
If the guest SSH session hangs, an attempt to relogin will be made.
|
|
If it fails, the guest will be reset. If during the process the VM
|
|
process abnormally ends, the test fails.
|
|
|
|
@param inst_list: List of instructions that will be executed.
|
|
@raise error.TestFail: If the VM process dies in the middle of the
|
|
fuzzing procedure.
|
|
"""
|
|
for (op, operand) in inst_list:
|
|
if op == "read":
|
|
inb(session, operand[0])
|
|
elif op == "write":
|
|
outb(session, operand[0], operand[1])
|
|
else:
|
|
raise error.TestError("Unknown command %s" % op)
|
|
|
|
if not session.is_responsive():
|
|
logging.debug("Session is not responsive")
|
|
if vm.process.is_alive():
|
|
logging.debug("VM is alive, try to re-login")
|
|
try:
|
|
session = vm.wait_for_login(timeout=10)
|
|
except:
|
|
logging.debug("Could not re-login, reboot the guest")
|
|
session = vm.reboot(method="system_reset")
|
|
else:
|
|
raise error.TestFail("VM has quit abnormally during "
|
|
"%s: %s" % (op, operand))
|
|
|
|
|
|
login_timeout = float(params.get("login_timeout", 240))
|
|
vm = env.get_vm(params["main_vm"])
|
|
vm.verify_alive()
|
|
session = vm.wait_for_login(timeout=login_timeout)
|
|
|
|
try:
|
|
ports = {}
|
|
r = random.SystemRandom()
|
|
|
|
logging.info("Enumerate guest devices through /proc/ioports")
|
|
ioports = session.cmd_output("cat /proc/ioports")
|
|
logging.debug(ioports)
|
|
devices = re.findall("(\w+)-(\w+)\ : (.*)", ioports)
|
|
|
|
skip_devices = params.get("skip_devices","")
|
|
fuzz_count = int(params.get("fuzz_count", 10))
|
|
|
|
for (beg, end, name) in devices:
|
|
ports[(int(beg, base=16), int(end, base=16))] = name.strip()
|
|
|
|
for (beg, end) in ports.keys():
|
|
name = ports[(beg, end)]
|
|
if name in skip_devices:
|
|
logging.info("Skipping device %s", name)
|
|
continue
|
|
|
|
logging.info("Fuzzing %s, port range 0x%x-0x%x", name, beg, end)
|
|
inst = []
|
|
|
|
# Read all ports of the range
|
|
for port in range(beg, end + 1):
|
|
inst.append(("read", [port]))
|
|
|
|
# Write 0 to all ports of the range
|
|
for port in range(beg, end + 1):
|
|
inst.append(("write", [port, 0]))
|
|
|
|
# Write random values to random ports of the range
|
|
for seq in range(fuzz_count * (end - beg + 1)):
|
|
inst.append(("write",
|
|
[r.randint(beg, end), r.randint(0,255)]))
|
|
|
|
fuzz(session, inst)
|
|
|
|
finally:
|
|
session.close()
|