From bced6ef7b7ea781b257983012c1076ffe595f728 Mon Sep 17 00:00:00 2001 From: Axel Heider Date: Wed, 21 Dec 2022 13:19:58 +0100 Subject: [PATCH] elfloader: factor out check_hash() This also allows running the hash check on the image before accessing any other data from it. Signed-off-by: Axel Heider --- elfloader-tool/src/common.c | 207 +++++++++++++++++++++--------------- 1 file changed, 121 insertions(+), 86 deletions(-) diff --git a/elfloader-tool/src/common.c b/elfloader-tool/src/common.c index 9846422f..8f6ab0c8 100644 --- a/elfloader-tool/src/common.c +++ b/elfloader-tool/src/common.c @@ -17,13 +17,19 @@ #include #include -#ifdef CONFIG_HASH_SHA +#if defined(CONFIG_HASH_SHA) #include "crypt_sha256.h" -#elif CONFIG_HASH_MD5 +#define ELFLOADER_CHECK_HASH +#elif defined(CONFIG_HASH_MD5) #include "crypt_md5.h" +#define ELFLOADER_CHECK_HASH +#elif !defined(CONFIG_HASH_NONE) +#error "invalid configuration" #endif +#ifdef ELFLOADER_CHECK_HASH #include "hash.h" +#endif #ifdef CONFIG_ELFLOADER_ROOTSERVERS_LAST #include // this provides memory_region @@ -90,6 +96,87 @@ static int ensure_phys_range_valid( return 0; } +#ifdef ELFLOADER_CHECK_HASH +/* + * Read hash file from CPIO archive and check if blob hash matches + */ +static int check_hash( + void const *blob, + size_t blob_size, + void const *cpio, + size_t cpio_len, + char const *hash_filename, + size_t index) +{ + /* ToDo: Support storing multiple hashes in a single hash file, as this + * might come handy when loading multiple images. Currently the + * feature is unsued, thus there is no implementation here. + */ + if (0 != index) { + printf("ERROR: only one hash is supported per file\n"); + return -1; + } + + /* Get the binary file that contains the Hash */ + unsigned long cpio_file_size = 0; + void const *file_hash = cpio_get_file(cpio, + cpio_len, + hash_filename, + &cpio_file_size); + + /* If the file hash doesn't have a pointer, the file doesn't exist, so we + * cannot confirm the file is what we expect. + */ + if (file_hash == NULL) { + printf("ERROR: hash file '%s' doesn't exist\n", hash_filename); + return -1; + } + + /* Ensure we can safely cast the CPIO API type to our preferred type. */ + _Static_assert(sizeof(cpio_file_size) <= sizeof(size_t), + "integer model mismatch"); + size_t file_hash_len = (size_t)cpio_file_size; + +#if defined(CONFIG_HASH_SHA) + uint8_t calculated_hash[32]; + hashes_t hashes = { .hash_type = SHA_256 }; +#elif defined(CONFIG_HASH_MD5) + uint8_t calculated_hash[16]; + hashes_t hashes = { .hash_type = MD5 }; +#else +#error "unsupported hash algorithm" +#endif + + if (file_hash_len < sizeof(calculated_hash)) { + printf("ERROR: hash file '%s' size %u invalid, expected at least %u\n", + hash_filename, file_hash_len, sizeof(calculated_hash)); + } + + /* Print the Hash for the user to see */ + printf("Hash from ELF File: "); + print_hash(file_hash, sizeof(calculated_hash)); + + /* This does not return anything */ + get_hash(hashes, blob, blob_size, calculated_hash); + + /* Print the hash so the user can see they're the same or different */ + printf("Hash for ELF Input: "); + print_hash(calculated_hash, sizeof(calculated_hash)); + + /* Check the hashes are the same. There is no memcmp() in the striped down + * runtime lib of ELF Loader, so we compare here byte per byte. + */ + for (unsigned int i = 0; i < sizeof(calculated_hash); i++) { + if (((char const *)file_hash)[i] != ((char const *)calculated_hash)[i]) { + printf("ERROR: Hashes are different\n"); + return -1; + } + } + + return 0; +} +#endif /* ELFLOADER_CHECK_HASH */ + /* * Unpack an ELF file to the given physical address. */ @@ -173,12 +260,8 @@ static int unpack_elf_to_paddr( * address used. */ static int load_elf( - void const *cpio, - size_t cpio_len, const char *name, void const *elf_blob, - size_t elf_blob_size, - char const *elf_hash_filename, paddr_t dest_paddr, int keep_headers, struct image_info *info, @@ -216,69 +299,6 @@ static int load_elf( return -1; } -#ifdef CONFIG_HASH_NONE - - UNUSED_VARIABLE(cpio); - UNUSED_VARIABLE(cpio_len); - UNUSED_VARIABLE(elf_blob_size); - UNUSED_VARIABLE(elf_hash_filename); - -#else - - /* Get the binary file that contains the Hash */ - unsigned long cpio_file_size = 0; - void const *file_hash = cpio_get_file(cpio, - cpio_len, - elf_hash_filename, - &cpio_file_size); - - /* If the file hash doesn't have a pointer, the file doesn't exist, so we - * cannot confirm the file is what we expect. - */ - if (file_hash == NULL) { - printf("ERROR: hash file '%s' doesn't exist\n", elf_hash_filename); - return -1; - } - - /* Ensure we can safely cast the CPIO API type to our preferred type. */ - _Static_assert(sizeof(cpio_file_size) <= sizeof(size_t), - "integer model mismatch"); - size_t file_hash_len = (size_t)cpio_file_size; - -#ifdef CONFIG_HASH_SHA - uint8_t calculated_hash[32]; - hashes_t hashes = { .hash_type = SHA_256 }; -#else - uint8_t calculated_hash[16]; - hashes_t hashes = { .hash_type = MD5 }; -#endif - - if (file_hash_len < sizeof(calculated_hash)) { - printf("ERROR: hash file '%s' size %u invalid, expected at least %u\n", - elf_hash_filename, file_hash_len, sizeof(calculated_hash)); - } - - /* Print the Hash for the user to see */ - printf("Hash from ELF File: "); - print_hash(file_hash, sizeof(calculated_hash)); - - get_hash(hashes, elf_blob, elf_blob_size, calculated_hash); - - /* Print the hash so the user can see they're the same or different */ - printf("Hash for ELF Input: "); - print_hash(calculated_hash, sizeof(calculated_hash)); - - /* Check the hashes are the same. There is no memcmp() in the striped down - * runtime lib of ELF Loader, so we compare here byte per byte. */ - for (unsigned int i = 0; i < sizeof(calculated_hash); i++) { - if (((char const *)file_hash)[i] != ((char const *)calculated_hash)[i]) { - printf("ERROR: Hashes are different\n"); - return -1; - } - } - -#endif /* CONFIG_HASH_NONE */ - /* Print diagnostics. */ printf(" paddr=[%p..%p]\n", dest_paddr, dest_paddr + image_size - 1); printf(" vaddr=[%p..%p]\n", (vaddr_t)min_vaddr, (vaddr_t)max_vaddr - 1); @@ -409,11 +429,21 @@ int load_images( return -1; } +#ifdef ELFLOADER_CHECK_HASH /* Ensure we can safely cast the CPIO API type to our preferred type. */ _Static_assert(sizeof(cpio_file_size) <= sizeof(size_t), "integer model mismatch"); size_t kernel_elf_blob_size = (size_t)cpio_file_size; + /* Check kernel image hash */ + ret = check_hash(kernel_elf_blob, kernel_elf_blob_size, + cpio, cpio_len, "kernel.bin", 0); + if (0 != ret) { + printf("ERROR: hash check failed for kernel image (%d)\n", ret); + return -1; + } +#endif /* ELFLOADER_CHECK_HASH */ + ret = elf_checkFile(kernel_elf_blob); if (ret != 0) { printf("ERROR: Kernel image not a valid ELF file\n"); @@ -496,12 +526,8 @@ int load_images( } /* Load the kernel */ - ret = load_elf(cpio, - cpio_len, - "kernel", + ret = load_elf("kernel", kernel_elf_blob, - kernel_elf_blob_size, - "kernel.bin", // hash file (paddr_t)kernel_phys_start, 0, // don't keep ELF headers kernel_info, @@ -537,6 +563,25 @@ int load_images( user_elf_offset = 1; } +#ifdef ELFLOADER_CHECK_HASH + for (unsigned int i = 0; i < max_user_images; i++) { + void const *user_elf = cpio_get_entry(cpio, + cpio_len, + i + user_elf_offset, + &elf_filename, + &cpio_file_size); + if (user_elf == NULL) { + break; + } + ret = check_hash(user_elf, (size_t)cpio_file_size, cpio, cpio_len, + "app.bin", i); + if (0 != ret) { + printf("ERROR: hash check failed for %s (%d)\n", elf_filename, ret); + return -1; + } + } +#endif /* ELFLOADER_CHECK_HASH */ + #ifdef CONFIG_ELFLOADER_ROOTSERVERS_LAST /* work out the size of the user images - this corresponds to how much @@ -575,28 +620,18 @@ int load_images( *num_images = 0; for (unsigned int i = 0; i < max_user_images; i++) { /* Fetch info about the next ELF file in the archive. */ - unsigned long cpio_file_size = 0; void const *user_elf = cpio_get_entry(cpio, cpio_len, i + user_elf_offset, &elf_filename, - &cpio_file_size); + NULL); if (user_elf == NULL) { break; } - /* Ensure we can safely cast the CPIO API type to our preferred type. */ - _Static_assert(sizeof(cpio_file_size) <= sizeof(size_t), - "integer model mismatch"); - size_t elf_filesize = (size_t)cpio_file_size; - /* Load the file into memory. */ - ret = load_elf(cpio, - cpio_len, - elf_filename, + ret = load_elf(elf_filename, user_elf, - elf_filesize, - "app.bin", // hash file next_phys_addr, 1, // keep ELF headers &user_info[*num_images],