コード例 #1
0
    def __init__(self, instr):
        # init attributes
        self.opcode_str = "invalid"
        self.opcode = TLULOpcode.invalid
        self.address = 0
        self.data = 0
        self.direct_in = None
        self.repeat = 1

        # Validate/Decode opcode string
        if _YAMLTags.opcode not in instr:
            print(
                red("ERROR: all YAML lines require an opcode field. ABORTING!")
            )
        self.opcode_str = str(instr[_YAMLTags.opcode])
        self.opcode = self._decode_opcode_str()

        # Check ADDRESS and DATA fields exist in YAML and convert to int
        if self.opcode == TLULOpcode.read:
            if _YAMLTags.address not in instr:
                print(
                    red("ERROR: read opcodes require an ADDRESS field. ABORTING!"
                        ))
                sys.exit(1)
            self.address = int(instr[_YAMLTags.address])
        elif self.opcode == TLULOpcode.write:
            if _YAMLTags.address not in instr:
                print(
                    red("ERROR: write opcodes require an ADDRESS field. ABORTING!"
                        ))
                sys.exit(1)
            if _YAMLTags.data not in instr:
                print(
                    red("ERROR: write opcodes require an DATA field. ABORTING!"
                        ))
                sys.exit(1)
            self.address = int(instr[_YAMLTags.address])
            self.data = int(instr[_YAMLTags.data])

        # Validata address and data fields
        self._validate_instr_field_size(_YAMLTags.address, self.address,
                                        TLULFuzzInstr.address_size)
        self._validate_instr_field_size(_YAMLTags.data, self.data,
                                        TLULFuzzInstr.data_size)

        # check if DIRECT_IN should exist in YAML and convert to int
        if TLULFuzzInstr.direct_in_size > 0:
            if _YAMLTags.direct_in not in instr:
                print(
                    red("ERROR: direct_in field required if size > 0. ABORTING!"
                        ))
            else:
                self.direct_in = int(instr[_YAMLTags.direct_in])
                self._validate_instr_field_size(_YAMLTags.direct_in,
                                                self.direct_in,
                                                TLULFuzzInstr.direct_in_size)

        # check if REPEAT field exists in YAML and convert to int
        if _YAMLTags.repeat in instr:
            self.repeat = int(instr[_YAMLTags.repeat])
コード例 #2
0
 def _load_cov_data(self, cov_type):
     cov_data_path = "%s/logs/%s_cum.csv" % (self.cov_data_path, cov_type)
     if not os.path.exists(cov_data_path):
         print(
             red("ERROR: coverage data (%s) does not exist." %
                 cov_data_path))
         sys.exit(1)
     # Load data into Pandas DataFrame
     cov_df = self._load_csv_data(cov_data_path)
     if cov_df.shape[0] < int(self.afl_data.iloc[-1, 2]):
         print(
             red("ERROR: coverage data is missing (%s). Aborting!" %
                 cov_type))
         sys.exit(1)
     # TODO(ttrippel): remove this hack after fixing run_cov_local.sh
     if cov_type == "vlt_cov":
         cov_df.drop(AFL_TEST_ID_LABEL, axis=1, inplace=True)
         cov_df.insert(0, AFL_TEST_ID_LABEL, list(range(cov_df.shape[0])))
     else:
         # Convert Test-ID labels to ints
         cov_df.loc[:,
                    AFL_TEST_ID_LABEL] = cov_df.loc[:,
                                                    AFL_TEST_ID_LABEL].apply(
                                                        FuzzingData.
                                                        _id_str_to_int)
     # Set ID column as the row indicies
     cov_df = cov_df.set_index(AFL_TEST_ID_LABEL)
     return cov_df
コード例 #3
0
 def _load_rfuzz_vlt_cov_data(self, cov_data_path):
     if not os.path.exists(cov_data_path):
         print(
             red("ERROR: coverage data (%s) does not exist." %
                 cov_data_path))
         sys.exit(1)
     # Load data into Pandas DataFrame
     cov_df = self._load_csv_data(cov_data_path)
     # Check dimensions match, i.e., no data is missing
     if cov_df.shape[0] != self.rfuzz_data.shape[0]:
         print(red("ERROR: coverage data is missing. Aborting!"))
         sys.exit(1)
     # Set ID column as the row indicies
     cov_df = cov_df.set_index(TEST_ID_LABEL)
     return cov_df
コード例 #4
0
def _check_simulation_results(encrypt_results,
                              decrypt_results,
                              test_pair,
                              verbose=False):
    error = False
    for i in range(len(test_pair.encrypt.data_in_line_starts)):
        # Extract plaintexts/ciphertexts
        with open(encrypt_results, "r") as fp:
            log_lines = fp.readlines()
            encrypt_in_data = _get_crypt_io_data_blocks(
                log_lines, test_pair.encrypt.data_in_line_starts[i],
                test_pair.encrypt.data_block_size)
            encrypt_out_data = _get_crypt_io_data_blocks(
                log_lines, test_pair.encrypt.data_out_line_starts[i],
                test_pair.encrypt.data_block_size)
        with open(decrypt_results, "r") as fp:
            log_lines = fp.readlines()
            decrypt_in_data = _get_crypt_io_data_blocks(
                log_lines, test_pair.decrypt.data_in_line_starts[i],
                test_pair.decrypt.data_block_size)
            decrypt_out_data = _get_crypt_io_data_blocks(
                log_lines, test_pair.decrypt.data_out_line_starts[i],
                test_pair.decrypt.data_block_size)
        # Check all data blocks are the same length
        if (len(encrypt_in_data) != len(encrypt_out_data)
                or len(encrypt_in_data) != len(decrypt_in_data)
                or len(encrypt_in_data) != len(decrypt_out_data)):
            error = True
            error_msg = "data LENGTH MISMATCH for encrypt/decrypt data blocks."
        if not error:
            for i in range(len(encrypt_out_data)):
                if verbose:
                    print(
                        "\n   Encrypt Out =  0x{:0>8X}; Decrypt In = 0x{:0>8X}"
                        .format(encrypt_out_data[i], decrypt_in_data[i]))
                if encrypt_out_data[i] != decrypt_in_data[i]:
                    error_msg = "encryption OUTPUT does not match decryption INPUT."
                    error = True
                    break
        if verbose:
            print("   --------------------------------------------")
        if not error:
            for i in range(len(encrypt_in_data)):
                if verbose:
                    print(
                        "   Encrypt In =  0x{:0>8X}; Decrypt Out = 0x{:0>8X}".
                        format(encrypt_in_data[i], decrypt_out_data[i]))
                if encrypt_in_data[i] != decrypt_out_data[i]:
                    error_msg = "encryption INPUT does not match decryption OUTPUT."
                    break
        if verbose:
            print("   --------------------------------------------")
        # If an error occured during any test, terminate
        if error:
            break
    # Print a color-coded message with results
    if not error:
        print(green("PASS"))
    else:
        print("".join([red("ERROR"), ": ", error_msg]))
コード例 #5
0
ファイル: fuzz.py プロジェクト: robtaylor/hw-fuzzing
def check_num_active_vm_instances(config):
  """Checks number of active VM instances on GCE as a $$$ safety measure."""
  if not config.args.silent:
    print(LINE_SEP)
    print("Checking number of active VMs on GCE ...")
    print(LINE_SEP)
  cmd = [
      "gcloud", "compute", "instances", "list",
      "--zones=%s" % config.gcp_params["zone"]
  ]
  proc = subprocess.Popen(cmd,
                          stdin=subprocess.PIPE,
                          stdout=subprocess.PIPE,
                          stderr=subprocess.STDOUT,
                          close_fds=True)
  num_active_vm_instances = -1  # first line is header
  while True:
    line = proc.stdout.readline()
    if not line:
      break
    num_active_vm_instances += 1
  if num_active_vm_instances < config.args.max_vm_instances:
    if not config.args.silent:
      print(green("%d active VM(s)" % num_active_vm_instances))
  else:
    if not config.args.silent:
      print(red("%d active VM(s)" % num_active_vm_instances))
      print(
          yellow("waiting %d seconds and trying again ..." %
                 config.args.vm_launch_wait_time_s))
  return num_active_vm_instances
コード例 #6
0
def _extract_crypt_io_log_lines(yaml_seeds_dir, yaml_seed):
    num_crypts = 0
    data_block_size = 0
    data_in_line_starts = []
    data_out_line_starts = []
    with open(os.path.join(yaml_seeds_dir, yaml_seed), "r") as ys:
        for line in ys:
            line = line.rstrip().lstrip("# ")
            if line == "TEST VARIABLES":
                ys.readline()
                # subtract three to account for other text in log
                num_crypts = _get_next_test_param(yaml_seed, ys, "NUM_CRYPTS")
                data_block_size = _get_next_test_param(yaml_seed, ys,
                                                       "DATA_BLOCK_SIZE")
                for crypt_num in range(1, num_crypts + 1):
                    data_in_line_starts.append(
                        _get_next_test_param(
                            yaml_seed, ys, "DATA_IN_LINE_START_" +
                            str(crypt_num)) - 3)
                    data_out_line_starts.append(
                        _get_next_test_param(
                            yaml_seed, ys, "DATA_OUT_LINE_START_" +
                            str(crypt_num)) - 3)
    if (num_crypts == 0 or data_block_size == 0
            or len(data_in_line_starts) == 0
            or len(data_out_line_starts) == 0):
        print(
            red("ERROR: could not retrieve test params from YAML seed (%s)." %
                yaml_seed),
            file=sys.stderr)
        sys.exit(1)
    return AESTestParams(num_crypts, data_block_size, data_in_line_starts,
                         data_out_line_starts)
コード例 #7
0
ファイル: seed_composer.py プロジェクト: robtaylor/hw-fuzzing
def dump_seed_file_to_stdin(output_file_name):
  """Dumps generated seed file in hex format to STDIN."""
  print(output_file_name + ":")
  cmd = ["xxd", output_file_name]
  try:
    subprocess.check_call(cmd)
  except subprocess.CalledProcessError:
    print(red("ERROR: cannot dump generated seed file."))
    sys.exit(1)
コード例 #8
0
 def _load_bb_data(self):
     bb_csv_file = os.path.join(self.data_path, "logs/bb_complexity.csv")
     if not os.path.exists(bb_csv_file):
         print(red("ERROR: BB CSV file (%s) not found." % bb_csv_file))
         sys.exit(1)
     # Load data into Pandas DataFrame
     df = self._load_csv_data(bb_csv_file)
     # Remove leading/trailing white space from column names
     df = df.rename(columns=lambda x: x.strip())
     return df
コード例 #9
0
 def _load_hwf_vlt_cov_data(self, cov_data_path):
     if not os.path.exists(cov_data_path):
         print(
             red("ERROR: coverage data (%s) does not exist." %
                 cov_data_path))
         sys.exit(1)
     # Load data into Pandas DataFrame
     cov_df = self._load_csv_data(cov_data_path)
     if cov_df.shape[0] < int(self.hwf_afl_data.iloc[-1, 2]):
         # print(cov_df.shape[0], int(self.hwf_afl_data.iloc[-1, 2]))
         print(
             red("WARNING: some coverage data is missing for %s" %
                 cov_data_path))
     # Convert Test-ID labels to ints
     cov_df.loc[:, TEST_ID_LABEL] = cov_df.loc[:, TEST_ID_LABEL].apply(
         FuzzingData._id_str_to_int)
     # Set ID column as the row indicies
     cov_df = cov_df.set_index(TEST_ID_LABEL)
     return cov_df
コード例 #10
0
def _get_next_test_param(yaml_seed, yaml_seed_file, expected_key):
    line = yaml_seed_file.readline()
    line_list = line.lstrip("# ").rstrip().split("=")
    key = line_list[0]
    if key != expected_key:
        print(
            red("ERROR: expected test parameter (%s) not in YAML seed (%s)." %
                (expected_key, yaml_seed)),
            file=sys.stderr)
        sys.exit(1)
    return int(line_list[1])
コード例 #11
0
ファイル: run_cmd.py プロジェクト: robtaylor/hw-fuzzing
def run_cmd(cmd, error_str, silent=False, fail_silent=False):
  """Runs the provided command (list of strings) in a separate process."""
  try:
    if not silent:
      print("Running command:")
      print(yellow(subprocess.list2cmdline(cmd)))
      subprocess.check_call(cmd)
    else:
      subprocess.check_call(cmd, stdout=subprocess.DEVNULL)
  except subprocess.CalledProcessError:
    if not fail_silent:
      print(red(error_str), file=sys.stderr)
      sys.exit(1)
コード例 #12
0
 def _load_run_time(self):
   run_time_path = "%s/logs/fuzz_time.log" % self.data_path
   if not os.path.exists(run_time_path):
     print(red("ERROR: run time data (%s) does not exist." % run_time_path))
     sys.exit(1)
   with open(run_time_path, "r") as lf:
     for line in lf:
       line = line.strip()
       if line.startswith("real"):
         line_list = line.split()
         rt_min = float(line_list[1].split("m")[0])
         rt_sec = float(line_list[1].split("m")[1].rstrip("s"))
   return ((rt_min * 60) + rt_sec)
コード例 #13
0
def _extract_test_pairs(yaml_seeds_dir, testcase=None):
    test_pairs = []
    encrypt_seeds = glob.glob(os.path.join(yaml_seeds_dir, "*encrypt*.yml"))
    decrypt_seeds = glob.glob(os.path.join(yaml_seeds_dir, "*decrypt*.yml"))
    encrypt_seeds = list(map(os.path.basename, encrypt_seeds))
    decrypt_seeds = list(map(os.path.basename, decrypt_seeds))
    encrypt_seeds.sort()
    decrypt_seeds.sort()
    if len(encrypt_seeds) != len(decrypt_seeds):
        print(red("ERROR: non-symmetric number of encrypt/decrypt seeds."),
              file=sys.stderr)
        sys.exit(1)
    for i in range(len(encrypt_seeds)):
        if testcase is not None:
            prefix = testcase.split("x")[0]
            suffix = "".join([testcase.split("x")[-1], ".yml"])
            if (not encrypt_seeds[i].startswith(prefix)
                    or not encrypt_seeds[i].endswith(suffix)):
                continue
        # Extract test details from comments in yaml file
        encrypt_test_params = _extract_crypt_io_log_lines(
            yaml_seeds_dir, encrypt_seeds[i])
        decrypt_test_params = _extract_crypt_io_log_lines(
            yaml_seeds_dir, decrypt_seeds[i])
        # Check if the test params are equivalent
        if encrypt_test_params != decrypt_test_params:
            print(red(
                "ERROR: test parameters do not match for seeds (%s and %s)." %
                (encrypt_seeds[i], decrypt_seeds[i])),
                  file=sys.stderr)
            sys.exit(1)
        # Create test objects and pair them together
        encrypt_test = AESTest("encrypt", encrypt_seeds[i],
                               encrypt_test_params)
        decrypt_test = AESTest("decrypt", decrypt_seeds[i],
                               decrypt_test_params)
        test_pairs.append(AESTestPair(encrypt_test, decrypt_test))
    return test_pairs
コード例 #14
0
 def _load_afl_data(self):
   afl_glob_path = os.path.join(self.data_path, "out", "afl_*_interactive",
                                "plot_data")
   afl_plot_data_files = glob.glob(afl_glob_path)
   if len(afl_plot_data_files) != 1:
     print(red("ERROR: AFL plot_data file no found."))
     sys.exit(1)
   # Load data into Pandas DataFrame
   afl_df = self._load_csv_data(afl_plot_data_files[0])
   # Remove leading/trailing white space from column names
   afl_df = afl_df.rename(columns=lambda x: x.strip())
   # Adjust time stamps to be relative to start time
   afl_df.loc[:, "# unix_time"] -= afl_df.loc[0, "# unix_time"]
   return afl_df
コード例 #15
0
def create_local_experiment_data_dir(config):
    """Creates local directories to store fuzzing experiment data."""
    if not config.args.silent:
        print(LINE_SEP)
        print("Creating local directories for fuzzing data ...")
        print(LINE_SEP)
    exp_data_path = "%s/data/%s" % \
        (config.root_path, config.experiment_name)

    # Create directories
    os.makedirs(exp_data_path)
    os.chmod(exp_data_path, stat.S_IRWXU | stat.S_IRGRP | stat.S_IROTH)
    os.mkdir(os.path.join(exp_data_path, "out"))
    os.chmod(os.path.join(exp_data_path, "out"),
             stat.S_IRWXU | stat.S_IRGRP | stat.S_IROTH)
    os.mkdir(os.path.join(exp_data_path, "logs"))
    os.chmod(os.path.join(exp_data_path, "logs"),
             stat.S_IRWXU | stat.S_IRGRP | stat.S_IROTH)

    # Copy over seeds that were used in this experiment
    seeds_dir = "%s/hw/%s/%s/seeds" % (config.root_path, config.soc,
                                       config.toplevel)
    seed_descripts_dir = "%s/hw/%s/%s/seed_descriptions" % (
        config.root_path, config.soc, config.toplevel)
    if os.path.isdir(seeds_dir):
        shutil.copytree(seeds_dir, os.path.join(exp_data_path, "seeds"))
        os.chmod(os.path.join(exp_data_path, "seeds"),
                 stat.S_IRWXU | stat.S_IRGRP | stat.S_IROTH)
    elif os.path.isdir(seed_descripts_dir):
        shutil.copytree(seed_descripts_dir,
                        os.path.join(exp_data_path, "seed_descriptions"))
        os.chmod(os.path.join(exp_data_path, "seed_descriptions"),
                 stat.S_IRWXU | stat.S_IRGRP | stat.S_IROTH)
    else:
        print(red("ERROR: no seeds found. Terminating experiment!"),
              file=sys.stderr)

    # Copy over HJSON config file that was used
    shutil.copy2(config.config_filename, exp_data_path)
    if not config.args.silent:
        print(green("DIRECTORY CREATION SUCCESSFUL -- Done!"))
    return exp_data_path
コード例 #16
0
    def dump_to_csv(self, csv_file_name):
        """Dump coverage dictionary to a CSV file for future analysis."""
        # Check that all columns of dict are the same length
        col_headers = list(self.coverage_dict.keys())
        num_rows = len(self.coverage_dict[col_headers[0]])
        for col_header in col_headers:
            if num_rows != len(self.coverage_dict[col_header]):
                print(red("ERROR: table dimension mismatch. Aborting!"))
                # Fail silently, we don't want to throw away fuzzing results for a
                # post-processing error.
                sys.exit()

        with open(csv_file_name, "w", newline="") as csv_file:
            csv_writer = csv.writer(csv_file)
            # Write CSV column headers
            col_headers = self.coverage_dict.keys()
            csv_writer.writerow(col_headers)
            for row_index in range(num_rows):
                # craft row list
                row_list = []
                for col in col_headers:
                    row_list.append(self.coverage_dict[col][row_index])
                # write row list to file
                csv_writer.writerow(row_list)
コード例 #17
0
def _main():
  num_experiments = len(NUM_STATES) * len(COMP_WIDTHS) * len(RUNS) * len(
      EXPERIMENT_BASE_NAMES)
  print(LINE_SEP)
  print(LINE_SEP)
  print(LINE_SEP)
  print(green("LAUNCHING %d EXPERIMENTS ..." % num_experiments))
  print(LINE_SEP)
  print(LINE_SEP)
  print(LINE_SEP)

  # create a temp dir to store config files
  try:
    tmp_dir = os.path.join(os.getcwd(), "tmp%d")
    i = 0
    while os.path.isdir(tmp_dir % i):
      i += 1
    tmp_dir = tmp_dir % i
    os.mkdir(tmp_dir)

    # create config files on the fly and launch experiments
    for experiment_base_name in EXPERIMENT_BASE_NAMES:
      for states in NUM_STATES:
        for width in COMP_WIDTHS:
          for run in RUNS:
            # craft config dictionary
            cdict = copy.deepcopy(CONFIG_DICT)

            # Set experiment name
            experiment_name = experiment_base_name % (states, width, run)
            cdict["experiment_name"] = experiment_name

            # Set test bench
            if "wopt" in experiment_name:
              cdict["tb"] = "afl_opt"
            else:
              cdict["tb"] = "afl"

            # Set instrumentation amount
            if "full-instr" in experiment_name:
              cdict["instrument_dut"] = 1
              cdict["instrument_tb"] = 1
              cdict["instrument_vltrt"] = 1
            elif "duttb-instr" in experiment_name:
              cdict["instrument_dut"] = 1
              cdict["instrument_tb"] = 1
              cdict["instrument_vltrt"] = 0
            elif "dut" in experiment_name:
              cdict["instrument_dut"] = 1
              cdict["instrument_tb"] = 0
              cdict["instrument_vltrt"] = 0
            else:
              print(red("ERROR: invalid instrumentation config. ABORTING!"))
              sys.exit(1)

            # Set lock size
            cdict["hdl_gen_params"]["num_lock_states"] = states
            cdict["hdl_gen_params"]["lock_comp_width"] = width

            # write to HJSON file
            hjson_filename = experiment_name + ".hjson"
            hjson_file_path = os.path.join(tmp_dir, hjson_filename)
            with open(hjson_file_path, "w") as fp:
              hjson.dump(cdict, fp)

            # launch fuzz the DUT
            fuzz(["--fail-silently", hjson_file_path])

            # cleanup config file
            os.remove(hjson_file_path)

  finally:
    # remove temp dir
    for tmp_dir in glob.glob("tmp*"):
      shutil.rmtree(tmp_dir, ignore_errors=True)

  print(LINE_SEP)
  print(LINE_SEP)
  print(LINE_SEP)
  print(green("DONE!"))
  print(LINE_SEP)
  print(LINE_SEP)
  print(LINE_SEP)
コード例 #18
0
 def _validate_instr_field_size(self, field, value, size):
     if value >= 2**(size * 8):
         print(
             red("ERROR: instruction field (%s) larger than size. ABORTING!"
                 % field))
         sys.exit(1)
コード例 #19
0
ファイル: fuzz.py プロジェクト: robtaylor/hw-fuzzing
def _sigint_handler(sig, frame):
  print(red("\nTERMINATING EXPERIMENT!"))
  sys.exit(0)
コード例 #20
0
ファイル: fuzz.py プロジェクト: robtaylor/hw-fuzzing
def _abort(abort_msg):
  print(red(abort_msg), file=sys.stderr)
  sys.exit(1)