diff options
Diffstat (limited to 'tools/tf_fuzz/tf_fuzz.cpp')
-rw-r--r-- | tools/tf_fuzz/tf_fuzz.cpp | 512 |
1 files changed, 0 insertions, 512 deletions
diff --git a/tools/tf_fuzz/tf_fuzz.cpp b/tools/tf_fuzz/tf_fuzz.cpp deleted file mode 100644 index 57ae836a3d..0000000000 --- a/tools/tf_fuzz/tf_fuzz.cpp +++ /dev/null @@ -1,512 +0,0 @@ -/* - * Copyright (c) 2019-2020, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#include <ctime> // to seed random, if seed not passed in -#include <string> -#include <vector> -#include <iostream> -#include <cstdlib> // for srand() and rand() -#include <cstdio> // for template lex&yacc input file -#include "class_forwards.hpp" -#include "boilerplate.hpp" -#include "gibberish.hpp" -#include "compute.hpp" -#include "string_ops.hpp" -#include "data_blocks.hpp" -#include "psa_asset.hpp" -#include "find_or_create_asset.hpp" -#include "template_line.hpp" -#include "tf_fuzz.hpp" -#include "sst_asset.hpp" -#include "crypto_asset.hpp" -#include "psa_call.hpp" -#include "tf_fuzz_grammar.tab.hpp" -#include "variables.hpp" - - -extern FILE* yyin; // telling lex&yacc which file to parse - -using namespace std; - -long psa_asset::unique_id_counter = 10; // counts unique IDs for assets -long psa_call::unique_id_counter = 10; // counts unique IDs for assets - /* FYI: Must initialize these class variables outside the class. If - initialized inside the class, g++ requires they be const. */ - -/********************************************************************************** - Methods of class tf_fuzz_info follow: -**********************************************************************************/ - -asset_search tf_fuzz_info::find_or_create_sst_asset ( - psa_asset_search criterion, // what to search on - psa_asset_usage where, // where to search - string target_name, // ignored if not searching on name - uint64_t target_id, // also ignored if not searching on ID (e.g., SST UID) - long &serial_no, // search by asset's unique serial number - bool create_asset, // true to create the asset if it doesn't exist - vector<psa_asset*>::iterator &asset // returns a pointer to requested asset -) { - return generic_find_or_create_asset<sst_asset>( - active_sst_asset, deleted_sst_asset, - invalid_sst_asset, criterion, where, target_name, target_id, - serial_no, create_asset, asset - ); -} - -asset_search tf_fuzz_info::find_or_create_key_asset ( - psa_asset_search criterion, // what to search on - psa_asset_usage where, // where to search - string target_name, // ignored if not searching on name - uint64_t target_id, // also ignored if not searching on ID (e.g., SST UID) - long &serial_no, // search by asset's unique serial number - bool create_asset, // true to create the asset if it doesn't exist - vector<psa_asset*>:: iterator &asset // returns iterator to requested asset -) { - return generic_find_or_create_asset<key_asset>( - active_key_asset, deleted_key_asset, - invalid_key_asset, criterion, where, target_name, target_id, - serial_no, create_asset, asset - ); -} - -asset_search tf_fuzz_info::find_or_create_policy_asset ( - psa_asset_search criterion, // what to search on - psa_asset_usage where, // where to search - string target_name, // ignored unless searching on name - uint64_t target_id, // also ignored unless searching on ID (e.g., SST UID) - long &serial_no, // search by asset's unique serial number - bool create_asset, // true to create the asset if it doesn't exist - vector<psa_asset*>::iterator &asset // iterator to requested asset -) { - return generic_find_or_create_asset<policy_asset>( - active_policy_asset, deleted_policy_asset, - invalid_policy_asset, criterion, where, target_name, target_id, - serial_no, create_asset, asset - ); -} - -asset_search tf_fuzz_info::find_or_create_psa_asset ( - psa_asset_type asset_type, // what type of asset to find - psa_asset_search criterion, // what to search on - psa_asset_usage where, // where to search - string target_name, // ignored if not searching on name - uint64_t target_id, // also ignored if not searching on ID (e.g., SST UID) - long &serial_no, // search by asset's unique serial number - bool create_asset, // true to create the asset if it doesn't exist - vector<psa_asset*>::iterator &asset // returns iterator to asset -) { - switch (asset_type) { - case psa_asset_type::sst: - return find_or_create_sst_asset ( - criterion, where, target_name, target_id, - serial_no, create_asset, asset); - break; - case psa_asset_type::key: - return find_or_create_key_asset ( - criterion, where, target_name, target_id, - serial_no, create_asset, asset); - break; - case psa_asset_type::policy: - return find_or_create_policy_asset ( - criterion, where, target_name, target_id, - serial_no, create_asset, asset); - break; - default: - cerr << "\nError: Internal: Please report error " - << "#1503 to TF-Fuzz developers." << endl; - exit (1500); - } -} - -// Return an iterator to a variable, if it exists. If not return variable.end(). -vector<variable_info>::iterator tf_fuzz_info::find_var (string var_name) -{ - vector<variable_info>::iterator the_var; - if (variable.empty()) { - return variable.end(); - } - for (the_var = variable.begin(); the_var < variable.end(); the_var++) { - if (the_var->name == var_name) { - break; - } - } - return the_var; -} -// Add a variable to the vector if not already there; return true if already there. -bool tf_fuzz_info::make_var (string var_name) -{ - bool found = false; - variable_info new_variable; - - found = (find_var (var_name) != variable.end()); - if (!found) { - new_variable.name.assign (var_name); - variable.push_back (new_variable); - } - return found; -} - - -// Remove any PSA resources used in the test. Returns success==true, fail==false. -void tf_fuzz_info::teardown_test (void) -{ - string call; - // Traverse through the SST-assets list, writing out remove commands: - for (auto &asset : active_sst_asset) { - // It turns out you're not allowed to remove "WRITE_ONCE" assets: - if ( asset->set_data.flags_string.find("PSA_STORAGE_FLAG_WRITE_ONCE") - == string::npos - ) { - call = bplate->bplate_string[teardown_sst]; - find_replace_1st ("$uid", to_string(asset->asset_info.id_n), call); - call.append (bplate->bplate_string[teardown_sst_check]); - output_C_file << call; - } - } - // Same, but with key assets: - for (auto &asset : active_key_asset) { - call = bplate->bplate_string[teardown_key]; - find_replace_1st ("$handle", asset->handle_str, call); - call.append (bplate->bplate_string[teardown_key_check]); - output_C_file << call; - } -} - -// Write out the test itself. -void tf_fuzz_info::write_test (void) -{ - string call; - string work = bplate->bplate_string[preamble_A]; // a temporary workspace string - - // The test file should be open before calling this method. - // Spit out the obligatory preamble: - find_replace_all ("$purpose", test_purpose, work); - output_C_file << work; - - // If using hashing, then spit out the hashing functions: - if (include_hashing_code) { - work = bplate->bplate_string[hashing_code]; - output_C_file << work; - } - - // Print out the second part of the preamble code: - work = bplate->bplate_string[preamble_B]; - find_replace_all ("$purpose", test_purpose, work); - output_C_file << work; - - output_C_file << " /* Variables (etc.) to initialize and check PSA " - << "assets: */" << endl; - for (auto call : calls) { - // Reminder: calls is a vector of *pointers to* psa_call subclass objects. - call->fill_in_prep_code(); - call->write_out_prep_code (output_C_file); - } - - // Print out the final part of the preamble code: - work = bplate->bplate_string[preamble_C]; - find_replace_all ("$purpose", test_purpose, work); - output_C_file << work; - - output_C_file << "\n\n /* PSA calls to test: */" << endl; - for (auto call : calls) { - call->fill_in_command(); // (fills in check code too) - call->write_out_command (output_C_file); - call->write_out_check_code (output_C_file); - } - - output_C_file << "\n\n /* Removing assets left over from testing: */" - << endl; - teardown_test(); - - // Seal the deal: - output_C_file << bplate->bplate_string[closeout]; - - // Close the template and test files: - output_C_file.close(); - fclose (template_file); -} - - -/* simulate_calls() goes through the vector of generated calls calculating expected - results for each. */ -void tf_fuzz_info::simulate_calls (void) -{ - bool asset_state_changed = false; - - IV(cout << "Call sequence:" << endl;) - /* For now, much of the simulation "thinking" infrastructure is here for future - elaboration. The algorithm is to through each call one by one, copying - information to the asset in question. Then each currently-active asset is - allowed to react to that information until they all agree that they're - "quiescent." Finally, result information is copied from the asset back to - the call. */ - for (auto this_call : calls) { - IV(cout << " " << this_call->call_description << " for asset " - << this_call->asset_info.get_name() << endl;) - this_call->copy_call_to_asset(); - /* Note: this_call->the_asset will now point to the asset - associated with this_call, if any such asset exists. */ - if (this_call->asset_info.the_asset != nullptr) { - /* If the asset exists, allow changes to it to affect other active - assets. */ - asset_state_changed = false; - do { - for (auto this_asset : active_sst_asset) { - asset_state_changed |= this_asset->simulate(); - } - for (auto this_asset : active_policy_asset) { - asset_state_changed |= this_asset->simulate(); - } - for (auto this_asset : active_key_asset) { - asset_state_changed |= this_asset->simulate(); - } - } while (asset_state_changed); - } - this_call->copy_asset_to_call(); - } -} - - -/* Parse command-line parameters. exit() if error(s) found. Place results into - the resource object. */ -void tf_fuzz_info::parse_cmd_line_params (int argc, char* argv[]) -{ - int exit_val = 0; // the linux return value, default 0, meaning all-good - vector<string> cmd_line_parameter, cmd_line_switch; - // (STL) vectors of hard cmd_line_parameter and cmd_line_switches - int n_parameters = 0, n_switches = 0; - // counting off cmd_line_parameter and cmd_line_switches while parsing - char testc; - - // Parse arguments into lists of strings: - for (int i = 1; i < argc; ++i) { - if (argv[i][0] == '-') { // cmd_line_switch - if (argv[i][1] == '-') { // double-dash - cmd_line_switch.push_back (string(argv[i]+2)); - } else { // single-dash cmd_line_switch; fine either way - cmd_line_switch.push_back (string(argv[i]+1)); - } - ++n_switches; - } else { // hard cmd_line_parameter - cmd_line_parameter.push_back(argv[i]); - ++n_parameters; - } - } - // If too-few or too many cmd_line_parameter supplied - for (int i = 0; i < n_switches; ++i) { - // If usage string requested... - if (cmd_line_switch[i] == "h") { - exit_val = 10; - } - // If verbose requested, make note: - if (cmd_line_switch[i] == "v") { - verbose_mode = true; - } - } - if (exit_val == 10) { // -h switch - cout << "\nHow to run TF-Fuzz:" << endl; - } else if (n_parameters < 2) { - cerr << "\nToo few command-line parameters." << endl; - exit_val = 11; - } else if (n_parameters > 3) { - cerr << "\nToo many command-line parameters." << endl; - exit_val = 12; - } else { - template_file_name = cmd_line_parameter[0]; - template_file = fopen (template_file_name.c_str(), "r"); - test_output_file_name = cmd_line_parameter[1]; - output_C_file.open (test_output_file_name, ios::out); - if (n_parameters == 3) { - /* TODO: The try-catch below doesn't always seem to work. For now, - manually "catch" the most basic problem: */ - testc = cmd_line_parameter[2][0]; - if (testc < '0' || testc > '9') { - cerr << "\nError: Random-seed value (third parameter) could " - << "not be interpreted as a number." << endl; - rand_seed = 0; - } else { - try { - rand_seed = stol (cmd_line_parameter[2], 0, 0); - } catch (int excep) { - excep = 0; // (keep compiler from complaining about not using excep) - cerr << "\nWarning: Random-seed value (third parameter) could " - << "not be interpreted as a number." << endl; - rand_seed = 0; - } - } - } - if (rand_seed == 0 || n_parameters < 3) { - if (n_parameters < 3) { - cout << "Info: random seed was not specified." << endl; - } else { - cout << "Warning: random seed, " << cmd_line_parameter[2] - << ", was not usable!" << endl; - } - srand((unsigned int) time(0)); // TODO: ideally, XOR or add in PID# - rand_seed = rand(); - /* doesn't really matter, but it just "feels better" when the - default seed value is itself more random. */ - } - cout << endl << "Using seed value of " << dec << rand_seed << " " << hex - << "(0x" << rand_seed << ")." << endl; - srand(rand_seed); - if (template_file == NULL) { - cerr << "\nError: Template file " << template_file_name - << " could not be opened." << endl; - exit_val = 13; - } else if (!output_C_file.is_open()) { - // If test-output file couldn't be opened - cerr << "\nError: Output C test file " << test_output_file_name - << " could not be opened." << endl; - exit_val = 14; - } - // Default (not entirely worthless) purpose of the test: - test_purpose.assign ( "template = " + template_file_name + ", seed = " - + to_string(rand_seed)); - } - // Bad command line, or request for usage blurb, so tell them how to run us: - if (exit_val != 0) { - cout << endl << argv[0] << " usage:" << endl; - cout << " Basic cmd_line_parameter (positional, in order, " - << "left-to-right):" << endl; - cout << " Test-template file" << endl; - cout << " Test-output .c file" << endl; - cout << " (optional) random seed value" << endl; - cout << " Optional switches:" << endl; - cout << " -h or --h: This help (command-line usage) summary." - << endl; - cout << " -v or --v: Verbose mode." << endl; - cout << "Examples:" << endl; - cout << " " << argv[0] << " -h" << endl; - cout << " " << argv[0] << " template.txt output_test.c 0x5EED" << endl; - exit (exit_val); - } -} - - -void tf_fuzz_info::add_call (psa_call *the_call, bool append_bool, - bool set_barrier_bool) { - // For testing purposes only, uncomment this to force sequential ordering: - //append_bool = true; - vector<psa_call*>::size_type - barrier_pos = 0, - // barrier pos. before which calls for this asset may not be placed - insert_call_pos = 0, // where to place the new call - i; // loop index - bool barrier_found = false; - psa_call *candidate = nullptr; // (not for long) - - if (set_barrier_bool) { - // Prevent calls regarding this asset being placed before this call: - the_call->barrier.assign (the_call->target_barrier); - IV(cout << "Inserted barrier for asset " << the_call->barrier << "." << endl;) - } - if (append_bool || calls.size() == 0) { - // Just .push_back() onto the end if asked to, or if this is the first call: - calls.push_back (the_call); - IV(cout << "Appended to end of call sequence: " << the_call->call_description - << "." << endl;) - return; // done, easy! - } - /* Now search for last call with a barrier for this asset. (Note: because - vector<psa_call*>::size_type is unsigned, we can't search backward from - .end(), decrementing past 0. Also, cannot initialize barrier_pos to -1; - must maintain boolean for that.) */ - for (i = 0ULL, barrier_found = false; i < calls.size(); i++) { - candidate = calls[i]; - if (candidate->barrier == the_call->target_barrier) { - barrier_pos = i; - barrier_found = true; - } - } - if (!barrier_found) { - /* STL-vector inserts occur *before* the stated index. With no barrier - found, we want to insert somewhere between before .begin() and after - .end(). So, we want a number between 0 and calls.size(), inclusive. */ - insert_call_pos = (rand() % (calls.size() + 1)); - IV(cout << "No barrier for asset " << the_call->asset_info.get_name() - << " found." << endl - << " Placing " << the_call->call_description - << " at position " << insert_call_pos << " in call sequence." - << endl;) - } else { - /* Insert at a random point between just after barrier and after the end - (including possibly after the end, but strictly after that barrier). - Since STL-vector inserts occur before the stated index, we want an - insertion point between the call after the barrier and calls.end(), - inclusive. */ - insert_call_pos = (vector<psa_call*>::size_type) - ( barrier_pos + 1 // must be *after* barrier-carrying call - + (rand() % (calls.size() - barrier_pos)) - ); - IV(cout << "Barrier for asset " << the_call->asset_info.get_name() - << " found at position " << dec << barrier_pos << "." << endl;) - } - if (insert_call_pos == calls.size()) { - // Insert at end: - calls.push_back (the_call); - IV(cout << "Insertion position is at end of call list." << endl;) - } else { - // Insert before insert_call_position: - calls.insert (calls.begin() + insert_call_pos, the_call); - IV(cout << "Inserting " << the_call->call_description - << " at position " << dec << insert_call_pos << " in call sequence." - << endl;) - } -} - - -tf_fuzz_info::tf_fuzz_info (void) // (constructor) -{ - this->bplate = new boilerplate(); - test_purpose = template_file_name = test_output_file_name = ""; - rand_seed = 0; - verbose_mode = false; - include_hashing_code = false; // default -} - -tf_fuzz_info::~tf_fuzz_info (void) -{ - delete bplate; -} - -/********************************************************************************** - End of methods of class tf_fuzz_info. -**********************************************************************************/ - - -int main(int argc, char* argv[]) -{ - cout << "Trusted Firmware Fuzzer (TF-Fuzz) starting..." << endl << endl; - - // Allocate "the world": - tf_fuzz_info *rsrc = new tf_fuzz_info; - - // Parse parameters and open files: - rsrc->parse_cmd_line_params (argc, argv); - - // Parse the test-template file: - yyin = rsrc->template_file; - int parse_result = yyparse (rsrc); - - if (parse_result == 1) { - cerr << "\nError: Template file has errors." << endl; - } else if (parse_result == 2) { - cerr << "\nError: Sorry, TF-Fuzz ran out of memory." << endl; - } - cout << "Call sequence generated." << endl; - - cout << "Simulating call sequence..." << endl; - rsrc->simulate_calls(); - - cout << "Writing test file, " << rsrc->test_output_file_name << "." << endl; - rsrc->write_test(); - rsrc->output_C_file.close(); - - cout << endl << "TF-Fuzz test generation complete." << endl; - return 0; -} |