summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMathieu Trudel-Lapierre <cyphermox@ubuntu.com>2017-08-04 12:10:50 -0400
committerMathieu Trudel-Lapierre <cyphermox@ubuntu.com>2017-08-04 12:10:50 -0400
commitbbfd2ab18f52600aa41f061b2da9a2afe2a9d6ac (patch)
tree56132d617fff7c4f05e67024ec872d88fcafa92d /lib
downloadefi-boot-shim-upstream/0.9+1474479173.6c180c6.tar.gz
efi-boot-shim-upstream/0.9+1474479173.6c180c6.zip
Import Upstream version 0.9+1474479173.6c180c6upstream/0.9+1474479173.6c180c6
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile15
-rw-r--r--lib/configtable.c144
-rw-r--r--lib/console.c461
-rw-r--r--lib/execute.c127
-rw-r--r--lib/guid.c22
-rw-r--r--lib/security_policy.c352
-rw-r--r--lib/shell.c57
-rw-r--r--lib/simple_file.c528
-rw-r--r--lib/variables.c345
9 files changed, 2051 insertions, 0 deletions
diff --git a/lib/Makefile b/lib/Makefile
new file mode 100644
index 00000000..d93a26de
--- /dev/null
+++ b/lib/Makefile
@@ -0,0 +1,15 @@
+TARGET = lib.a
+
+LIBFILES = simple_file.o guid.o console.o execute.o configtable.o shell.o variables.o security_policy.o
+
+EFI_INCLUDES = -I$(EFI_INCLUDE) -I$(EFI_INCLUDE)/$(ARCH) -I$(EFI_INCLUDE)/protocol -I../include
+
+lib.a: $(LIBFILES)
+ ar rcs lib.a $(LIBFILES)
+
+all: $(TARGET)
+
+clean:
+ rm -f lib.a
+ rm -f $(LIBFILES)
+
diff --git a/lib/configtable.c b/lib/configtable.c
new file mode 100644
index 00000000..edf2ed74
--- /dev/null
+++ b/lib/configtable.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2013 <James.Bottomley@HansenPartnership.com>
+ *
+ * see COPYING file
+ *
+ * read some platform configuration tables
+ */
+#include <efi.h>
+#include <efilib.h>
+
+#include <guid.h>
+#include <configtable.h>
+
+void *
+configtable_get_table(EFI_GUID *guid)
+{
+ unsigned int i;
+
+ for (i = 0; i < ST->NumberOfTableEntries; i++) {
+ EFI_CONFIGURATION_TABLE *CT = &ST->ConfigurationTable[i];
+
+ if (CompareGuid(guid, &CT->VendorGuid) == 0) {
+ return CT->VendorTable;
+ }
+ }
+ return NULL;
+}
+
+EFI_IMAGE_EXECUTION_INFO_TABLE *
+configtable_get_image_table(void)
+{
+ return configtable_get_table(&SIG_DB);
+}
+
+EFI_IMAGE_EXECUTION_INFO *
+configtable_find_image(const EFI_DEVICE_PATH *DevicePath)
+{
+ EFI_IMAGE_EXECUTION_INFO_TABLE *t = configtable_get_image_table();
+
+ if (!t)
+ return NULL;
+
+ int entries = t->NumberOfImages;
+ EFI_IMAGE_EXECUTION_INFO *e = t->InformationInfo;
+
+ int i;
+ for (i = 0; i < entries; i++) {
+#ifdef DEBUG_CONFIG
+ Print(L"InfoSize = %d Action = %d\n", e->InfoSize, e->Action);
+
+ /* print what we have for debugging */
+ UINT8 *d = (UINT8 *)e; // + sizeof(UINT32)*2;
+ Print(L"Data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
+ d += 16;
+ Print(L"Data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
+ d += 16;
+ Print(L"Data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
+ d += 16;
+ Print(L"Data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
+ d += 16;
+ Print(L"Data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
+ d += 16;
+ Print(L"Data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
+#endif
+ CHAR16 *name = (CHAR16 *)(e->Data);
+ int skip = 0;
+
+ /* There's a bug in a lot of EFI platforms and they forget to
+ * put the name here. The only real way of detecting it is to
+ * look for either a UC16 NULL or ASCII as UC16 */
+ if (name[0] == '\0' || (e->Data[1] == 0 && e->Data[3] == 0)) {
+ skip = StrSize(name);
+#ifdef DEBUG_CONFIG
+ Print(L"FOUND NAME %s (%d)\n", name, skip);
+#endif
+ }
+ EFI_DEVICE_PATH *dp = (EFI_DEVICE_PATH *)(e->Data + skip), *dpn = dp;
+ if (dp->Type == 0 || dp->Type > 6 || dp->SubType == 0
+ || ((unsigned)((dp->Length[1] << 8) + dp->Length[0]) > e->InfoSize)) {
+ /* Parse error, table corrupt, bail */
+ Print(L"Image Execution Information table corrupt\n");
+ break;
+ }
+
+ UINTN Size;
+ DevicePathInstance(&dpn, &Size);
+#ifdef DEBUG_CONFIG
+ Print(L"Path: %s\n", DevicePathToStr(dp));
+ Print(L"Device Path Size %d\n", Size);
+#endif
+ if (Size > e->InfoSize) {
+ /* parse error; the platform obviously has a
+ * corrupted image table; bail */
+ Print(L"Image Execution Information table corrupt\n");
+ break;
+ }
+
+ if (CompareMem(dp, (void *)DevicePath, Size) == 0) {
+#ifdef DEBUG_CONFIG
+ Print(L"***FOUND\n");
+ console_get_keystroke();
+#endif
+ return e;
+ }
+ e = (EFI_IMAGE_EXECUTION_INFO *)((UINT8 *)e + e->InfoSize);
+ }
+
+#ifdef DEBUG_CONFIG
+ Print(L"***NOT FOUND\n");
+ console_get_keystroke();
+#endif
+
+ return NULL;
+}
+
+int
+configtable_image_is_forbidden(const EFI_DEVICE_PATH *DevicePath)
+{
+ EFI_IMAGE_EXECUTION_INFO *e = configtable_find_image(DevicePath);
+
+ /* Image may not be in DB if it gets executed successfully If it is,
+ * and EFI_IMAGE_EXECUTION_INITIALIZED is not set, then the image
+ * isn't authenticated. If there's no signature, usually
+ * EFI_IMAGE_EXECUTION_AUTH_UNTESTED is set, if the hash is in dbx,
+ * EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND is returned, and if the key is
+ * in dbx, EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED is returned*/
+
+ if (e && (e->Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND
+ || e->Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED)) {
+ /* this means the images signing key is in dbx */
+#ifdef DEBUG_CONFIG
+ Print(L"SIGNATURE IS IN DBX, FORBIDDING EXECUTION\n");
+#endif
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/lib/console.c b/lib/console.c
new file mode 100644
index 00000000..3fee403e
--- /dev/null
+++ b/lib/console.c
@@ -0,0 +1,461 @@
+/*
+ * Copyright 2012 <James.Bottomley@HansenPartnership.com>
+ * Copyright 2013 Red Hat Inc. <pjones@redhat.com>
+ *
+ * see COPYING file
+ */
+#include <efi.h>
+#include <efilib.h>
+
+#include <console.h>
+#include <variables.h>
+#include <errors.h>
+
+static EFI_GUID SHIM_LOCK_GUID = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} };
+
+static int min(int a, int b)
+{
+ if (a < b)
+ return a;
+ return b;
+}
+
+static int
+count_lines(CHAR16 *str_arr[])
+{
+ int i = 0;
+
+ while (str_arr[i])
+ i++;
+ return i;
+}
+
+static void
+SetMem16(CHAR16 *dst, UINT32 n, CHAR16 c)
+{
+ unsigned int i;
+
+ for (i = 0; i < n/2; i++) {
+ dst[i] = c;
+ }
+}
+
+EFI_STATUS
+console_get_keystroke(EFI_INPUT_KEY *key)
+{
+ UINTN EventIndex;
+ EFI_STATUS status;
+
+ do {
+ uefi_call_wrapper(BS->WaitForEvent, 3, 1, &ST->ConIn->WaitForKey, &EventIndex);
+ status = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, key);
+ } while (status == EFI_NOT_READY);
+
+ return status;
+}
+
+void
+console_print_box_at(CHAR16 *str_arr[], int highlight,
+ int start_col, int start_row,
+ int size_cols, int size_rows,
+ int offset, int lines)
+{
+ int i;
+ SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
+ UINTN rows, cols;
+ CHAR16 *Line;
+
+ if (lines == 0)
+ return;
+
+ uefi_call_wrapper(co->QueryMode, 4, co, co->Mode->Mode, &cols, &rows);
+
+ /* last row on screen is unusable without scrolling, so ignore it */
+ rows--;
+
+ if (size_rows < 0)
+ size_rows = rows + size_rows + 1;
+ if (size_cols < 0)
+ size_cols = cols + size_cols + 1;
+
+ if (start_col < 0)
+ start_col = (cols + start_col + 2)/2;
+ if (start_row < 0)
+ start_row = (rows + start_row + 2)/2;
+ if (start_col < 0)
+ start_col = 0;
+ if (start_row < 0)
+ start_row = 0;
+
+ if (start_col > (int)cols || start_row > (int)rows) {
+ Print(L"Starting Position (%d,%d) is off screen\n",
+ start_col, start_row);
+ return;
+ }
+ if (size_cols + start_col > (int)cols)
+ size_cols = cols - start_col;
+ if (size_rows + start_row > (int)rows)
+ size_rows = rows - start_row;
+
+ if (lines > size_rows - 2)
+ lines = size_rows - 2;
+
+ Line = AllocatePool((size_cols+1)*sizeof(CHAR16));
+ if (!Line) {
+ Print(L"Failed Allocation\n");
+ return;
+ }
+
+ SetMem16 (Line, size_cols * 2, BOXDRAW_HORIZONTAL);
+
+ Line[0] = BOXDRAW_DOWN_RIGHT;
+ Line[size_cols - 1] = BOXDRAW_DOWN_LEFT;
+ Line[size_cols] = L'\0';
+ uefi_call_wrapper(co->SetCursorPosition, 3, co, start_col, start_row);
+ uefi_call_wrapper(co->OutputString, 2, co, Line);
+
+ int start;
+ if (offset == 0)
+ /* middle */
+ start = (size_rows - lines)/2 + start_row + offset;
+ else if (offset < 0)
+ /* from bottom */
+ start = start_row + size_rows - lines + offset - 1;
+ else
+ /* from top */
+ start = start_row + offset;
+
+ for (i = start_row + 1; i < size_rows + start_row - 1; i++) {
+ int line = i - start;
+
+ SetMem16 (Line, size_cols*2, L' ');
+ Line[0] = BOXDRAW_VERTICAL;
+ Line[size_cols - 1] = BOXDRAW_VERTICAL;
+ Line[size_cols] = L'\0';
+ if (line >= 0 && line < lines) {
+ CHAR16 *s = str_arr[line];
+ int len = StrLen(s);
+ int col = (size_cols - 2 - len)/2;
+
+ if (col < 0)
+ col = 0;
+
+ CopyMem(Line + col + 1, s, min(len, size_cols - 2)*2);
+ }
+ if (line >= 0 && line == highlight)
+ uefi_call_wrapper(co->SetAttribute, 2, co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
+ uefi_call_wrapper(co->SetCursorPosition, 3, co, start_col, i);
+ uefi_call_wrapper(co->OutputString, 2, co, Line);
+ if (line >= 0 && line == highlight)
+ uefi_call_wrapper(co->SetAttribute, 2, co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
+
+ }
+ SetMem16 (Line, size_cols * 2, BOXDRAW_HORIZONTAL);
+ Line[0] = BOXDRAW_UP_RIGHT;
+ Line[size_cols - 1] = BOXDRAW_UP_LEFT;
+ Line[size_cols] = L'\0';
+ uefi_call_wrapper(co->SetCursorPosition, 3, co, start_col, i);
+ uefi_call_wrapper(co->OutputString, 2, co, Line);
+
+ FreePool (Line);
+
+}
+
+void
+console_print_box(CHAR16 *str_arr[], int highlight)
+{
+ SIMPLE_TEXT_OUTPUT_MODE SavedConsoleMode;
+ SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
+ EFI_INPUT_KEY key;
+
+ CopyMem(&SavedConsoleMode, co->Mode, sizeof(SavedConsoleMode));
+ uefi_call_wrapper(co->EnableCursor, 2, co, FALSE);
+ uefi_call_wrapper(co->SetAttribute, 2, co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
+
+ console_print_box_at(str_arr, highlight, 0, 0, -1, -1, 0,
+ count_lines(str_arr));
+
+ console_get_keystroke(&key);
+
+ uefi_call_wrapper(co->EnableCursor, 2, co, SavedConsoleMode.CursorVisible);
+ uefi_call_wrapper(co->SetCursorPosition, 3, co, SavedConsoleMode.CursorColumn, SavedConsoleMode.CursorRow);
+ uefi_call_wrapper(co->SetAttribute, 2, co, SavedConsoleMode.Attribute);
+}
+
+int
+console_select(CHAR16 *title[], CHAR16* selectors[], unsigned int start)
+{
+ SIMPLE_TEXT_OUTPUT_MODE SavedConsoleMode;
+ SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
+ EFI_INPUT_KEY k;
+ EFI_STATUS status;
+ int selector;
+ unsigned int selector_lines = count_lines(selectors);
+ int selector_max_cols = 0;
+ unsigned int i;
+ int offs_col, offs_row, size_cols, size_rows, lines;
+ unsigned int selector_offset;
+ UINTN cols, rows;
+
+ uefi_call_wrapper(co->QueryMode, 4, co, co->Mode->Mode, &cols, &rows);
+
+ for (i = 0; i < selector_lines; i++) {
+ int len = StrLen(selectors[i]);
+
+ if (len > selector_max_cols)
+ selector_max_cols = len;
+ }
+
+ if (start < 0)
+ start = 0;
+ if (start >= selector_lines)
+ start = selector_lines - 1;
+
+ offs_col = - selector_max_cols - 4;
+ size_cols = selector_max_cols + 4;
+
+ if (selector_lines > rows - 10) {
+ int title_lines = count_lines(title);
+ offs_row = title_lines + 1;
+ size_rows = rows - 3 - title_lines;
+ lines = size_rows - 2;
+ } else {
+ offs_row = - selector_lines - 4;
+ size_rows = selector_lines + 2;
+ lines = selector_lines;
+ }
+
+ if (start > (unsigned)lines) {
+ selector = lines;
+ selector_offset = start - lines;
+ } else {
+ selector = start;
+ selector_offset = 0;
+ }
+
+ CopyMem(&SavedConsoleMode, co->Mode, sizeof(SavedConsoleMode));
+ uefi_call_wrapper(co->EnableCursor, 2, co, FALSE);
+ uefi_call_wrapper(co->SetAttribute, 2, co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
+
+ console_print_box_at(title, -1, 0, 0, -1, -1, 1, count_lines(title));
+
+ console_print_box_at(selectors, selector, offs_col, offs_row,
+ size_cols, size_rows, 0, lines);
+
+ do {
+ status = console_get_keystroke(&k);
+ if (EFI_ERROR (status)) {
+ Print(L"Failed to read the keystroke: %r", status);
+ selector = -1;
+ break;
+ }
+
+ if (k.ScanCode == SCAN_ESC) {
+ selector = -1;
+ break;
+ }
+
+ if (k.ScanCode == SCAN_UP) {
+ if (selector > 0)
+ selector--;
+ else if (selector_offset > 0)
+ selector_offset--;
+ } else if (k.ScanCode == SCAN_DOWN) {
+ if (selector < lines - 1)
+ selector++;
+ else if (selector_offset < (selector_lines - lines))
+ selector_offset++;
+ }
+
+ console_print_box_at(&selectors[selector_offset], selector,
+ offs_col, offs_row,
+ size_cols, size_rows, 0, lines);
+ } while (!(k.ScanCode == SCAN_NULL
+ && k.UnicodeChar == CHAR_CARRIAGE_RETURN));
+
+ uefi_call_wrapper(co->EnableCursor, 2, co, SavedConsoleMode.CursorVisible);
+ uefi_call_wrapper(co->SetCursorPosition, 3, co, SavedConsoleMode.CursorColumn, SavedConsoleMode.CursorRow);
+ uefi_call_wrapper(co->SetAttribute, 2, co, SavedConsoleMode.Attribute);
+
+ if (selector < 0)
+ /* ESC pressed */
+ return selector;
+ return selector + selector_offset;
+}
+
+
+int
+console_yes_no(CHAR16 *str_arr[])
+{
+ return console_select(str_arr, (CHAR16 *[]){ L"No", L"Yes", NULL }, 0);
+}
+
+void
+console_alertbox(CHAR16 **title)
+{
+ console_select(title, (CHAR16 *[]){ L"OK", 0 }, 0);
+}
+
+void
+console_errorbox(CHAR16 *err)
+{
+ CHAR16 **err_arr = (CHAR16 *[]){
+ L"ERROR",
+ L"",
+ 0,
+ 0,
+ };
+
+ err_arr[2] = err;
+
+ console_alertbox(err_arr);
+}
+
+void
+console_notify(CHAR16 *string)
+{
+ CHAR16 **str_arr = (CHAR16 *[]){
+ 0,
+ 0,
+ };
+
+ str_arr[0] = string;
+
+ console_alertbox(str_arr);
+}
+
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
+
+/* Copy of gnu-efi-3.0 with the added secure boot strings */
+static struct {
+ EFI_STATUS Code;
+ WCHAR *Desc;
+} error_table[] = {
+ { EFI_SUCCESS, L"Success"},
+ { EFI_LOAD_ERROR, L"Load Error"},
+ { EFI_INVALID_PARAMETER, L"Invalid Parameter"},
+ { EFI_UNSUPPORTED, L"Unsupported"},
+ { EFI_BAD_BUFFER_SIZE, L"Bad Buffer Size"},
+ { EFI_BUFFER_TOO_SMALL, L"Buffer Too Small"},
+ { EFI_NOT_READY, L"Not Ready"},
+ { EFI_DEVICE_ERROR, L"Device Error"},
+ { EFI_WRITE_PROTECTED, L"Write Protected"},
+ { EFI_OUT_OF_RESOURCES, L"Out of Resources"},
+ { EFI_VOLUME_CORRUPTED, L"Volume Corrupt"},
+ { EFI_VOLUME_FULL, L"Volume Full"},
+ { EFI_NO_MEDIA, L"No Media"},
+ { EFI_MEDIA_CHANGED, L"Media changed"},
+ { EFI_NOT_FOUND, L"Not Found"},
+ { EFI_ACCESS_DENIED, L"Access Denied"},
+ { EFI_NO_RESPONSE, L"No Response"},
+ { EFI_NO_MAPPING, L"No mapping"},
+ { EFI_TIMEOUT, L"Time out"},
+ { EFI_NOT_STARTED, L"Not started"},
+ { EFI_ALREADY_STARTED, L"Already started"},
+ { EFI_ABORTED, L"Aborted"},
+ { EFI_ICMP_ERROR, L"ICMP Error"},
+ { EFI_TFTP_ERROR, L"TFTP Error"},
+ { EFI_PROTOCOL_ERROR, L"Protocol Error"},
+ { EFI_INCOMPATIBLE_VERSION, L"Incompatible Version"},
+ { EFI_SECURITY_VIOLATION, L"Security Violation"},
+
+ // warnings
+ { EFI_WARN_UNKOWN_GLYPH, L"Warning Unknown Glyph"},
+ { EFI_WARN_DELETE_FAILURE, L"Warning Delete Failure"},
+ { EFI_WARN_WRITE_FAILURE, L"Warning Write Failure"},
+ { EFI_WARN_BUFFER_TOO_SMALL, L"Warning Buffer Too Small"},
+ { 0, NULL}
+} ;
+
+
+static CHAR16 *
+err_string (
+ IN EFI_STATUS Status
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; error_table[Index].Desc; Index +=1) {
+ if (error_table[Index].Code == Status) {
+ return error_table[Index].Desc;
+ }
+ }
+
+ return L"";
+}
+
+
+void
+console_error(CHAR16 *err, EFI_STATUS status)
+{
+ CHAR16 **err_arr = (CHAR16 *[]){
+ L"ERROR",
+ L"",
+ 0,
+ 0,
+ };
+ CHAR16 str[512];
+
+ SPrint(str, sizeof(str), L"%s: (%d) %s", err, status, err_string(status));
+
+ err_arr[2] = str;
+
+ console_alertbox(err_arr);
+}
+
+void
+console_reset(void)
+{
+ SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
+
+ uefi_call_wrapper(co->Reset, 2, co, TRUE);
+ /* set mode 0 - required to be 80x25 */
+ uefi_call_wrapper(co->SetMode, 2, co, 0);
+ uefi_call_wrapper(co->ClearScreen, 1, co);
+}
+
+UINT8 verbose;
+
+VOID
+setup_verbosity(VOID)
+{
+ EFI_STATUS status;
+ EFI_GUID guid = SHIM_LOCK_GUID;
+ UINT8 verbose_check;
+ UINTN verbose_check_size;
+
+ verbose_check_size = 1;
+ status = get_variable(L"SHIM_VERBOSE", (void *)&verbose_check,
+ &verbose_check_size, guid);
+ verbose = 0;
+ if (!EFI_ERROR(status))
+ verbose = verbose_check;
+}
+
+VOID setup_console (int text)
+{
+ EFI_STATUS status;
+ EFI_GUID console_control_guid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
+ EFI_CONSOLE_CONTROL_PROTOCOL *concon;
+ static EFI_CONSOLE_CONTROL_SCREEN_MODE mode =
+ EfiConsoleControlScreenGraphics;
+ EFI_CONSOLE_CONTROL_SCREEN_MODE new_mode;
+
+ status = LibLocateProtocol(&console_control_guid, (VOID **)&concon);
+ if (status != EFI_SUCCESS)
+ return;
+
+ if (text) {
+ new_mode = EfiConsoleControlScreenText;
+
+ status = uefi_call_wrapper(concon->GetMode, 4, concon, &mode,
+ 0, 0);
+ /* If that didn't work, assume it's graphics */
+ if (status != EFI_SUCCESS)
+ mode = EfiConsoleControlScreenGraphics;
+ } else {
+ new_mode = mode;
+ }
+
+ uefi_call_wrapper(concon->SetMode, 2, concon, new_mode);
+}
diff --git a/lib/execute.c b/lib/execute.c
new file mode 100644
index 00000000..89328c68
--- /dev/null
+++ b/lib/execute.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2012 <James.Bottomley@HansenPartnership.com>
+ *
+ * see COPYING file
+ *
+ * --
+ *
+ * generate_path is a cut and paste from
+ *
+ * git://github.com/mjg59/shim.git
+ *
+ * Code Copyright 2012 Red Hat, Inc <mjg@redhat.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+#include <guid.h>
+#include <execute.h>
+
+EFI_STATUS
+generate_path(CHAR16* name, EFI_LOADED_IMAGE *li, EFI_DEVICE_PATH **path, CHAR16 **PathName)
+{
+ unsigned int pathlen;
+ EFI_STATUS efi_status = EFI_SUCCESS;
+ CHAR16 *devpathstr = DevicePathToStr(li->FilePath),
+ *found = NULL;
+ unsigned int i;
+
+ for (i = 0; i < StrLen(devpathstr); i++) {
+ if (devpathstr[i] == '/')
+ devpathstr[i] = '\\';
+ if (devpathstr[i] == '\\')
+ found = &devpathstr[i];
+ }
+ if (!found) {
+ pathlen = 0;
+ } else {
+ while (*(found - 1) == '\\')
+ --found;
+ *found = '\0';
+ pathlen = StrLen(devpathstr);
+ }
+
+ if (name[0] != '\\')
+ pathlen++;
+
+ *PathName = AllocatePool((pathlen + 1 + StrLen(name))*sizeof(CHAR16));
+
+ if (!*PathName) {
+ Print(L"Failed to allocate path buffer\n");
+ efi_status = EFI_OUT_OF_RESOURCES;
+ goto error;
+ }
+
+ StrCpy(*PathName, devpathstr);
+
+ if (name[0] != '\\')
+ StrCat(*PathName, L"\\");
+ StrCat(*PathName, name);
+
+ *path = FileDevicePath(li->DeviceHandle, *PathName);
+
+error:
+ FreePool(devpathstr);
+
+ return efi_status;
+}
+
+EFI_STATUS
+execute(EFI_HANDLE image, CHAR16 *name)
+{
+ EFI_STATUS status;
+ EFI_HANDLE h;
+ EFI_LOADED_IMAGE *li;
+ EFI_DEVICE_PATH *devpath;
+ CHAR16 *PathName;
+
+ status = uefi_call_wrapper(BS->HandleProtocol, 3, image,
+ &IMAGE_PROTOCOL, (void **)&li);
+ if (status != EFI_SUCCESS)
+ return status;
+
+
+ status = generate_path(name, li, &devpath, &PathName);
+ if (status != EFI_SUCCESS)
+ return status;
+
+ status = uefi_call_wrapper(BS->LoadImage, 6, FALSE, image,
+ devpath, NULL, 0, &h);
+ if (status != EFI_SUCCESS)
+ goto out;
+
+ status = uefi_call_wrapper(BS->StartImage, 3, h, NULL, NULL);
+ uefi_call_wrapper(BS->UnloadImage, 1, h);
+
+ out:
+ FreePool(PathName);
+ FreePool(devpath);
+ return status;
+}
diff --git a/lib/guid.c b/lib/guid.c
new file mode 100644
index 00000000..5f5a03ff
--- /dev/null
+++ b/lib/guid.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2012 <James.Bottomley@HansenPartnership.com>
+ *
+ * see COPYING file
+ */
+
+#include <guid.h>
+
+/* all the necessary guids */
+EFI_GUID GV_GUID = EFI_GLOBAL_VARIABLE;
+EFI_GUID SIG_DB = { 0xd719b2cb, 0x3d3a, 0x4596, {0xa3, 0xbc, 0xda, 0xd0, 0xe, 0x67, 0x65, 0x6f }};
+
+EFI_GUID X509_GUID = { 0xa5c059a1, 0x94e4, 0x4aa7, {0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72} };
+EFI_GUID RSA2048_GUID = { 0x3c5766e8, 0x269c, 0x4e34, {0xaa, 0x14, 0xed, 0x77, 0x6e, 0x85, 0xb3, 0xb6} };
+EFI_GUID PKCS7_GUID = { 0x4aafd29d, 0x68df, 0x49ee, {0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7} };
+EFI_GUID IMAGE_PROTOCOL = LOADED_IMAGE_PROTOCOL;
+EFI_GUID SIMPLE_FS_PROTOCOL = SIMPLE_FILE_SYSTEM_PROTOCOL;
+EFI_GUID EFI_CERT_SHA1_GUID = { 0x826ca512, 0xcf10, 0x4ac9, {0xb1, 0x87, 0xbe, 0x1, 0x49, 0x66, 0x31, 0xbd }};
+EFI_GUID EFI_CERT_SHA256_GUID = { 0xc1c41626, 0x504c, 0x4092, { 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 } };
+EFI_GUID MOK_OWNER = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} };
+EFI_GUID SECURITY_PROTOCOL_GUID = { 0xA46423E3, 0x4617, 0x49f1, {0xB9, 0xFF, 0xD1, 0xBF, 0xA9, 0x11, 0x58, 0x39 } };
+EFI_GUID SECURITY2_PROTOCOL_GUID = { 0x94ab2f58, 0x1438, 0x4ef1, {0x91, 0x52, 0x18, 0x94, 0x1a, 0x3a, 0x0e, 0x68 } };
diff --git a/lib/security_policy.c b/lib/security_policy.c
new file mode 100644
index 00000000..9af3a107
--- /dev/null
+++ b/lib/security_policy.c
@@ -0,0 +1,352 @@
+/*
+ * Copyright 2012 <James.Bottomley@HansenPartnership.com>
+ *
+ * see COPYING file
+ *
+ * Install and remove a platform security2 override policy
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+#include <guid.h>
+#include <variables.h>
+#include <simple_file.h>
+#include <errors.h>
+
+#if defined(OVERRIDE_SECURITY_POLICY)
+#include <security_policy.h>
+
+/*
+ * See the UEFI Platform Initialization manual (Vol2: DXE) for this
+ */
+struct _EFI_SECURITY2_PROTOCOL;
+struct _EFI_SECURITY_PROTOCOL;
+typedef struct _EFI_SECURITY2_PROTOCOL EFI_SECURITY2_PROTOCOL;
+typedef struct _EFI_SECURITY_PROTOCOL EFI_SECURITY_PROTOCOL;
+typedef EFI_DEVICE_PATH EFI_DEVICE_PATH_PROTOCOL;
+
+typedef EFI_STATUS (EFIAPI *EFI_SECURITY_FILE_AUTHENTICATION_STATE) (
+ const EFI_SECURITY_PROTOCOL *This,
+ UINT32 AuthenticationStatus,
+ const EFI_DEVICE_PATH_PROTOCOL *File
+ );
+typedef EFI_STATUS (EFIAPI *EFI_SECURITY2_FILE_AUTHENTICATION) (
+ const EFI_SECURITY2_PROTOCOL *This,
+ const EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ VOID *FileBuffer,
+ UINTN FileSize,
+ BOOLEAN BootPolicy
+ );
+
+struct _EFI_SECURITY2_PROTOCOL {
+ EFI_SECURITY2_FILE_AUTHENTICATION FileAuthentication;
+};
+
+struct _EFI_SECURITY_PROTOCOL {
+ EFI_SECURITY_FILE_AUTHENTICATION_STATE FileAuthenticationState;
+};
+
+
+static UINT8 *security_policy_esl = NULL;
+static UINTN security_policy_esl_len;
+static SecurityHook extra_check = NULL;
+
+static EFI_SECURITY_FILE_AUTHENTICATION_STATE esfas = NULL;
+static EFI_SECURITY2_FILE_AUTHENTICATION es2fa = NULL;
+
+static EFI_STATUS thunk_security_policy_authentication(
+ const EFI_SECURITY_PROTOCOL *This,
+ UINT32 AuthenticationStatus,
+ const EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+__attribute__((unused));
+
+static EFI_STATUS thunk_security2_policy_authentication(
+ const EFI_SECURITY2_PROTOCOL *This,
+ const EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ VOID *FileBuffer,
+ UINTN FileSize,
+ BOOLEAN BootPolicy
+ )
+__attribute__((unused));
+
+static __attribute__((used)) EFI_STATUS
+security2_policy_authentication (
+ const EFI_SECURITY2_PROTOCOL *This,
+ const EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ VOID *FileBuffer,
+ UINTN FileSize,
+ BOOLEAN BootPolicy
+ )
+{
+ EFI_STATUS status, auth;
+
+ /* Chain original security policy */
+
+ status = uefi_call_wrapper(es2fa, 5, This, DevicePath, FileBuffer,
+ FileSize, BootPolicy);
+
+ /* if OK, don't bother with MOK check */
+ if (status == EFI_SUCCESS)
+ return status;
+
+ if (extra_check)
+ auth = extra_check(FileBuffer, FileSize);
+ else
+ return EFI_SECURITY_VIOLATION;
+
+ if (auth == EFI_SECURITY_VIOLATION || auth == EFI_ACCESS_DENIED)
+ /* return previous status, which is the correct one
+ * for the platform: may be either EFI_ACCESS_DENIED
+ * or EFI_SECURITY_VIOLATION */
+ return status;
+
+ return auth;
+}
+
+static __attribute__((used)) EFI_STATUS
+security_policy_authentication (
+ const EFI_SECURITY_PROTOCOL *This,
+ UINT32 AuthenticationStatus,
+ const EFI_DEVICE_PATH_PROTOCOL *DevicePathConst
+ )
+{
+ EFI_STATUS status, fail_status;
+ EFI_DEVICE_PATH *DevPath
+ = DuplicateDevicePath((EFI_DEVICE_PATH *)DevicePathConst),
+ *OrigDevPath = DevPath;
+ EFI_HANDLE h;
+ EFI_FILE *f;
+ VOID *FileBuffer;
+ UINTN FileSize;
+ CHAR16* DevPathStr;
+
+ /* Chain original security policy */
+ status = uefi_call_wrapper(esfas, 3, This, AuthenticationStatus,
+ DevicePathConst);
+
+ /* if OK avoid checking MOK: It's a bit expensive to
+ * read the whole file in again (esfas already did this) */
+ if (status == EFI_SUCCESS)
+ goto out;
+
+ /* capture failure status: may be either EFI_ACCESS_DENIED or
+ * EFI_SECURITY_VIOLATION */
+ fail_status = status;
+
+ status = uefi_call_wrapper(BS->LocateDevicePath, 3,
+ &SIMPLE_FS_PROTOCOL, &DevPath, &h);
+ if (status != EFI_SUCCESS)
+ goto out;
+
+ DevPathStr = DevicePathToStr(DevPath);
+
+ status = simple_file_open_by_handle(h, DevPathStr, &f,
+ EFI_FILE_MODE_READ);
+ FreePool(DevPathStr);
+ if (status != EFI_SUCCESS)
+ goto out;
+
+ status = simple_file_read_all(f, &FileSize, &FileBuffer);
+ simple_file_close(f);
+ if (status != EFI_SUCCESS)
+ goto out;
+
+ if (extra_check)
+ status = extra_check(FileBuffer, FileSize);
+ else
+ status = EFI_SECURITY_VIOLATION;
+ FreePool(FileBuffer);
+
+ if (status == EFI_ACCESS_DENIED || status == EFI_SECURITY_VIOLATION)
+ /* return what the platform originally said */
+ status = fail_status;
+ out:
+ FreePool(OrigDevPath);
+ return status;
+}
+
+
+/* Nasty: ELF and EFI have different calling conventions. Here is the map for
+ * calling ELF -> EFI
+ *
+ * 1) rdi -> rcx (32 saved)
+ * 2) rsi -> rdx (32 saved)
+ * 3) rdx -> r8 ( 32 saved)
+ * 4) rcx -> r9 (32 saved)
+ * 5) r8 -> 32(%rsp) (48 saved)
+ * 6) r9 -> 40(%rsp) (48 saved)
+ * 7) pad+0(%rsp) -> 48(%rsp) (64 saved)
+ * 8) pad+8(%rsp) -> 56(%rsp) (64 saved)
+ * 9) pad+16(%rsp) -> 64(%rsp) (80 saved)
+ * 10) pad+24(%rsp) -> 72(%rsp) (80 saved)
+ * 11) pad+32(%rsp) -> 80(%rsp) (96 saved)
+
+ *
+ * So for a five argument callback, the map is ignore the first two arguments
+ * and then map (EFI -> ELF) assuming pad = 0.
+ *
+ * ARG4 -> ARG1
+ * ARG3 -> ARG2
+ * ARG5 -> ARG3
+ * ARG6 -> ARG4
+ * ARG11 -> ARG5
+ *
+ * Calling conventions also differ over volatile and preserved registers in
+ * MS: RBX, RBP, RDI, RSI, R12, R13, R14, and R15 are considered nonvolatile .
+ * In ELF: Registers %rbp, %rbx and %r12 through %r15 “belong” to the calling
+ * function and the called function is required to preserve their values.
+ *
+ * This means when accepting a function callback from MS -> ELF, we have to do
+ * separate preservation on %rdi, %rsi before swizzling the arguments and
+ * handing off to the ELF function.
+ */
+
+asm (
+".type security2_policy_authentication,@function\n"
+"thunk_security2_policy_authentication:\n\t"
+ "mov 0x28(%rsp), %r10 # ARG5\n\t"
+ "push %rdi\n\t"
+ "push %rsi\n\t"
+ "mov %r10, %rdi\n\t"
+ "subq $8, %rsp # space for storing stack pad\n\t"
+ "mov $0x08, %rax\n\t"
+ "mov $0x10, %r10\n\t"
+ "and %rsp, %rax\n\t"
+ "cmovnz %rax, %r11\n\t"
+ "cmovz %r10, %r11\n\t"
+ "subq %r11, %rsp\n\t"
+ "addq $8, %r11\n\t"
+ "mov %r11, (%rsp)\n\t"
+"# five argument swizzle\n\t"
+ "mov %rdi, %r10\n\t"
+ "mov %rcx, %rdi\n\t"
+ "mov %rdx, %rsi\n\t"
+ "mov %r8, %rdx\n\t"
+ "mov %r9, %rcx\n\t"
+ "mov %r10, %r8\n\t"
+ "callq security2_policy_authentication@PLT\n\t"
+ "mov (%rsp), %r11\n\t"
+ "addq %r11, %rsp\n\t"
+ "pop %rsi\n\t"
+ "pop %rdi\n\t"
+ "ret\n"
+);
+
+asm (
+".type security_policy_authentication,@function\n"
+"thunk_security_policy_authentication:\n\t"
+ "push %rdi\n\t"
+ "push %rsi\n\t"
+ "subq $8, %rsp # space for storing stack pad\n\t"
+ "mov $0x08, %rax\n\t"
+ "mov $0x10, %r10\n\t"
+ "and %rsp, %rax\n\t"
+ "cmovnz %rax, %r11\n\t"
+ "cmovz %r10, %r11\n\t"
+ "subq %r11, %rsp\n\t"
+ "addq $8, %r11\n\t"
+ "mov %r11, (%rsp)\n\t"
+"# three argument swizzle\n\t"
+ "mov %rcx, %rdi\n\t"
+ "mov %rdx, %rsi\n\t"
+ "mov %r8, %rdx\n\t"
+ "callq security_policy_authentication@PLT\n\t"
+ "mov (%rsp), %r11\n\t"
+ "addq %r11, %rsp\n\t"
+ "pop %rsi\n\t"
+ "pop %rdi\n\t"
+ "ret\n"
+);
+
+EFI_STATUS
+security_policy_install(SecurityHook hook)
+{
+ EFI_SECURITY_PROTOCOL *security_protocol;
+ EFI_SECURITY2_PROTOCOL *security2_protocol = NULL;
+ EFI_STATUS status;
+
+ if (esfas)
+ /* Already Installed */
+ return EFI_ALREADY_STARTED;
+
+ /* Don't bother with status here. The call is allowed
+ * to fail, since SECURITY2 was introduced in PI 1.2.1
+ * If it fails, use security2_protocol == NULL as indicator */
+ uefi_call_wrapper(BS->LocateProtocol, 3,
+ &SECURITY2_PROTOCOL_GUID, NULL,
+ &security2_protocol);
+
+ status = uefi_call_wrapper(BS->LocateProtocol, 3,
+ &SECURITY_PROTOCOL_GUID, NULL,
+ &security_protocol);
+ if (status != EFI_SUCCESS)
+ /* This one is mandatory, so there's a serious problem */
+ return status;
+
+ if (security2_protocol) {
+ es2fa = security2_protocol->FileAuthentication;
+ security2_protocol->FileAuthentication =
+ thunk_security2_policy_authentication;
+ }
+
+ esfas = security_protocol->FileAuthenticationState;
+ security_protocol->FileAuthenticationState =
+ thunk_security_policy_authentication;
+
+ if (hook)
+ extra_check = hook;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+security_policy_uninstall(void)
+{
+ EFI_STATUS status;
+
+ if (esfas) {
+ EFI_SECURITY_PROTOCOL *security_protocol;
+
+ status = uefi_call_wrapper(BS->LocateProtocol, 3,
+ &SECURITY_PROTOCOL_GUID, NULL,
+ &security_protocol);
+
+ if (status != EFI_SUCCESS)
+ return status;
+
+ security_protocol->FileAuthenticationState = esfas;
+ esfas = NULL;
+ } else {
+ /* nothing installed */
+ return EFI_NOT_STARTED;
+ }
+
+ if (es2fa) {
+ EFI_SECURITY2_PROTOCOL *security2_protocol;
+
+ status = uefi_call_wrapper(BS->LocateProtocol, 3,
+ &SECURITY2_PROTOCOL_GUID, NULL,
+ &security2_protocol);
+
+ if (status != EFI_SUCCESS)
+ return status;
+
+ security2_protocol->FileAuthentication = es2fa;
+ es2fa = NULL;
+ }
+
+ if (extra_check)
+ extra_check = NULL;
+
+ return EFI_SUCCESS;
+}
+
+void
+security_protocol_set_hashes(unsigned char *esl, int len)
+{
+ security_policy_esl = esl;
+ security_policy_esl_len = len;
+}
+#endif /* OVERRIDE_SECURITY_POLICY */
diff --git a/lib/shell.c b/lib/shell.c
new file mode 100644
index 00000000..afd3952c
--- /dev/null
+++ b/lib/shell.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2012 <James.Bottomley@HansenPartnership.com>
+ *
+ * see COPYING file
+ *
+ * misc shell helper functions
+ */
+#include <efi.h>
+#include <efilib.h>
+
+#include <shell.h>
+
+EFI_STATUS
+argsplit(EFI_HANDLE image, int *argc, CHAR16*** ARGV)
+{
+ unsigned int i, count = 1;
+ EFI_STATUS status;
+ EFI_LOADED_IMAGE *info;
+ CHAR16 *start;
+
+ *argc = 0;
+
+ status = uefi_call_wrapper(BS->HandleProtocol, 3, image, &LoadedImageProtocol, (VOID **) &info);
+ if (EFI_ERROR(status)) {
+ Print(L"Failed to get arguments\n");
+ return status;
+ }
+
+ for (i = 0; i < info->LoadOptionsSize; i += 2) {
+ CHAR16 *c = (CHAR16 *)(info->LoadOptions + i);
+ if (*c == L' ' && *(c+1) != '\0') {
+ (*argc)++;
+ }
+ }
+
+ (*argc)++; /* we counted spaces, so add one for initial */
+
+ *ARGV = AllocatePool(*argc * sizeof(**ARGV));
+ if (!*ARGV) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ (*ARGV)[0] = (CHAR16 *)info->LoadOptions;
+ for (i = 0; i < info->LoadOptionsSize; i += 2) {
+ CHAR16 *c = (CHAR16 *)(info->LoadOptions + i);
+ if (*c == L' ') {
+ *c = L'\0';
+ if (*(c + 1) == '\0')
+ /* strip trailing space */
+ break;
+ start = c + 1;
+ (*ARGV)[count++] = start;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/lib/simple_file.c b/lib/simple_file.c
new file mode 100644
index 00000000..d345d870
--- /dev/null
+++ b/lib/simple_file.c
@@ -0,0 +1,528 @@
+/*
+ * Copyright 2012 <James.Bottomley@HansenPartnership.com>
+ *
+ * see COPYING file
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+#include <console.h>
+#include <simple_file.h>
+#include <efiauthenticated.h>
+#include <execute.h> /* for generate_path() */
+
+static EFI_GUID IMAGE_PROTOCOL = LOADED_IMAGE_PROTOCOL;
+static EFI_GUID SIMPLE_FS_PROTOCOL = SIMPLE_FILE_SYSTEM_PROTOCOL;
+static EFI_GUID FILE_INFO = EFI_FILE_INFO_ID;
+static EFI_GUID FS_INFO = EFI_FILE_SYSTEM_INFO_ID;
+
+EFI_STATUS
+simple_file_open_by_handle(EFI_HANDLE device, CHAR16 *name, EFI_FILE **file, UINT64 mode)
+{
+ EFI_STATUS efi_status;
+ EFI_FILE_IO_INTERFACE *drive;
+ EFI_FILE *root;
+
+ efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, device,
+ &SIMPLE_FS_PROTOCOL, (void **)&drive);
+
+ if (efi_status != EFI_SUCCESS) {
+ Print(L"Unable to find simple file protocol (%d)\n", efi_status);
+ goto error;
+ }
+
+ efi_status = uefi_call_wrapper(drive->OpenVolume, 2, drive, &root);
+
+ if (efi_status != EFI_SUCCESS) {
+ Print(L"Failed to open drive volume (%d)\n", efi_status);
+ goto error;
+ }
+
+ efi_status = uefi_call_wrapper(root->Open, 5, root, file, name,
+ mode, 0);
+
+ error:
+ return efi_status;
+}
+
+EFI_STATUS
+simple_file_open(EFI_HANDLE image, CHAR16 *name, EFI_FILE **file, UINT64 mode)
+{
+ EFI_STATUS efi_status;
+ EFI_HANDLE device;
+ EFI_LOADED_IMAGE *li;
+ EFI_DEVICE_PATH *loadpath = NULL;
+ CHAR16 *PathName = NULL;
+
+ efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, image,
+ &IMAGE_PROTOCOL, (void **)&li);
+
+ if (efi_status != EFI_SUCCESS)
+ return simple_file_open_by_handle(image, name, file, mode);
+
+ efi_status = generate_path(name, li, &loadpath, &PathName);
+
+ if (efi_status != EFI_SUCCESS) {
+ Print(L"Unable to generate load path for %s\n", name);
+ return efi_status;
+ }
+
+ device = li->DeviceHandle;
+
+ efi_status = simple_file_open_by_handle(device, PathName, file, mode);
+
+ FreePool(PathName);
+ FreePool(loadpath);
+
+ return efi_status;
+}
+
+EFI_STATUS
+simple_dir_read_all_by_handle(EFI_HANDLE image, EFI_FILE *file, CHAR16* name, EFI_FILE_INFO **entries,
+ int *count)
+{
+ EFI_STATUS status;
+ char buf[4096];
+ UINTN size = sizeof(buf);
+ EFI_FILE_INFO *fi = (void *)buf;
+
+ status = uefi_call_wrapper(file->GetInfo, 4, file, &FILE_INFO,
+ &size, fi);
+ if (status != EFI_SUCCESS) {
+ Print(L"Failed to get file info\n");
+ goto out;
+ }
+ if ((fi->Attribute & EFI_FILE_DIRECTORY) == 0) {
+ Print(L"Not a directory %s\n", name);
+ status = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+ size = 0;
+ *count = 0;
+ for (;;) {
+ UINTN len = sizeof(buf);
+ status = uefi_call_wrapper(file->Read, 3, file, &len, buf);
+ if (status != EFI_SUCCESS || len == 0)
+ break;
+ (*count)++;
+ size += len;
+ }
+ uefi_call_wrapper(file->SetPosition, 2, file, 0);
+
+ char *ptr = AllocatePool(size);
+ *entries = (EFI_FILE_INFO *)ptr;
+ if (!*entries)
+ return EFI_OUT_OF_RESOURCES;
+ int i;
+ for (i = 0; i < *count; i++) {
+ UINTN len = size;
+ uefi_call_wrapper(file->Read, 3, file, &len, ptr);
+ ptr += len;
+ size -= len;
+ }
+ status = EFI_SUCCESS;
+ out:
+ simple_file_close(file);
+ if (status != EFI_SUCCESS && *entries) {
+ FreePool(*entries);
+ *entries = NULL;
+ }
+ return status;
+}
+
+EFI_STATUS
+simple_dir_read_all(EFI_HANDLE image, CHAR16 *name, EFI_FILE_INFO **entries,
+ int *count)
+{
+ EFI_FILE *file;
+ EFI_STATUS status;
+
+ status = simple_file_open(image, name, &file, EFI_FILE_MODE_READ);
+ if (status != EFI_SUCCESS) {
+ Print(L"failed to open file %s: %d\n", name, status);
+ return status;
+ }
+
+ return simple_dir_read_all_by_handle(image, file, name, entries, count);
+}
+
+EFI_STATUS
+simple_file_read_all(EFI_FILE *file, UINTN *size, void **buffer)
+{
+ EFI_STATUS efi_status;
+ EFI_FILE_INFO *fi;
+ char buf[1024];
+
+ *size = sizeof(buf);
+ fi = (void *)buf;
+
+
+ efi_status = uefi_call_wrapper(file->GetInfo, 4, file, &FILE_INFO,
+ size, fi);
+ if (efi_status != EFI_SUCCESS) {
+ Print(L"Failed to get file info\n");
+ return efi_status;
+ }
+
+ *size = fi->FileSize;
+
+ *buffer = AllocatePool(*size);
+ if (!*buffer) {
+ Print(L"Failed to allocate buffer of size %d\n", *size);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ efi_status = uefi_call_wrapper(file->Read, 3, file, size, *buffer);
+
+ return efi_status;
+}
+
+
+EFI_STATUS
+simple_file_write_all(EFI_FILE *file, UINTN size, void *buffer)
+{
+ EFI_STATUS efi_status;
+
+ efi_status = uefi_call_wrapper(file->Write, 3, file, &size, buffer);
+
+ return efi_status;
+}
+
+void
+simple_file_close(EFI_FILE *file)
+{
+ uefi_call_wrapper(file->Close, 1, file);
+}
+
+EFI_STATUS
+simple_volume_selector(CHAR16 **title, CHAR16 **selected, EFI_HANDLE *h)
+{
+ UINTN count, i;
+ EFI_HANDLE *vol_handles = NULL;
+ EFI_STATUS status;
+ CHAR16 **entries;
+ int val;
+
+ uefi_call_wrapper(BS->LocateHandleBuffer, 5, ByProtocol,
+ &SIMPLE_FS_PROTOCOL, NULL, &count, &vol_handles);
+
+ if (!count || !vol_handles)
+ return EFI_NOT_FOUND;
+
+ entries = AllocatePool(sizeof(CHAR16 *) * (count+1));
+ if (!entries)
+ return EFI_OUT_OF_RESOURCES;
+
+ for (i = 0; i < count; i++) {
+ char buf[4096];
+ UINTN size = sizeof(buf);
+ EFI_FILE_SYSTEM_INFO *fi = (void *)buf;
+ EFI_FILE *root;
+ CHAR16 *name;
+ EFI_FILE_IO_INTERFACE *drive;
+
+ status = uefi_call_wrapper(BS->HandleProtocol, 3,
+ vol_handles[i],
+ &SIMPLE_FS_PROTOCOL,
+ (void **)&drive);
+ if (status != EFI_SUCCESS || !drive)
+ continue;
+
+ status = uefi_call_wrapper(drive->OpenVolume, 2, drive, &root);
+ if (status != EFI_SUCCESS)
+ continue;
+
+ status = uefi_call_wrapper(root->GetInfo, 4, root, &FS_INFO,
+ &size, fi);
+ if (status != EFI_SUCCESS)
+ continue;
+
+ name = fi->VolumeLabel;
+
+ if (!name || StrLen(name) == 0 || StrCmp(name, L" ") == 0)
+ name = DevicePathToStr(DevicePathFromHandle(vol_handles[i]));
+
+ entries[i] = AllocatePool((StrLen(name) + 2) * sizeof(CHAR16));
+ if (!entries[i])
+ break;
+ StrCpy(entries[i], name);
+ }
+ entries[i] = NULL;
+
+ val = console_select(title, entries, 0);
+
+ if (val >= 0) {
+ *selected = AllocatePool((StrLen(entries[val]) + 1) * sizeof(CHAR16));
+ if (*selected) {
+ StrCpy(*selected , entries[val]);
+ }
+ *h = vol_handles[val];
+ } else {
+ *selected = NULL;
+ *h = 0;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (entries[i])
+ FreePool(entries[i]);
+ }
+ FreePool(entries);
+ FreePool(vol_handles);
+
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+simple_dir_filter(EFI_HANDLE image, CHAR16 *name, CHAR16 *filter,
+ CHAR16 ***result, int *count, EFI_FILE_INFO **entries)
+{
+ EFI_STATUS status;
+ int tot, offs = StrLen(filter), i, c, filtercount = 1;
+ EFI_FILE_INFO *next;
+ void *ptr;
+ CHAR16 *newfilter = AllocatePool((StrLen(filter) + 1) * sizeof(CHAR16)),
+ **filterarr;
+
+ if (!newfilter)
+ return EFI_OUT_OF_RESOURCES;
+
+ /* just in case efi ever stops writeable strings */
+ StrCpy(newfilter, filter);
+
+ for (i = 0; i < offs; i++) {
+ if (filter[i] == '|')
+ filtercount++;
+ }
+ filterarr = AllocatePool(filtercount * sizeof(void *));
+ if (!filterarr)
+ return EFI_OUT_OF_RESOURCES;
+ c = 0;
+ filterarr[c++] = newfilter;
+ for (i = 0; i < offs; i++) {
+ if (filter[i] == '|') {
+ newfilter[i] = '\0';
+ filterarr[c++] = &newfilter[i+1];
+ }
+ }
+
+ *count = 0;
+
+ status = simple_dir_read_all(image, name, entries, &tot);
+
+ if (status != EFI_SUCCESS)
+ goto out;
+ ptr = next = *entries;
+
+ for (i = 0; i < tot; i++) {
+ int len = StrLen(next->FileName);
+
+ for (c = 0; c < filtercount; c++) {
+ offs = StrLen(filterarr[c]);
+
+ if (StrCmp(&next->FileName[len - offs], filterarr[c]) == 0
+ || (next->Attribute & EFI_FILE_DIRECTORY)) {
+ (*count)++;
+ break;
+ }
+ }
+ ptr += OFFSET_OF(EFI_FILE_INFO, FileName) + (len + 1)*sizeof(CHAR16);
+ next = ptr;
+ }
+ if (*count)
+ *result = AllocatePool(((*count) + 1) * sizeof(void *));
+ else
+ *result = AllocatePool(2 * sizeof(void *));
+
+ *count = 0;
+ ptr = next = *entries;
+
+ for (i = 0; i < tot; i++) {
+ int len = StrLen(next->FileName);
+
+ if (StrCmp(next->FileName, L".") == 0)
+ /* ignore . directory */
+ goto next;
+
+ if (next->Attribute & EFI_FILE_DIRECTORY) {
+ (*result)[(*count)] = PoolPrint(L"%s/", next->FileName);
+ if (!(*result)[(*count)]) {
+ Print(L"Failed to allocate buffer");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ (*count)++;
+ goto next;
+ }
+
+ for (c = 0; c < filtercount; c++) {
+ offs = StrLen(filterarr[c]);
+
+ if (StrCmp(&next->FileName[len - offs], filterarr[c]) == 0) {
+ (*result)[(*count)] = StrDuplicate(next->FileName);
+ if (!(*result)[(*count)]) {
+ Print(L"Failed to allocate buffer");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ (*count)++;
+ } else {
+ continue;
+ }
+ break;
+ }
+
+ next:
+ if (StrCmp(next->FileName, L"..") == 0) {
+ /* place .. directory first */
+ CHAR16 *tmp = (*result)[(*count) - 1];
+
+ (*result)[(*count) - 1] = (*result)[0];
+ (*result)[0] = tmp;
+ }
+
+ ptr += OFFSET_OF(EFI_FILE_INFO, FileName) + (len + 1)*sizeof(CHAR16);
+ next = ptr;
+ }
+ if (*count == 0) {
+ /* no entries at all ... can happen because top level dir has no . or .. */
+ (*result)[(*count)++] = L"./";
+ }
+ (*result)[*count] = NULL;
+ status = EFI_SUCCESS;
+
+ out:
+ if (status != EFI_SUCCESS) {
+ if (*entries)
+ FreePool(*entries);
+ *entries = NULL;
+ if (*result)
+ FreePool(*result);
+ *result = NULL;
+ }
+ return status;
+}
+
+static void
+free_entries(CHAR16 **entries, int count)
+{
+ int i;
+
+ for (i = 0; i<count; i++)
+ FreePool(entries[i]);
+}
+
+void
+simple_file_selector(EFI_HANDLE *im, CHAR16 **title, CHAR16 *name,
+ CHAR16 *filter, CHAR16 **result)
+{
+ EFI_STATUS status;
+ CHAR16 **entries = NULL;
+ EFI_FILE_INFO *dmp;
+ int count, select, len;
+ CHAR16 *newname, *selected;
+
+ *result = NULL;
+ if (!name)
+ name = L"\\";
+ if (!filter)
+ filter = L"";
+ if (!*im) {
+ EFI_HANDLE h;
+ CHAR16 *volname;
+
+ simple_volume_selector(title, &volname, &h);
+ if (!volname)
+ return;
+ FreePool(volname);
+ *im = h;
+ }
+
+ newname = AllocatePool((StrLen(name) + 1)*sizeof(CHAR16));
+ if (!newname)
+ return;
+
+ StrCpy(newname, name);
+ name = newname;
+
+ redo:
+ status = simple_dir_filter(*im, name, filter, &entries, &count, &dmp);
+
+ if (status != EFI_SUCCESS)
+ goto out_free_name;
+
+ select = console_select(title, entries, 0);
+ if (select < 0)
+ /* ESC key */
+ goto out_free;
+ selected = entries[select];
+ /* note that memory used by selected is valid until dmp is freed */
+ len = StrLen(selected);
+ if (selected[len - 1] == '/') {
+ CHAR16 *newname;
+
+ /* stay where we are */
+ if (StrCmp(selected, L"./") == 0) {
+ free_entries(entries, count);
+ FreePool(entries);
+ entries = NULL;
+ FreePool(dmp);
+ goto redo;
+ } else if (StrCmp(selected, L"../") == 0) {
+ int i;
+
+ i = StrLen(name) - 1;
+
+
+ for (i = StrLen(name); i > 0; --i) {
+ if (name[i] == '\\')
+ break;
+ }
+ if (i == 0)
+ i = 1;
+
+ if (StrCmp(name, L"\\") != 0
+ && StrCmp(&name[i], L"..") != 0) {
+ name[i] = '\0';
+ free_entries(entries, count);
+ FreePool(entries);
+ entries = NULL;
+ FreePool(dmp);
+ goto redo;
+ }
+ }
+ newname = AllocatePool((StrLen(name) + len + 2)*sizeof(CHAR16));
+ if (!newname)
+ goto out_free;
+ StrCpy(newname, name);
+
+ if (name[StrLen(name) - 1] != '\\')
+ StrCat(newname, L"\\");
+ StrCat(newname, selected);
+ /* remove trailing / */
+ newname[StrLen(newname) - 1] = '\0';
+
+ free_entries(entries, count);
+ FreePool(entries);
+ entries = NULL;
+ FreePool(dmp);
+ FreePool(name);
+ name = newname;
+
+ goto redo;
+ }
+ *result = AllocatePool((StrLen(name) + len + 2)*sizeof(CHAR16));
+ if (*result) {
+ StrCpy(*result, name);
+ if (name[StrLen(name) - 1] != '\\')
+ StrCat(*result, L"\\");
+ StrCat(*result, selected);
+ }
+
+ out_free:
+ FreePool(dmp);
+ if (entries) {
+ free_entries(entries, count);
+ FreePool(entries);
+ }
+ out_free_name:
+ FreePool(name);
+}
diff --git a/lib/variables.c b/lib/variables.c
new file mode 100644
index 00000000..59d7d054
--- /dev/null
+++ b/lib/variables.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright 2012 <James.Bottomley@HansenPartnership.com>
+ *
+ * see COPYING file
+ *
+ * Portions of this file are a direct cut and paste from Tianocore
+ * (http://tianocore.sf.net)
+ *
+ * SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c
+ *
+ * Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>
+ * This program and the accompanying materials
+ * are licensed and made available under the terms and conditions of the BSD License
+ * which accompanies this distribution. The full text of the license may be found
+ * at
+ * http://opensource.org/licenses/bsd-license.php
+ *
+ * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ */
+#include <efi.h>
+#include <efilib.h>
+
+#include <efiauthenticated.h>
+
+#include <variables.h>
+#include <guid.h>
+#include <console.h>
+#include <errors.h>
+
+EFI_STATUS
+variable_create_esl(void *cert, int cert_len, EFI_GUID *type, EFI_GUID *owner,
+ void **out, int *outlen)
+{
+ *outlen = cert_len + sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID);
+
+ *out = AllocateZeroPool(*outlen);
+ if (!*out)
+ return EFI_OUT_OF_RESOURCES;
+
+ EFI_SIGNATURE_LIST *sl = *out;
+
+ sl->SignatureHeaderSize = 0;
+ sl->SignatureType = *type;
+ sl->SignatureSize = cert_len + sizeof(EFI_GUID);
+ sl->SignatureListSize = *outlen;
+
+ EFI_SIGNATURE_DATA *sd = *out + sizeof(EFI_SIGNATURE_LIST);
+
+ if (owner)
+ sd->SignatureOwner = *owner;
+
+ CopyMem(sd->SignatureData, cert, cert_len);
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+CreateTimeBasedPayload (
+ IN OUT UINTN *DataSize,
+ IN OUT UINT8 **Data
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *NewData;
+ UINT8 *Payload;
+ UINTN PayloadSize;
+ EFI_VARIABLE_AUTHENTICATION_2 *DescriptorData;
+ UINTN DescriptorSize;
+ EFI_TIME Time;
+ EFI_GUID efi_cert_type = EFI_CERT_TYPE_PKCS7_GUID;
+
+ if (Data == NULL || DataSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // In Setup mode or Custom mode, the variable does not need to be signed but the
+ // parameters to the SetVariable() call still need to be prepared as authenticated
+ // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate
+ // data in it.
+ //
+ Payload = *Data;
+ PayloadSize = *DataSize;
+
+ DescriptorSize = OFFSET_OF(EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData);
+ NewData = (UINT8*) AllocateZeroPool (DescriptorSize + PayloadSize);
+ if (NewData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if ((Payload != NULL) && (PayloadSize != 0)) {
+ CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
+ }
+
+ DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData);
+
+ ZeroMem (&Time, sizeof (EFI_TIME));
+ Status = uefi_call_wrapper(RT->GetTime,2, &Time, NULL);
+ if (EFI_ERROR (Status)) {
+ FreePool(NewData);
+ return Status;
+ }
+ Time.Pad1 = 0;
+ Time.Nanosecond = 0;
+ Time.TimeZone = 0;
+ Time.Daylight = 0;
+ Time.Pad2 = 0;
+ CopyMem (&DescriptorData->TimeStamp, &Time, sizeof (EFI_TIME));
+
+ DescriptorData->AuthInfo.Hdr.dwLength = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
+ DescriptorData->AuthInfo.Hdr.wRevision = 0x0200;
+ DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
+ DescriptorData->AuthInfo.CertType = efi_cert_type;
+
+ /* we're expecting an EFI signature list, so don't free the input since
+ * it might not be in a pool */
+#if 0
+ if (Payload != NULL) {
+ FreePool(Payload);
+ }
+#endif
+
+ *DataSize = DescriptorSize + PayloadSize;
+ *Data = NewData;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SetSecureVariable(CHAR16 *var, UINT8 *Data, UINTN len, EFI_GUID owner,
+ UINT32 options, int createtimebased)
+{
+ EFI_SIGNATURE_LIST *Cert;
+ UINTN DataSize;
+ EFI_STATUS efi_status;
+
+ /* Microsoft request: Bugs in some UEFI platforms mean that PK or any
+ * other secure variable can be updated or deleted programmatically,
+ * so prevent */
+ if (!variable_is_setupmode(1))
+ return EFI_SECURITY_VIOLATION;
+
+ if (createtimebased) {
+ int ds;
+ efi_status = variable_create_esl(Data, len, &X509_GUID, NULL,
+ (void **)&Cert, &ds);
+ if (efi_status != EFI_SUCCESS) {
+ Print(L"Failed to create %s certificate %d\n", var, efi_status);
+ return efi_status;
+ }
+
+ DataSize = ds;
+ } else {
+ /* we expect an efi signature list rather than creating it */
+ Cert = (EFI_SIGNATURE_LIST *)Data;
+ DataSize = len;
+ }
+ efi_status = CreateTimeBasedPayload(&DataSize, (UINT8 **)&Cert);
+ if (efi_status != EFI_SUCCESS) {
+ Print(L"Failed to create time based payload %d\n", efi_status);
+ return efi_status;
+ }
+
+ efi_status = uefi_call_wrapper(RT->SetVariable, 5, var, &owner,
+ EFI_VARIABLE_NON_VOLATILE
+ | EFI_VARIABLE_RUNTIME_ACCESS
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
+ | options,
+ DataSize, Cert);
+
+ return efi_status;
+}
+
+UINT64
+GetOSIndications(void)
+{
+ UINT64 indications;
+ UINTN DataSize = sizeof(indications);
+ EFI_STATUS efi_status;
+
+ efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"OsIndicationsSupported", &GV_GUID, NULL, &DataSize, &indications);
+ if (efi_status != EFI_SUCCESS)
+ return 0;
+
+ return indications;
+}
+
+EFI_STATUS
+SETOSIndicationsAndReboot(UINT64 indications)
+{
+ UINTN DataSize = sizeof(indications);
+ EFI_STATUS efi_status;
+
+ efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"OsIndications",
+ &GV_GUID,
+ EFI_VARIABLE_NON_VOLATILE
+ | EFI_VARIABLE_RUNTIME_ACCESS
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ DataSize, &indications);
+
+ if (efi_status != EFI_SUCCESS)
+ return efi_status;
+
+ uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm, EFI_SUCCESS, 0, NULL);
+ /* does not return */
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+get_variable_attr(CHAR16 *var, UINT8 **data, UINTN *len, EFI_GUID owner,
+ UINT32 *attributes)
+{
+ EFI_STATUS efi_status;
+
+ *len = 0;
+
+ efi_status = uefi_call_wrapper(RT->GetVariable, 5, var, &owner,
+ NULL, len, NULL);
+ if (efi_status != EFI_BUFFER_TOO_SMALL)
+ return efi_status;
+
+ *data = AllocateZeroPool(*len);
+ if (!*data)
+ return EFI_OUT_OF_RESOURCES;
+
+ efi_status = uefi_call_wrapper(RT->GetVariable, 5, var, &owner,
+ attributes, len, *data);
+
+ if (efi_status != EFI_SUCCESS) {
+ FreePool(*data);
+ *data = NULL;
+ }
+ return efi_status;
+}
+
+EFI_STATUS
+get_variable(CHAR16 *var, UINT8 **data, UINTN *len, EFI_GUID owner)
+{
+ return get_variable_attr(var, data, len, owner, NULL);
+}
+
+EFI_STATUS
+find_in_esl(UINT8 *Data, UINTN DataSize, UINT8 *key, UINTN keylen)
+{
+ EFI_SIGNATURE_LIST *CertList;
+
+ certlist_for_each_certentry(CertList, Data, DataSize, DataSize) {
+ if (CertList->SignatureSize != keylen + sizeof(EFI_GUID))
+ continue;
+ EFI_SIGNATURE_DATA *Cert;
+
+ certentry_for_each_cert(Cert, CertList)
+ if (CompareMem (Cert->SignatureData, key, keylen) == 0)
+ return EFI_SUCCESS;
+ }
+ return EFI_NOT_FOUND;
+}
+
+EFI_STATUS
+find_in_variable_esl(CHAR16* var, EFI_GUID owner, UINT8 *key, UINTN keylen)
+{
+ UINTN DataSize;
+ UINT8 *Data;
+ EFI_STATUS status;
+
+ status = get_variable(var, &Data, &DataSize, owner);
+ if (status != EFI_SUCCESS)
+ return status;
+
+ status = find_in_esl(Data, DataSize, key, keylen);
+
+ FreePool(Data);
+
+ return status;
+}
+
+int
+variable_is_setupmode(int default_return)
+{
+ /* set to 1 because we return true if SetupMode doesn't exist */
+ UINT8 SetupMode = default_return;
+ UINTN DataSize = sizeof(SetupMode);
+ EFI_STATUS status;
+
+ status = uefi_call_wrapper(RT->GetVariable, 5, L"SetupMode", &GV_GUID, NULL,
+ &DataSize, &SetupMode);
+ if (EFI_ERROR(status))
+ return default_return;
+
+ return SetupMode;
+}
+
+int
+variable_is_secureboot(void)
+{
+ /* return false if variable doesn't exist */
+ UINT8 SecureBoot = 0;
+ UINTN DataSize;
+ EFI_STATUS status;
+
+ DataSize = sizeof(SecureBoot);
+ status = uefi_call_wrapper(RT->GetVariable, 5, L"SecureBoot", &GV_GUID, NULL,
+ &DataSize, &SecureBoot);
+ if (EFI_ERROR(status))
+ return 0;
+
+ return SecureBoot;
+}
+
+EFI_STATUS
+variable_enroll_hash(CHAR16 *var, EFI_GUID owner,
+ UINT8 hash[SHA256_DIGEST_SIZE])
+{
+ EFI_STATUS status;
+
+ if (find_in_variable_esl(var, owner, hash, SHA256_DIGEST_SIZE)
+ == EFI_SUCCESS)
+ /* hash already present */
+ return EFI_ALREADY_STARTED;
+
+ UINT8 sig[sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + SHA256_DIGEST_SIZE];
+ EFI_SIGNATURE_LIST *l = (void *)sig;
+ EFI_SIGNATURE_DATA *d = (void *)sig + sizeof(EFI_SIGNATURE_LIST);
+ SetMem(sig, 0, sizeof(sig));
+ l->SignatureType = EFI_CERT_SHA256_GUID;
+ l->SignatureListSize = sizeof(sig);
+ l->SignatureSize = 16 +32; /* UEFI defined */
+ CopyMem(&d->SignatureData, hash, SHA256_DIGEST_SIZE);
+ d->SignatureOwner = MOK_OWNER;
+
+ if (CompareGuid(&owner, &SIG_DB) == 0)
+ status = SetSecureVariable(var, sig, sizeof(sig), owner,
+ EFI_VARIABLE_APPEND_WRITE, 0);
+ else
+ status = uefi_call_wrapper(RT->SetVariable, 5, var, &owner,
+ EFI_VARIABLE_NON_VOLATILE
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ | EFI_VARIABLE_APPEND_WRITE,
+ sizeof(sig), sig);
+ return status;
+}