The contents of an existing database file can be extracted with the -E option. By default the top level of the directory tree is rmc_db_dump, an alternative path can be specified with the -o option. The file blobs corresponding to a given record will be saved in a separate sub-directory. The sub-directory name of each record is the signature corresponding to the fingerprint for that record with all non-alphanumeric characters stripped.
Example: ./src/rmc -E -d rmc.db -o output/directory/ Successfully extracted rmc.db Signed-off-by: Todor Minchev <todor.minc...@linux.intel.com> --- inc/rmc_api.h | 9 +++++ inc/rmcl.h | 7 ++++ src/lib/api.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++- src/lib/common/rmcl.c | 17 +++++++- src/rmc.c | 30 +++++++++----- 5 files changed, 157 insertions(+), 12 deletions(-) diff --git a/inc/rmc_api.h b/inc/rmc_api.h index a484389..2f8c978 100644 --- a/inc/rmc_api.h +++ b/inc/rmc_api.h @@ -109,6 +109,15 @@ extern int read_file(const char *pathname, char **data, rmc_size_t* len); */ int write_file(const char *pathname, void *data, rmc_size_t len, int append); +/* extract the contents of a database file and store the files corresponding to + * each record in a separate directory. The name of each directory is the signature + * of the fingerpring for that record with all non-alphanumeric characters stripped + * (in) db_pathname: The path and file name of a RMC database file generated by RMC tool + * (in) output_path: A directory path to extract the database to + * return: 0 on success, non-zero on failure. + */ +int dump_db(char *db_pathname, char *output_path) ; + #else /* 2 - API for UEFI context */ diff --git a/inc/rmcl.h b/inc/rmcl.h index 5bbad42..471ebfe 100644 --- a/inc/rmcl.h +++ b/inc/rmcl.h @@ -164,4 +164,11 @@ extern int rmcl_generate_db(rmc_record_file_t *record_files, rmc_uint8_t **rmc_d */ extern int query_policy_from_db(rmc_fingerprint_t *fingerprint, rmc_uint8_t *rmc_db, rmc_uint8_t type, char *blob_name, rmc_file_t *policy); +/* + * Check if db_blob has a valid rmc database signature + * + * return 0 if db_blob has a valid signature or non-zero otherwise + */ +int is_rmcdb(rmc_uint8_t *db_blob); + #endif /* INC_RMCL_H_ */ diff --git a/src/lib/api.c b/src/lib/api.c index 0adb390..56746a4 100644 --- a/src/lib/api.c +++ b/src/lib/api.c @@ -3,6 +3,7 @@ * RMC API implementation for Linux user space */ +#define _GNU_SOURCE #include <stdio.h> #include <unistd.h> #include <errno.h> @@ -10,12 +11,15 @@ #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> +#include <dirent.h> +#include <ctype.h> #include <rmcl.h> #include <rsmp.h> -#define EFI_SYSTAB_PATH "/sys/firmware/efi/systab" -#define SYSTAB_LEN 4096 /* assume 4kb is enough...*/ +#define EFI_SYSTAB_PATH "/sys/firmware/efi/systab" +#define SYSTAB_LEN 4096 /* assume 4kb is enough...*/ +#define DB_DUMP_DIR "./rmc_db_dump" /* directory to store db data dump */ int read_file(const char *pathname, char **data, rmc_size_t* len) { int fd = -1; @@ -325,3 +329,101 @@ int rmc_gimme_file(char* db_pathname, char *file_name, rmc_file_t *file) { return ret; } + +void remove_non_alphanum(char *in) { + char c; + unsigned long i = 0, j = 0; + + while ((c = in[i++]) != '\0'){ + if (isalnum(c)) + in[j++] = c; + } + in[j] = '\0'; +} + +int dump_db(char *db_pathname, char *output_path) { + rmc_meta_header_t meta_header; + rmc_db_header_t *db_header = NULL; + rmc_record_header_t record_header; + rmc_uint64_t record_idx = 0; /* offset of each reacord in db*/ + rmc_uint64_t meta_idx = 0; /* offset of each meta in a record */ + rmc_uint64_t file_idx = 0; /* offset of file in a meta */ + rmc_file_t file; + char *out_dir = NULL, *out_name = NULL, *cmd = NULL, *tmp_dir_name = NULL; + rmc_size_t db_len = 0; + rmc_uint8_t *rmc_db = NULL; + DIR *tmp_dir = NULL; + + if (read_file(db_pathname, (char **)&rmc_db, &db_len)) { + fprintf(stderr, "Failed to read database file\n\n"); + return 1; + } + + db_header = (rmc_db_header_t *)rmc_db; + + /* sanity check of db */ + if (is_rmcdb(rmc_db)) + return 1; + + /* query the meta. idx: start of record */ + record_idx = sizeof(rmc_db_header_t); + while (record_idx < db_header->length) { + memcpy(&record_header, rmc_db + record_idx, + sizeof(rmc_record_header_t)); + + /* directory name is fingerprint signature with stripped special chars*/ + asprintf(&tmp_dir_name, "%s", record_header.signature.raw); + remove_non_alphanum(tmp_dir_name); + if(output_path) + asprintf(&out_dir, "%s/%s/", output_path, tmp_dir_name); + else + asprintf(&out_dir, "%s/%s/", DB_DUMP_DIR, tmp_dir_name); + if ((tmp_dir = opendir(out_dir))) { + /* Directory exists */ + closedir(tmp_dir); + free(tmp_dir_name); + } else if (ENOENT == errno) { + /* Directory does not exist, try to create it. */ + asprintf(&cmd, "mkdir -p %s", out_dir); + if(system(cmd) == -1) { + fprintf(stderr, "Failed to create %s directory\n\n", out_dir); + free(out_dir); + free(tmp_dir_name); + free(cmd); + return 1; + } + free(cmd); + } else { + /* Some other error occured */ + free(out_dir); + free(tmp_dir_name); + free(cmd); + return 1; + } + + /* find meta */ + for (meta_idx = record_idx + sizeof(rmc_record_header_t); + meta_idx < record_idx + record_header.length;) { + memcpy(&meta_header, rmc_db + meta_idx, sizeof(rmc_meta_header_t)); + file_idx = meta_idx + sizeof(rmc_meta_header_t); + rmc_ssize_t name_len = strlen((char *)&rmc_db[file_idx]) + 1; + file.blob = &rmc_db[file_idx + name_len]; + file.blob_len = meta_header.length - sizeof(rmc_meta_header_t) - + name_len; + file.next = NULL; + file.type = RMC_GENERIC_FILE; + asprintf(&out_name, "%s%s", out_dir, (char *)&rmc_db[file_idx]); + /* write file to dump directory */ + if (write_file((const char *)out_name, file.blob, file.blob_len, 0)) + return 1; + + /* next meta */ + meta_idx += meta_header.length; + free(out_name); + } + /* next record */ + record_idx += record_header.length; + free(out_dir); + } + return 0; +} diff --git a/src/lib/common/rmcl.c b/src/lib/common/rmcl.c index 67622a0..58a4a52 100644 --- a/src/lib/common/rmcl.c +++ b/src/lib/common/rmcl.c @@ -193,6 +193,21 @@ static int match_record(rmc_record_header_t *r, rmc_signature_t* sig) { return strncmp((const char *)r->signature.raw, (const char *)sig->raw, sizeof(r->signature.raw)); } +int is_rmcdb(rmc_uint8_t *db_blob) { + rmc_db_header_t *db_header = NULL; + + if (db_blob == NULL) + return 1; + + db_header = (rmc_db_header_t *)db_blob; + + /* sanity check of db */ + if (strncmp((const char *)db_header->signature, (const char *)rmc_db_signature, RMC_DB_SIG_LEN)) + return 1; + else + return 0; +} + int query_policy_from_db(rmc_fingerprint_t *fingerprint, rmc_uint8_t *rmc_db, rmc_uint8_t type, char *blob_name, rmc_file_t *policy) { rmc_meta_header_t meta_header; rmc_db_header_t *db_header = NULL; @@ -211,7 +226,7 @@ int query_policy_from_db(rmc_fingerprint_t *fingerprint, rmc_uint8_t *rmc_db, rm db_header = (rmc_db_header_t *)rmc_db; /* sanity check of db */ - if (strncmp((const char *)db_header->signature, (const char *)rmc_db_signature, RMC_DB_SIG_LEN)) + if (is_rmcdb(rmc_db)) return 1; /* calculate signature of fingerprint */ diff --git a/src/rmc.c b/src/rmc.c index b5c7847..0740223 100644 --- a/src/rmc.c +++ b/src/rmc.c @@ -31,8 +31,10 @@ "running on\n" \ "\t-d: database file to be queried\n" \ "\t-o: path and name of output file of a specific command\n\n" \ - "-E: Extract data from fingerprint file and print it to terminal\n" \ - "\t-f: fingerprint file to extract\n\n" \ + "-E: Extract data from fingerprint file or database\n" \ + "\t-f: fingerprint file to extract\n" \ + "\t-d: database file to extract\n" \ + "\t-o: directory to extract the database to\n\n" \ "Examples (Steps in an order to add board support into rmc):\n\n" \ "1. Generate board fingerprint:\n" \ "\trmc -F\n\n" \ @@ -408,12 +410,14 @@ int main(int argc, char **argv){ /* sanity check for -o */ if (options & RMC_OPT_O) { - rmc_uint16_t opt_o = options & (RMC_OPT_CAP_D | RMC_OPT_CAP_R | RMC_OPT_CAP_F | RMC_OPT_CAP_B); + rmc_uint16_t opt_o = options & (RMC_OPT_CAP_D | RMC_OPT_CAP_R | + RMC_OPT_CAP_F | RMC_OPT_CAP_B | RMC_OPT_CAP_E); if (!(opt_o)) { - fprintf(stderr, "\nWRONG: Option -o cannot be applied without -B, -D, -R or -F\n\n"); + fprintf(stderr, "\nWRONG: Option -o cannot be applied without -B, -D, -E, -R or -F\n\n"); usage(); return 1; - } else if (opt_o != RMC_OPT_CAP_D && opt_o != RMC_OPT_CAP_R && opt_o != RMC_OPT_CAP_F && opt_o != RMC_OPT_CAP_B) { + } else if (opt_o != RMC_OPT_CAP_D && opt_o != RMC_OPT_CAP_R && + opt_o != RMC_OPT_CAP_F && opt_o != RMC_OPT_CAP_B && opt_o != RMC_OPT_CAP_E) { fprintf(stderr, "\nWRONG: Option -o can be applied with only one of -B, -D, -R and -F\n\n"); usage(); return 1; @@ -428,8 +432,8 @@ int main(int argc, char **argv){ } /* sanity check for -E */ - if ((options & RMC_OPT_CAP_E) && (!(options & RMC_OPT_F))) { - fprintf(stderr, "\nERROR: -E requires -f <fingerprint file name>\n\n"); + if ((options & RMC_OPT_CAP_E) && (!(options & RMC_OPT_F) && !(options & RMC_OPT_D))) { + fprintf(stderr, "\nERROR: -E requires -f <fingerprint file name> or -d <database file name>\n\n"); usage(); return 1; } @@ -446,7 +450,8 @@ int main(int argc, char **argv){ rmc_file_t file; if (!output_path) { - fprintf(stderr, "-B internal error, with -o but no output pathname specified\n\n"); + fprintf(stderr, "-B internal error, with -o but no output \ + pathname specified\n\n"); goto main_free; } @@ -454,7 +459,8 @@ int main(int argc, char **argv){ goto main_free; if (write_file(output_path, file.blob, file.blob_len, 0)) { - fprintf(stderr, "-B failed to write file %s to %s\n\n", input_blob_name, output_path); + fprintf(stderr, "-B failed to write file %s to %s\n\n", + input_blob_name, output_path); rmc_free_file(&file); goto main_free; } @@ -477,6 +483,12 @@ int main(int argc, char **argv){ }else { printf("Fingerprint file not provided! Exiting.\n"); } + } else if (options & RMC_OPT_D) { + if(dump_db(input_db_path_d, output_path)) { + fprintf(stderr, "\nFailed to extract %s\n\n", input_db_path_d); + goto main_free; + } else + printf("\nSuccessfully extracted %s\n\n", input_db_path_d); } } -- 2.11.1 -- _______________________________________________ yocto mailing list yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/yocto