From 8e2900c0f0e2d23d11a1a13b99351e7526169e53 Mon Sep 17 00:00:00 2001 From: Fabian Freyer Date: Tue, 20 Feb 2018 12:32:50 +0100 Subject: [PATCH] tests: add multiboot tests --- tests/Makefile | 6 +- tests/test-multiboot.c | 290 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 294 insertions(+), 2 deletions(-) diff --git a/tests/Makefile b/tests/Makefile index 10f0aac..1ca5071 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -14,6 +14,8 @@ OUTPUT_BFD=elf64-x86-64-freebsd MB_DIR=data/multiboot MB_TESTCASES=data_multiboot_mmap.o data_multiboot_modules.o +MOCK_BHYVELOAD=mock/bhyveload.o mock/compat-strlcat.o mock/compat-strlcpy.o + .PHONY: all all: test-allocator test-loader test-mock-bhyveload test-multiboot @@ -45,10 +47,10 @@ data_multiboot_mmap.o: ${MB_DIR}/mmap.elf data_multiboot_modules.o: ${MB_DIR}/modules.elf $(OBJCOPY) --input binary --binary-architecture i386 --output ${OUTPUT_BFD} $> $@ -test-multiboot: test-multiboot.o ${MB_TESTCASES} ../libmultiboot_p.a +test-multiboot: test-multiboot.o ${MB_TESTCASES} ${MOCK_BHYVELOAD} ../libmultiboot_p.a $(CC) ${LDFLAGS} ${CFLAGS} -o $@ $> ${LIBATF_C} ${LIBELF} -test-mock-bhyveload: test-mock-bhyveload.o mock/bhyveload.o mock/compat-strlcat.o mock/compat-strlcpy.o +test-mock-bhyveload: test-mock-bhyveload.o ${MOCK_BHYVELOAD} $(CC) ${LDFLAGS} ${CFLAGS} -o $@ $> ${LIBATF_C} ${LIBELF} test-loader: mock/bhyveload.o ../libmultiboot_p.a diff --git a/tests/test-multiboot.c b/tests/test-multiboot.c index c67e133..6d5286a 100644 --- a/tests/test-multiboot.c +++ b/tests/test-multiboot.c @@ -26,9 +26,19 @@ */ #include +#include #include +#include +#include +#include +#include +#include +#include #include +struct loader_callbacks *callbacks = &mock_callbacks; +void *callbacks_arg = NULL;; + ATF_TC(testdata); ATF_TC_HEAD(testdata, tc) { @@ -50,9 +60,289 @@ ATF_TC_BODY(testdata, tc) ATF_CHECK_EQ_MSG(0, (0 < MB_TESTDATA_SIZE(modules)), "mmap test size"); } +ATF_TC(scan); +ATF_TC_HEAD(scan, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test scanning for a multiboot header"); +} +ATF_TC_BODY(scan, tc) +{ + struct multiboot *mb = NULL; + struct multiboot_header *mbh = NULL; + struct multiboot2_header *mb2h = NULL; + char *random_buffer = NULL; + FILE *urandom = NULL; + + mb = mb_scan(MB_TESTDATA_START(mmap), MB_TESTDATA_SIZE(mmap)); + ATF_CHECK_EQ(MULTIBOOT1_MAGIC, mb->magic); + ATF_CHECK_MSG(mb->info.mb.header >= MB_TESTDATA_START(mmap), + "mb_scan did not find the header"); + + ATF_CHECK(urandom = fopen("/dev/urandom", "r")); + + ATF_CHECK_MSG(random_buffer = malloc(128*kiB), "could not allocate memory"); + ATF_CHECK(fread(random_buffer, 128*kiB, 1, urandom)); + + /* Random data */ + mb = mb_scan(random_buffer, 128*kiB); + ATF_CHECK_MSG(mb == 0, "returned non-NULL for random data"); + + /* Craft a valid multiboot header */ + ATF_CHECK(fread(random_buffer, 128*kiB, 1, urandom)); + mbh = (struct multiboot_header* )(random_buffer + 2*kiB); + mbh->magic = MULTIBOOT1_MAGIC; + mbh->flags = 0; + mbh->checksum = (uint32_t) 0U-MULTIBOOT1_MAGIC; + mb = mb_scan(random_buffer, 128*kiB); + ATF_CHECK_EQ_MSG(mb->info.mb.header, mbh, + "did not find crafted valid header"); + mbh = NULL; + + /* Craft a valid multiboot header out of search range*/ + ATF_CHECK(fread(random_buffer, 128*kiB, 1, urandom)); + mbh = (struct multiboot_header* )(random_buffer + 10*kiB); + mbh->magic = MULTIBOOT1_MAGIC; + mbh->flags = 0; + mbh->checksum = (uint32_t) 0U-MULTIBOOT1_MAGIC; + mb = mb_scan(random_buffer, 128*kiB); + ATF_CHECK_MSG(!mb, "found valid header out of range"); + mbh = NULL; + + /* Craft a header with an invalid checksum */ + ATF_CHECK(fread(random_buffer, 128*kiB, 1, urandom)); + mbh = (struct multiboot_header* )(random_buffer + 10*kiB); + mbh->magic = MULTIBOOT1_MAGIC; + mbh->flags = 0; + mbh->checksum = 0xdeadbeef; + mb = mb_scan(random_buffer, 128*kiB); + ATF_CHECK_MSG(!mb, "found valid header with invalid checksum"); + mb = NULL; + + /* Craft a valid multiboot2 header */ + ATF_CHECK(fread(random_buffer, 128*kiB, 1, urandom)); + mb2h = (struct multiboot2_header* )(random_buffer + 16*kiB); + mb2h->magic = MULTIBOOT2_MAGIC; + mb2h->header_length = 0; + mb2h->architecture = 0; + mb2h->checksum = (uint32_t) 0U-MULTIBOOT2_MAGIC; + mb = mb_scan(random_buffer, 128*kiB); + ATF_CHECK_EQ(MULTIBOOT2_MAGIC, mb->magic); + mb2h = NULL; + + /* Craft a valid multiboot2 header out of search range */ + ATF_CHECK(fread(random_buffer, 128*kiB, 1, urandom)); + mb2h = (struct multiboot2_header* )(random_buffer + 36*kiB); + mb2h->magic = MULTIBOOT2_MAGIC; + mb2h->header_length = 0; + mb2h->architecture = 0; + mb2h->checksum = (uint32_t) 0U-MULTIBOOT2_MAGIC; + mb = mb_scan(random_buffer, 128*kiB); + ATF_CHECK_MSG(!mb, "found valid header out of range"); + mb2h = NULL; + + free(random_buffer); + fclose(urandom); +} + +ATF_TC(loadtype); +ATF_TC_HEAD(loadtype, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test load type detection"); +} +ATF_TC_BODY(loadtype, tc) +{ + char *random_buffer = NULL; + FILE *urandom = NULL; + struct multiboot *mb = NULL; + struct multiboot_header *mbh = NULL; + void *kernel = MB_TESTDATA_START(mmap); + size_t kernsz = MB_TESTDATA_SIZE(mmap); + enum LOAD_TYPE type; + Elf *kernelf; + + mb = mb_scan(kernel, kernsz); + + type = multiboot_load_type(kernel, kernsz, &kernelf, mb->info.mb.header); + ATF_CHECK_EQ_MSG(type, LOAD_ELF, "mmap test kernel not loaded as ELF"); + + ATF_CHECK(urandom = fopen("/dev/urandom", "r")); + ATF_CHECK_MSG(random_buffer = malloc(128*kiB), "could not allocate memory"); + elf_end(kernelf); + + /* Craft a valid multiboot header */ + ATF_CHECK(fread(random_buffer, 128*kiB, 1, urandom)); + mbh = (struct multiboot_header* )(random_buffer + 2*kiB); + mbh->magic = MULTIBOOT1_MAGIC; + mbh->flags = 0 | MULTIBOOT_AOUT_KLUDGE; + mbh->checksum = (uint32_t) 0U-MULTIBOOT1_MAGIC-(mbh->flags); + mb = mb_scan(random_buffer, 128*kiB); + ATF_CHECK_EQ_MSG(mb->info.mb.header, mbh, + "did not find crafted valid header"); + mbh = NULL; + type = multiboot_load_type(random_buffer, 128*kiB, + &kernelf, mb->info.mb.header); + ATF_CHECK_EQ_MSG(type, LOAD_AOUT, + "random test data not loaded as a.out kludge"); + ATF_CHECK_EQ_MSG(NULL, kernelf, "ELF resources not freed"); + + free(random_buffer); + fclose(urandom); +} + +ATF_TC(load_aout_direct); +ATF_TC_HEAD(load_aout_direct, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test loading a.out kludge directly"); +} +ATF_TC_BODY(load_aout_direct, tc) +{ + char *random_buffer = NULL; + FILE *urandom = NULL; + struct multiboot *mb = NULL; + struct multiboot_header *mbh = NULL; + uint32_t error = 0; + size_t lowmem = 0; + size_t highmem = 0; + + setmem(4*MiB, 0); + callbacks->getmem(callbacks_arg, &lowmem, &highmem); + init_allocator(lowmem, highmem); + + ATF_CHECK(urandom = fopen("/dev/urandom", "r")); + ATF_CHECK_MSG(random_buffer = malloc(128*kiB), "could not allocate memory"); + + /* Load a kernel with a valid a.out kludge */ + ATF_CHECK(fread(random_buffer, 128*kiB, 1, urandom)); + mbh = (struct multiboot_header* )(random_buffer + 2*kiB); + mbh->magic = MULTIBOOT1_MAGIC; + mbh->flags = 0 | MULTIBOOT_AOUT_KLUDGE; + mbh->checksum = (uint32_t) 0U-MULTIBOOT1_MAGIC-(mbh->flags); + mbh->header_addr = 1*MiB; + mbh->load_addr = 1*MiB; + mbh->load_end_addr = 1*MiB + 0x100; + mbh->bss_end_addr = 1*MiB + 0x200; + mbh->entry_addr = 1*MiB + sizeof(struct multiboot_header); + + mb = mb_scan(random_buffer, 128*kiB); + error = multiboot_load_aout(random_buffer, 128*kiB, mbh); + ATF_CHECK_EQ_MSG(0, error, "multiboot_load_aout failed"); + + /* load_addr must be less than or equal to header_addr */ + mbh->load_addr = 1*MiB+1; + mb = mb_scan(random_buffer, 128*kiB); + error = multiboot_load_aout(random_buffer, 128*kiB, mbh); + ATF_CHECK_EQ_MSG(EINVAL, error, "load_addr > header_addr"); + + free(random_buffer); + fclose(urandom); +} + +ATF_TC(load_aout); +ATF_TC_HEAD(load_aout, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test loading a.out kludge directly"); +} +ATF_TC_BODY(load_aout, tc) +{ + char *random_buffer = NULL; + FILE *urandom = NULL; + struct multiboot *mb = NULL; + struct multiboot_header *mbh = NULL; + uint32_t error = 0; + size_t lowmem = 0; + size_t highmem = 0; + + setmem(4*MiB, 0); + callbacks->getmem(callbacks_arg, &lowmem, &highmem); + init_allocator(lowmem, highmem); + + ATF_CHECK(urandom = fopen("/dev/urandom", "r")); + ATF_CHECK_MSG(random_buffer = malloc(128*kiB), "could not allocate memory"); + + /* Load a kernel with a valid a.out kludge */ + ATF_CHECK(fread(random_buffer, 128*kiB, 1, urandom)); + mbh = (struct multiboot_header* )(random_buffer + 2*kiB); + mbh->magic = MULTIBOOT1_MAGIC; + mbh->flags = 0 | MULTIBOOT_AOUT_KLUDGE; + mbh->checksum = (uint32_t) 0U-MULTIBOOT1_MAGIC-(mbh->flags); + mbh->header_addr = 1*MiB; + mbh->load_addr = 1*MiB; + mbh->load_end_addr = 1*MiB + 0x100; + mbh->bss_end_addr = 1*MiB + 0x200; + mbh->entry_addr = 1*MiB + sizeof(struct multiboot_header); + + mb = mb_scan(random_buffer, 128*kiB); + error = multiboot_load(random_buffer, 128*kiB, mbh); + ATF_CHECK_EQ_MSG(0, error, "multiboot_load failed"); + + free(random_buffer); + fclose(urandom); +} + +ATF_TC(load_elf_direct); +ATF_TC_HEAD(load_elf_direct, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test loading ELF directly"); +} +ATF_TC_BODY(load_elf_direct, tc) +{ + struct multiboot *mb = NULL; + struct multiboot_header *mbh = NULL; + uint32_t error = 0; + size_t lowmem = 0; + size_t highmem = 0; + void *kernel = MB_TESTDATA_START(mmap); + size_t kernsz = MB_TESTDATA_SIZE(mmap); + Elf *kernelf; + + setmem(4*MiB, 0); + callbacks->getmem(callbacks_arg, &lowmem, &highmem); + init_allocator(lowmem, highmem); + + mb = mb_scan(kernel, kernsz); + mbh = mb->info.mb.header; + multiboot_load_type(kernel, kernsz, &kernelf, mbh); + error = multiboot_load_elf(kernel, kernsz, kernelf); + ATF_CHECK_EQ_MSG(0, error, "multiboot_load_elf failed"); + + elf_end(kernelf); +} + +ATF_TC(load_elf); +ATF_TC_HEAD(load_elf, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test loading ELF"); +} +ATF_TC_BODY(load_elf, tc) +{ + struct multiboot *mb = NULL; + struct multiboot_header *mbh = NULL; + uint32_t error = 0; + size_t lowmem = 0; + size_t highmem = 0; + void *kernel = MB_TESTDATA_START(mmap); + size_t kernsz = MB_TESTDATA_SIZE(mmap); + + setmem(4*MiB, 0); + callbacks->getmem(callbacks_arg, &lowmem, &highmem); + init_allocator(lowmem, highmem); + + mb = mb_scan(kernel, kernsz); + mbh = mb->info.mb.header; + error = multiboot_load(kernel, kernsz, mbh); + ATF_CHECK_EQ_MSG(0, error, "multiboot_load_elf failed"); +} + + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, testdata); + ATF_TP_ADD_TC(tp, scan); + ATF_TP_ADD_TC(tp, loadtype); + ATF_TP_ADD_TC(tp, load_aout_direct); + ATF_TP_ADD_TC(tp, load_aout); + ATF_TP_ADD_TC(tp, load_elf_direct); + ATF_TP_ADD_TC(tp, load_elf); return atf_no_error(); }