Add tf_fuzz tool
This is fully derived from tf-m repo.
Signed-off-by: Karl Zhang <karl.zhang@arm.com>
Change-Id: I8d35e70eda9081af66d8fa3f3cb4beb1d953060e
diff --git a/tf_fuzz/tf_fuzz.hpp b/tf_fuzz/tf_fuzz.hpp
new file mode 100644
index 0000000..ce9051f
--- /dev/null
+++ b/tf_fuzz/tf_fuzz.hpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef TF_FUZZ_HPP
+#define TF_FUZZ_HPP
+
+#include <string>
+#include <vector>
+#include <iostream>
+#include <fstream>
+
+
+/* This project's header files #including other project headers quickly becomes
+ unrealistically complicated. The only solution is for each .cpp to include
+ the headers it needs.
+#include "psa_call.hpp"
+#include "sst_asset.hpp"
+#include "crypto_asset.hpp"
+#include "boilerplate.hpp"
+*/
+
+/* Shortcuts, to reduce code clutter, and reduce risk of coding errors. */
+#define IVM(content) if(rsrc->verbose_mode){content} // IVM = "If Verbose Mode"
+#define IV(content) if(verbose_mode){content} // Same, but for use by tf_fuzz methods
+
+
+// consts to help readability:
+const bool add_to_end = true; // add a call to the end of the call vector
+const bool add_random_after_barrier = false;
+ /* add to the call list randomly after the latest barrier for this asset, and
+ as late as the end of the list. */
+const bool yes_set_barrier = true; // create the call and set a barrier for that asset
+const bool dont_set_barrier = false;
+ // inserted call does not preclude calls related to that asset being placed earlier
+
+using namespace std;
+
+// class tf_fuzz_info mostly just groups together everything needed generate the test.
+class tf_fuzz_info
+{
+ /* In creating a test, TF-Fuzz parses the test template, creating a vector of
+ PSA-call-tracker objects. TF-Fuzz then performs a simulation of those calls
+ -- simulation only in enough detail to predict expected results of those PSA
+ calls. After that simulation phase, write_test() writes it all out. The
+ process of creating these structures also requires the boilerplate text
+ strings. */
+
+public:
+ // Data members (this class is mostly just to group stuff together, so public):
+ vector<string> prep_code; // variable declarations to write out to test file
+ vector<psa_call*> calls;
+ /* the calls to perform: Note: must be vector *psa_call; a vector of
+ psa_call does not allow (run-time) polymorphism. */
+ boilerplate *bplate; // the boilerplate text for building the test
+ gibberish gibbergen; // the gibberish asset-data generator
+ crc32 hashgen; // simple 32-bit LFSR-based hashing generator
+ /* Note: The following asset-lists are kept in base-class type to allow a
+ common template-line processing function in tf_fuzz_grammar.y. */
+ vector<psa_asset*> active_sst_asset; // list of known and usable SST assets
+ vector<psa_asset*> deleted_sst_asset; // deleted SST assets
+ vector<psa_asset*> invalid_sst_asset; // SST assets with invalid attributes
+ vector<psa_asset*> active_key_asset; // list of known and usable keys
+ vector<psa_asset*> deleted_key_asset; // deleted keys
+ vector<psa_asset*> invalid_key_asset; // keys with invalid attributes
+ vector<psa_asset*> active_policy_asset; // list of known, usable policies
+ vector<psa_asset*> deleted_policy_asset; // deleted policies
+ vector<psa_asset*> invalid_policy_asset; // policies with invalid attrs
+ /* The "variable" vector tracks variables in the generated code. Actually,
+ it tracks variables explicitly named in the test template, and actual-data
+ holder variables from reading an asset. It does not track asset set-data
+ or asset expect-data variables, because there are multiple versions of
+ those, and it's easier to just to "count off" those multiple versions.
+ Notice that, unlike the above vectors, the variable vector is not a
+ vector of pointers to variable_info objects, but of the objects themselves.
+ This is because polymorphism is not of concern here. */
+ vector<variable_info> variable;
+ string test_purpose; // what the test tests
+ long rand_seed; // the original random seed, whether passed in or defaulted
+ string template_file_name, test_output_file_name;
+ FILE *template_file;
+ /* handle to the test-template input file. Unfortunately I can't seem to
+ get lex/yacc to understand C++ file references, probably because I'm
+ "extern C"ing the Lex content (Yacc/Bison turns out to be a lot easier
+ to coerce into generating C++ code than (F)Lex). */
+ ofstream output_C_file; // handle to the output C test file
+ bool verbose_mode; // true to "think aloud"
+ bool include_hashing_code; // true to instantiate the hashing code
+ // Methods:
+ asset_search 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, // 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 asset
+ );
+ asset_search 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, // 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
+ );
+ asset_search find_or_create_policy_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 asset
+ );
+ asset_search 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
+ );
+ vector<variable_info>::iterator find_var (string var_name);
+ void parse_cmd_line_params (int argc, char* argv[]);
+ // parse command-line parameters, and open files
+ void add_call (psa_call *the_call, bool to_end, bool set_barrier_bool);
+ /* stuffs a new call into the call list, either sequentially or at a random
+ place after a "barrier" for that particular asset. If set_barrier_bool
+ is true, it will prevent calls related to this asset from going before
+ this call. */
+ bool make_var (string var_name);
+ void simulate_calls (void);
+ // goes through generated calls calculating expected results
+ void write_test (void); // writes out the test's .c file
+ void teardown_test(void); // removes any PSA resources used in the test
+ tf_fuzz_info (void); // (constructor)
+ ~tf_fuzz_info (void);
+
+protected:
+ // Data members:
+ vector<string> teardown_calls;
+ // list of PSA commands to remove assets left over upon test completion
+ // Methods:
+
+private:
+ // Data members:
+ // Methods:
+};
+
+
+/*--------------------------------------------------------------
+ Helper functions:
+--------------------------------------------------------------*/
+
+
+template<typename CALL_TYPE>
+void define_call (set_data_info set_data, bool random_data, bool fill_in_template,
+ bool create_call, template_line *temLin, tf_fuzz_info *rsrc,
+ bool to_end_bool, bool set_barrier_bool) {
+ CALL_TYPE *the_call;
+ gibberish gib;
+ char gib_buff[1000];
+ string t_string;
+
+ if (fill_in_template) {
+ if (set_data.literal_data_not_file) {
+ if (random_data) {
+ int rand_data_length = 12 + (rand() % 800);
+ gib.sentence (gib_buff, gib_buff + rand_data_length - 1);
+ t_string = gib_buff;
+ temLin->set_data.set_calculated (t_string);
+ }
+ } else {
+ if (set_data.file_path == "") { // catch the most likely failure at least!
+ cerr << "Error: Tool-internal: Please report error "
+ << "#407 to the TF-Fuzz developers." << endl;
+ exit(407);
+ }
+ temLin->set_data.set_file (set_data.file_path);
+ // set in sst_asset_make_file_path
+ }
+ }
+ if (create_call) {
+ the_call = new CALL_TYPE (rsrc, temLin->call_ser_no,
+ temLin->asset_info.how_asset_found);
+ if (!temLin->copy_template_to_call (the_call)) {
+ cerr << "Error: Tool-internal: Please report error "
+ << "#402 to the TF-Fuzz developers." << endl;
+ exit(402);
+ }
+ rsrc->add_call (the_call, to_end_bool, set_barrier_bool);
+ }
+}
+
+#endif // #ifndef TF_FUZZ_HPP