def test_fuzz_args():
    fuzzing_time_seconds = 45 * 60
    iotrace: IotracePlugin = TestRun.plugins['iotrace']

    repo_path: str = f"{iotrace.working_dir}/slit-afl"
    disk = TestRun.dut.disks[0].system_path

    # Make sure AFL is installed
    if not is_afl_installed():
        install_afl()

    # Install iotrace locally with AFL support
    # Patch so that we redirect fuzzed stdin to argv
    install_iotrace_with_afl_support(
        repo_path + "/tests/security/fuzzy/redirect-fuzz-to-argv.patch")

    # Instruct the system to output coredumps as files instead of sending them
    # to a specific crash handler app
    TestRun.LOGGER.info('Setting up system for fuzzing')
    TestRun.executor.run_expect_success(
        'echo core > /proc/sys/kernel/core_pattern')
    TestRun.executor.run_expect_success(
        f'cd {repo_path} && mkdir -p afl-i afl-o')

    # Add input seeds which shall be mutated - try list-traces, version, help,
    # start-tracing and remove-trace commands to guide the fuzzer.
    TestRun.executor.run_expect_success(f'cd {repo_path} && echo "-L"'
                                        f' > afl-i/case0')
    TestRun.executor.run_expect_success(f'cd {repo_path} && echo "-L -p k*"'
                                        f' > afl-i/case1')
    TestRun.executor.run_expect_success(f'cd {repo_path} && echo "-V"'
                                        f' > afl-i/case2')
    TestRun.executor.run_expect_success(f'cd {repo_path} && echo "-H"'
                                        f' > afl-i/case3')
    TestRun.executor.run_expect_success(
        f'cd {repo_path} && echo "-S -d {disk}"'
        f' > afl-i/case4')
    TestRun.executor.run_expect_success(f'cd {repo_path} && echo "-R -p k*"'
                                        f' > afl-i/case5')

    # Run script which will launch parallel fuzzers in separate 'screen'
    # windows in the background
    TestRun.LOGGER.info('Starting fuzzing argv. This should take ' +
                        str(fuzzing_time_seconds / 60) + ' minutes')
    TestRun.executor.run(f'cd {repo_path} && ./tests/security/fuzzy/fuzz.sh '
                         'rootfs/bin/iotrace')

    # Wait for fuzzing completion and output logs
    output = wait_for_completion(fuzzing_time_seconds, repo_path)

    TestRun.LOGGER.info('Killing fuzzers')
    TestRun.executor.run(
        f'cd {repo_path} && ./tests/security/fuzzy/fuzz.sh clean')
    TestRun.executor.run_expect_success(f'rm -rf {repo_path}/afl-i')

    detect_crashes(output, "argv")
def test_fuzz_trace_file():
    fuzzing_time_seconds = 10 * 60
    iotrace: IotracePlugin = TestRun.plugins['iotrace']

    repo_path: str = f"{iotrace.working_dir}/slit-afl"

    # Make sure AFL is installed
    if not is_afl_installed():
        install_afl()

    # Create trace files
    iotrace.start_tracing()
    iotrace.stop_tracing()
    trace_repo_path = iotrace.parse_json(
        iotrace.get_trace_repository_path())[0]['path']
    trace_path = trace_repo_path + "/" + iotrace.get_latest_trace_path()
    tracefile_path = f'{trace_path}/octf.trace.0'
    copied_tracefile_path = f'{repo_path}/rootfs/var/lib/octf/trace/' + \
                            f'{iotrace.get_latest_trace_path()}/octf.trace.0'

    # Create patch file for redirecting fuzzed stdin to trace file
    new_patch_path: str = f'{iotrace.working_dir}/redirect_to_tracefile.patch'
    create_patch_redirect_fuzz_to_file(f'{copied_tracefile_path}',
                                       new_patch_path)

    # Install iotrace locally with AFL support and redirect patch
    install_iotrace_with_afl_support(new_patch_path)

    # Copy trace files to local instalation of iotrace
    TestRun.executor.run_expect_success(
        f'cp -r {trace_repo_path}/kernel '
        f'{repo_path}/rootfs/var/lib/octf/trace/')

    # Instruct the system to output coredumps as files instead of sending them
    # to a specific crash handler app
    TestRun.LOGGER.info('Setting up system for fuzzing')
    TestRun.executor.run_expect_success(
        'echo core > /proc/sys/kernel/core_pattern')
    TestRun.executor.run_expect_success(
        f'cd {repo_path} && mkdir -p afl-i afl-o')

    # Add input seed which shall be mutated
    TestRun.executor.run_expect_success(
        f'cd {repo_path} && echo "0" > afl-i/case0')

    TestRun.LOGGER.info(
        f'Starting fuzzing {tracefile_path} This should take ' +
        str(fuzzing_time_seconds / 60) + ' minutes')
    TestRun.executor.run(f'cd {repo_path} && ./tests/security/fuzzy/fuzz.sh '
                         '"rootfs/bin/iotrace --get-trace-statistics -p '
                         f'{iotrace.get_latest_trace_path()}" --one-job')
    output = wait_for_completion(fuzzing_time_seconds, repo_path)
    TestRun.executor.run(
        f'cd {repo_path} && ./tests/security/fuzzy/fuzz.sh clean')
    detect_crashes(output.stdout)
def test_fuzz_config():
    fuzzing_time_seconds = 10 * 60
    iotrace: IotracePlugin = TestRun.plugins['iotrace']

    repo_path: str = f"{iotrace.working_dir}/slit-afl"

    # Make sure AFL is installed
    if not is_afl_installed():
        install_afl()

    # Create patch file for redirecting fuzzed stdin to config file path
    new_patch_path: str = f'{iotrace.working_dir}/redirect_to_config.patch'
    create_patch_redirect_fuzz_to_file(
        f'{repo_path}/rootfs/etc/octf/octf.conf', new_patch_path)

    # Install iotrace locally with AFL support and redirect patch
    install_iotrace_with_afl_support(new_patch_path)

    # Instruct the system to output coredumps as files instead of sending them
    # to a specific crash handler app
    TestRun.LOGGER.info('Setting up system for fuzzing')
    TestRun.executor.run_expect_success(
        'echo core > /proc/sys/kernel/core_pattern')
    TestRun.executor.run_expect_success(
        f'cd {repo_path} && mkdir -p afl-i afl-o')

    # Use config as seed to be mutated
    TestRun.executor.run_expect_success(
        f'cp {repo_path}/rootfs/etc/octf/octf.conf'
        f' {repo_path}/afl-i/case0')

    TestRun.LOGGER.info('Starting fuzzing octf.conf. This should take ' +
                        str(fuzzing_time_seconds / 60) + ' minutes')

    TestRun.LOGGER.info("Trying 'list-traces' command")
    TestRun.executor.run(f'cd {repo_path} && ./tests/security/fuzzy/fuzz.sh '
                         '"rootfs/bin/iotrace -L" --one-job')
    output = wait_for_completion(fuzzing_time_seconds / 2, repo_path)
    TestRun.executor.run(
        f'cd {repo_path} && ./tests/security/fuzzy/fuzz.sh clean')
    detect_crashes(output.stdout)

    TestRun.LOGGER.info("Trying 'get-trace-repository-path' command")
    TestRun.executor.run(
        f'cd {repo_path} && ./tests/security/fuzzy/fuzz.sh '
        '"rootfs/bin/iotrace --get-trace-repository" --one-job')
    output = wait_for_completion(fuzzing_time_seconds / 2, repo_path)
    TestRun.executor.run(
        f'cd {repo_path} && ./tests/security/fuzzy/fuzz.sh clean')
    detect_crashes(output.stdout)
def test_fuzz_procfs():
    # For simplicity we start one non-instrumented iotrace instance
    # and fuzz proc files using afl with -n flag (dumb fuzzing)
    fuzzing_time_seconds = 15 * 60
    iotrace: IotracePlugin = TestRun.plugins['iotrace']

    repo_path: str = f"{iotrace.working_dir}/slit-afl"

    # Make sure AFL is installed
    if not is_afl_installed():
        install_afl()

    # Instruct the system to output coredumps as files instead of sending them
    # to a specific crash handler app
    TestRun.LOGGER.info('Setting up system for fuzzing')
    TestRun.executor.run_expect_success(
        'echo core > /proc/sys/kernel/core_pattern')
    TestRun.executor.run_expect_success(
        f'cd {repo_path} && mkdir -p afl-i afl-o')

    # Procfs files and their initial seed
    fuzzed_files = {
        "/proc/iotrace/add_device": "/dev/sdb",
        "/proc/iotrace/remove_device": "/dev/sdb",
        "/proc/iotrace/size": "1024"
    }

    # Start tracing, we start it using procfs interface by putting traced
    # device path, buffer size, and mmaping (using fio with mmap engine)
    # consumer header procfile. This is because procfiles may have a limit
    # on applications which mmap them, and iotrace -S may block other mmaps
    disk = TestRun.dut.disks[0].system_path
    TestRun.executor.run_expect_success(
        f'echo {disk} > /proc/iotrace/add_device')
    TestRun.executor.run_expect_success(f'echo 1024 > /proc/iotrace/size')
    fio_pid = TestRun.executor.run_in_background(
        f'fio --name=job --direct=0 --ioengine=mmap '
        f'--filename=/proc/iotrace/consumer_hdr.0 '
        f"--buffer_pattern=\\'/dev/urandom\\' "
        f'--time_based --runtime=30s --bs=4k '
        f'--iodepth=128 --rw=randwrite')

    # Also start some workload on traced device to generate trace traffic
    workload_pid = TestRun.executor.run_in_background(
        f'fio --direct=1'
        f'--filename={disk} '
        f'--time_based --runtime=24h --bs=4k '
        f'--iodepth=1 --rw=randwrite')

    for procfile, seed in fuzzed_files.items():
        # Create patch file for redirecting fuzzed stdin to proc file
        new_patch_path: str = f'{iotrace.working_dir}/redirect_to_procfile.patch'
        create_patch_redirect_fuzz_to_file(f'{procfile}', new_patch_path)

        # Install iotrace locally with AFL support and redirect patch
        install_iotrace_with_afl_support(new_patch_path)

        # Add input seed which shall be mutated
        TestRun.executor.run_expect_success(
            f'cd {repo_path} && echo {seed} > afl-i/case0')

        TestRun.LOGGER.info(f'Starting fuzzing {procfile} This should take ' +
                            str(fuzzing_time_seconds / 60 /
                                len(fuzzed_files)) + ' minutes')

        TestRun.executor.run_in_background(
            f'cd {repo_path} && screen -S master -d -m &&'
            f'screen -S master -X stuff "afl-fuzz -n -i '
            f'afl-i -o afl-o {repo_path}/rootfs/bin/iotrace -H\n"')
        elapsed = 0
        start_time = time.time()
        while elapsed < fuzzing_time_seconds / len(fuzzed_files):
            output = TestRun.executor.run(f'dmesg | grep -A 20 "Call Trace"')
            if output.exit_code == 0:
                save_fuzzing_output(f'{repo_path}/afl-o')
                TestRun.executor.run_expect_success('dmesg -c')
                TestRun.fail('Kernel BUGs during fuzzing procfs were found:\n'
                             f'{output.stdout}')

            time.sleep(5)
            current_time = time.time()
            elapsed = current_time - start_time

        TestRun.executor.run_expect_success(
            'killall afl-fuzz && screen -X -S master kill')

    # Stop tracing
    TestRun.executor.run_expect_success(f'kill {fio_pid}')
    TestRun.executor.run_expect_success(f'kill {workload_pid}')