Skip to content

Commit

Permalink
elfloader: factor out check_hash()
Browse files Browse the repository at this point in the history
This also allows running the hash check on the image before accessing
any other data from it.

Signed-off-by: Axel Heider <axel.heider@hensoldt.net>
  • Loading branch information
Axel Heider committed Mar 6, 2024
1 parent 24a7eca commit 594de26
Showing 1 changed file with 122 additions and 86 deletions.
208 changes: 122 additions & 86 deletions elfloader-tool/src/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,19 @@
#include <elfloader.h>
#include <fdt.h>

#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 <platform_info.h> // this provides memory_region
Expand Down Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -409,11 +429,22 @@ 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");
Expand Down Expand Up @@ -496,12 +527,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,
Expand Down Expand Up @@ -537,6 +564,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
Expand Down Expand Up @@ -575,28 +621,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],
Expand Down

0 comments on commit 594de26

Please sign in to comment.