Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

elfloader: factor out check_hash() #160

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
207 changes: 121 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,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");
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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],
Expand Down