Skip to content

Commit

Permalink
Add a tester for parse_load_options()
Browse files Browse the repository at this point in the history
This adds tests for all the cases we've documented in the
set_second_stage() comments.  Each test checks that all of second_stage,
loader_str, and loader_str_size are set correctly.

Note that this adds a dependency on libefivar to build device paths to
test against.

Signed-off-by: Peter Jones <pjones@redhat.com>
  • Loading branch information
vathpela committed Jul 20, 2021
1 parent cda8128 commit d70c12b
Show file tree
Hide file tree
Showing 3 changed files with 285 additions and 8 deletions.
16 changes: 12 additions & 4 deletions include/test.mk
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ include Make.defaults
CC = gcc
VALGRIND ?=
DEBUG_PRINTS ?= 0
CFLAGS = -O2 -ggdb -std=gnu11 \
OPTIMIZATIONS=-O2 -ggdb
CFLAGS = $(OPTIMIZATIONS) -std=gnu11 \
-isystem $(TOPDIR)/include/system \
$(EFI_INCLUDES) \
-Iinclude -iquote . \
Expand Down Expand Up @@ -50,13 +51,19 @@ libefi-test.a :
-f $(TOPDIR)/gnu-efi/Makefile \
clean

test-random.h:
dd if=/dev/urandom bs=512 count=17 of=random.bin
xxd -i random.bin test-random.h

$(wildcard test-*.c) :: %.c : test-random.h
$(patsubst %.c,%,$(wildcard test-*.c)) :: | test-random.h
$(patsubst %.c,%.o,$(wildcard test-*.c)) : | test-random.h

test-random.h:
dd if=/dev/urandom bs=512 count=17 of=random.bin
xxd -i random.bin test-random.h
test-load-options_FILES = lib/guid.c \
libefi-test.a \
-lefivar
test-load-options :: libefi-test.a
test-load-options : CFLAGS+=-DHAVE_SHIM_LOCK_GUID

test-sbat_FILES = csv.c lib/variables.c lib/guid.c
test-sbat :: CFLAGS+=-DHAVE_GET_VARIABLE -DHAVE_GET_VARIABLE_ATTR -DHAVE_SHIM_LOCK_GUID
Expand All @@ -66,6 +73,7 @@ test-str_FILES = lib/string.c
tests := $(patsubst %.c,%,$(wildcard test-*.c))

$(tests) :: test-% : | libefi-test.a

$(tests) :: test-% : test.c test-%.c $(test-%_FILES)
$(CC) $(CFLAGS) -o $@ $^ $(wildcard $*.c) $(test-$*_FILES) libefi-test.a
$(VALGRIND) ./$@
Expand Down
8 changes: 4 additions & 4 deletions load-options.c
Original file line number Diff line number Diff line change
Expand Up @@ -415,10 +415,10 @@ parse_load_options(EFI_LOADED_IMAGE *li)
* LoadOptions. We ignore the first string, i.e. the name of this
* program in this case.
*/
CHAR16 *loader_str = split_load_options(li->LoadOptions,
li->LoadOptionsSize,
&remaining,
&remaining_size);
loader_str = split_load_options(li->LoadOptions,
li->LoadOptionsSize,
&remaining,
&remaining_size);

if (loader_str && is_our_path(li, loader_str)) {
li->LoadOptions = remaining;
Expand Down
269 changes: 269 additions & 0 deletions test-load-options.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
// SPDX-License-Identifier: BSD-2-Clause-Patent
/*
* test-argv.c - test our loader_opts parsing
*/
#pragma GCC diagnostic ignored "-Wunused-variable"
#pragma GCC diagnostic error "-Wnonnull"
#pragma GCC diagnostic error "-Wunused-function"

#pragma GCC diagnostic warning "-Wcpp"

#ifndef SHIM_UNIT_TEST
#define SHIM_UNIT_TEST
#endif

#include "shim.h"

#include <execinfo.h>
#include <stdio.h>
#include <efivar/efivar.h>

EFI_DEVICE_PATH *
make_file_dp(char *filename)
{
void *filedp = NULL;
size_t filedpsz = 0, filedpneeded = 0;

filedpneeded = efidp_make_file(filedp, filedpneeded, filename);
assert_positive_return(filedpneeded, NULL, "\n");

filedp = calloc(1, filedpneeded + 4);
assert_nonzero_return(filedp, NULL, "\n");

filedpsz = efidp_make_file(filedp, filedpneeded, filename);
assert_equal_goto(filedpsz, filedpneeded, err, "got %zu expected %zu\n");

efidp_make_end_entire((uint8_t *)filedp + filedpneeded, 4);

return filedp;
err:
free(filedp);
return NULL;
}

int
test_parse_load_options(char *load_option_data,
size_t load_option_data_size,
char *file_path,
CHAR16 *target_second_stage,
char *target_remaining,
size_t target_remaining_size)
{
EFI_STATUS status = EFI_SUCCESS;
EFI_LOADED_IMAGE li = {
.LoadOptions = load_option_data,
.LoadOptionsSize = load_option_data_size,
.FilePath = make_file_dp(file_path),
};
CHAR16 *dummy_second_stage = calloc(1, 8);
int rc = -1;

assert_nonzero_goto(li.FilePath, err, "\n");
assert_nonzero_goto(dummy_second_stage, err, "\n");

StrCat(dummy_second_stage, L"foo");
second_stage = dummy_second_stage;

status = parse_load_options(&li);
assert_false_goto(EFI_ERROR(status), err, "\n");

assert_nonzero_goto(second_stage, err, "\n");
assert_not_equal_goto(second_stage, dummy_second_stage, err, "%p == %p\n");
assert_zero_goto(StrnCmp(second_stage, target_second_stage, 90),
err_print_second_stage, "%d != 0\n");

assert_equal_goto(load_options_size, target_remaining_size, err_remaining, "%zu != %zu\n");
assert_equal_goto(load_options, target_remaining, err_remaining, "%p != %p\n");
assert_zero_goto(memcmp(load_options, target_remaining, load_options_size), err_remaining, "\n");

rc = 0;
err_remaining:
if (rc != 0) {
printf("expected remaining:%p\n", target_remaining);
for (size_t i = 0; i < target_remaining_size; i++)
printf("0x%02hhx ", target_remaining[i]);
printf("\n");
printf("actual remaining:%p\n", load_options);
for (size_t i = 0; i < load_options_size; i++)
printf("0x%02hhx ", ((char *)load_options)[i]);
printf("\n");
}
err_print_second_stage:
if (rc != 0) {
printf("second stage:\"");
for(int i = 0; second_stage[i] != 0; i++)
printf("%c", second_stage[i]);
printf("\"\nexpected:\"");
for(int i = 0; target_second_stage[i] != 0; i++)
printf("%c", target_second_stage[i]);
printf("\"\n");
}
err:
if (rc != 0) {
print_traceback(0);
}
if (li.FilePath) {
free(li.FilePath);
}
if (dummy_second_stage && dummy_second_stage != second_stage) {
free(dummy_second_stage);
}
second_stage = NULL;

return rc;
}

int __attribute__((__flatten__))
test_efi_shell_0(void)
{
/*
00000000 5c 00 45 00 46 00 49 00 5c 00 66 00 65 00 64 00 |\.E.F.I.\.f.e.d.|
00000010 6f 00 72 00 61 00 5c 00 73 00 68 00 69 00 6d 00 |o.r.a.\.s.h.i.m.|
00000020 78 00 36 00 34 00 2e 00 65 00 66 00 69 00 20 00 |x.6.4...e.f.i. .|
00000030 5c 00 45 00 46 00 49 00 5c 00 66 00 65 00 64 00 |\.E.F.I.\.f.e.d.|
00000040 6f 00 72 00 61 00 5c 00 66 00 77 00 75 00 70 00 |o.r.a.\.f.w.u.p.|
00000050 64 00 61 00 74 00 65 00 2e 00 65 00 66 00 69 00 |d.a.t.e...e.f.i.|
00000060 20 00 00 00 66 00 73 00 30 00 3a 00 5c 00 00 00 | ...f.s.0.:.\...|
*/

char load_option_data[] = {
0x5c, 0x00, 0x45, 0x00, 0x46, 0x00, 0x49, 0x00,
0x5c, 0x00, 0x66, 0x00, 0x65, 0x00, 0x64, 0x00,
0x6f, 0x00, 0x72, 0x00, 0x61, 0x00, 0x5c, 0x00,
0x73, 0x00, 0x68, 0x00, 0x69, 0x00, 0x6d, 0x00,
0x78, 0x00, 0x36, 0x00, 0x34, 0x00, 0x2e, 0x00,
0x65, 0x00, 0x66, 0x00, 0x69, 0x00, 0x20, 0x00,
0x5c, 0x00, 0x45, 0x00, 0x46, 0x00, 0x49, 0x00,
0x5c, 0x00, 0x66, 0x00, 0x65, 0x00, 0x64, 0x00,
0x6f, 0x00, 0x72, 0x00, 0x61, 0x00, 0x5c, 0x00,
0x66, 0x00, 0x77, 0x00, 0x75, 0x00, 0x70, 0x00,
0x64, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00,
0x2e, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00,
0x20, 0x00, 0x00, 0x00, 0x66, 0x00, 0x73, 0x00,
0x30, 0x00, 0x3a, 0x00, 0x5c, 0x00, 0x00, 0x00,
};
size_t load_option_data_size = sizeof(load_option_data);
char *remaining = &load_option_data[sizeof(load_option_data)-14];
size_t remaining_size = 14;

return test_parse_load_options(load_option_data,
load_option_data_size,
"\\EFI\\fedora\\shimx64.efi",
L"\\EFI\\fedora\\fwupdate.efi",
remaining, remaining_size);
}

int __attribute__((__flatten__))
test_bds_0(void)
{
/*
00000000 01 00 00 00 62 00 4c 00 69 00 6e 00 75 00 78 00 |....b.L.i.n.u.x.|
00000010 20 00 46 00 69 00 72 00 6d 00 77 00 61 00 72 00 | .F.i.r.m.w.a.r.|
00000020 65 00 20 00 55 00 70 00 64 00 61 00 74 00 65 00 |e. .U.p.d.a.t.e.|
00000030 72 00 00 00 40 01 2a 00 01 00 00 00 00 08 00 00 |r.....*.........|
00000040 00 00 00 00 00 40 06 00 00 00 00 00 1a 9e 55 bf |.....@........U.|
00000050 04 57 f2 4f b4 4a ed 26 4a 40 6a 94 02 02 04 04 |.W.O.:.&J@j.....|
00000060 34 00 5c 00 45 00 46 00 49 00 5c 00 66 00 65 00 |4.\.E.F.I.\.f.e.|
00000070 64 00 6f 00 72 00 61 00 5c 00 73 00 68 00 69 00 |d.o.r.a.\.s.h.i.|
00000080 6d 00 78 00 36 00 34 00 2e 00 65 00 66 00 69 00 |m.x.6.4...e.f.i.|
00000090 00 00 7f ff 04 00 20 00 5c 00 66 00 77 00 75 00 |...... .\.f.w.u.|
000000a0 70 00 78 00 36 00 34 00 2e 00 65 00 66 00 69 00 |p.x.6.4...e.f.i.|
000000b0 00 00 |..|
*/
char load_option_data [] = {
0x01, 0x00, 0x00, 0x00, 0x62, 0x00, 0x4c, 0x00,
0x69, 0x00, 0x6e, 0x00, 0x75, 0x00, 0x78, 0x00,
0x20, 0x00, 0x46, 0x00, 0x69, 0x00, 0x72, 0x00,
0x6d, 0x00, 0x77, 0x00, 0x61, 0x00, 0x72, 0x00,
0x65, 0x00, 0x20, 0x00, 0x55, 0x00, 0x70, 0x00,
0x64, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00,
0x72, 0x00, 0x00, 0x00, 0x40, 0x01, 0x2a, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1a, 0x9e, 0x55, 0xbf,
0x04, 0x57, 0xf2, 0x4f, 0xb4, 0x4a, 0xed, 0x26,
0x4a, 0x40, 0x6a, 0x94, 0x02, 0x02, 0x04, 0x04,
0x34, 0x00, 0x5c, 0x00, 0x45, 0x00, 0x46, 0x00,
0x49, 0x00, 0x5c, 0x00, 0x66, 0x00, 0x65, 0x00,
0x64, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x61, 0x00,
0x5c, 0x00, 0x73, 0x00, 0x68, 0x00, 0x69, 0x00,
0x6d, 0x00, 0x78, 0x00, 0x36, 0x00, 0x34, 0x00,
0x2e, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00,
0x00, 0x00, 0x7f, 0xff, 0x04, 0x00, 0x20, 0x00,
0x5c, 0x00, 0x66, 0x00, 0x77, 0x00, 0x75, 0x00,
0x70, 0x00, 0x78, 0x00, 0x36, 0x00, 0x34, 0x00,
0x2e, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00,
0x00, 0x00
};
size_t load_option_data_size = sizeof(load_option_data);

return test_parse_load_options(load_option_data,
load_option_data_size,
"\\EFI\\fedora\\shimx64.efi",
L"\\fwupx64.efi",
NULL, 0);
}

int __attribute__((__flatten__))
test_bds_1(void)
{
/*
00000000 5c 00 66 00 77 00 75 00 70 00 78 00 36 00 34 00 |\.f.w.u.p.x.6.4.|
00000010 2e 00 65 00 66 00 69 00 00 00 |..e.f.i...|
0000001a
*/
char load_option_data [] = {
0x5c, 0x00, 0x66, 0x00, 0x77, 0x00, 0x75, 0x00,
0x70, 0x00, 0x78, 0x00, 0x36, 0x00, 0x34, 0x00,
0x2e, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00,
0x00, 0x00
};
size_t load_option_data_size = sizeof(load_option_data);

return test_parse_load_options(load_option_data,
load_option_data_size,
"\\EFI\\fedora\\shimx64.efi",
L"\\fwupx64.efi",
NULL, 0);
}

int
test_bds_2(void)
{
/*
00000000 74 00 65 00 73 00 74 00 2E 00 65 00 66 00 69 00 |t.e.s.t...e.f.i.|
00000010 20 00 6F 00 6E 00 65 00 20 00 74 00 77 00 6F 00 |..o.n.e...t.w.o.|
00000020 20 00 74 00 68 00 72 00 65 00 65 00 00 00 |..t.h.r.e.e...|
*/
char load_option_data [] = {
0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
0x2E, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00,
0x20, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x65, 0x00,
0x20, 0x00, 0x74, 0x00, 0x77, 0x00, 0x6F, 0x00,
0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x72, 0x00,
0x65, 0x00, 0x65, 0x00, 0x00, 0x00
};
size_t load_option_data_size = sizeof(load_option_data);
char *target_remaining = &load_option_data[26];
size_t target_remaining_size = 20;

return test_parse_load_options(load_option_data,
load_option_data_size,
"test.efi",
L"one",
target_remaining,
target_remaining_size);
}

int
main(void)
{
int status = 0;
test(test_efi_shell_0);
test(test_bds_0);
test(test_bds_1);
test(test_bds_2);
return status;
}

// vim:fenc=utf-8:tw=75:noet

0 comments on commit d70c12b

Please sign in to comment.