]> code.delx.au - refind/blobdiff - mok/security_policy.c
Files for new MOK/shim code based on Bottomley's PreLoader.
[refind] / mok / security_policy.c
diff --git a/mok/security_policy.c b/mok/security_policy.c
new file mode 100644 (file)
index 0000000..086ef6a
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * Copyright 2012 <James.Bottomley@HansenPartnership.com>
+ *
+ * see COPYING file
+ *
+ * Install and remove a platform security2 override policy
+ */
+
+// #include <efi.h>
+// #include <efilib.h>
+#include <global.h>
+
+#include "guid.h"
+//#include "sha256.h"
+//#include "variables.h"
+#include "simple_file.h"
+//#include "errors.h"
+#include "../include/refit_call_wrapper.h"
+#include "mok.h"
+
+#include <security_policy.h>
+
+/*
+ * See the UEFI Platform Initialization manual (Vol2: DXE) for this
+ */
+struct _EFI_SECURITY2_PROTOCOL;
+struct _EFI_SECURITY_PROTOCOL;
+struct _EFI_DEVICE_PATH_PROTOCOL;
+typedef struct _EFI_SECURITY2_PROTOCOL EFI_SECURITY2_PROTOCOL;
+typedef struct _EFI_SECURITY_PROTOCOL EFI_SECURITY_PROTOCOL;
+#ifdef __MAKEWITH_GNUEFI
+typedef struct _EFI_DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH_PROTOCOL;
+#endif
+
+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 EFI_SECURITY_FILE_AUTHENTICATION_STATE esfas = NULL;
+static EFI_SECURITY2_FILE_AUTHENTICATION es2fa = NULL;
+
+#ifdef __MAKEWITH_GNUEFI
+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));
+#endif
+
+#ifdef __MAKEWITH_GNUEFI
+static __attribute__((used)) EFI_STATUS
+#else
+static __attribute__((ms_abi)) EFI_STATUS
+#endif
+security2_policy_authentication (
+   const EFI_SECURITY2_PROTOCOL *This,
+   const EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+   VOID *FileBuffer,
+   UINTN FileSize,
+   BOOLEAN  BootPolicy
+             )
+{
+   EFI_STATUS status;
+
+   /* 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 (ShimValidate(FileBuffer, FileSize)) {
+      status = EFI_SUCCESS;
+   } else {
+      status = EFI_ACCESS_DENIED;
+   }
+
+//   status = security_policy_check_mok(FileBuffer, FileSize);
+
+   return status;
+}
+
+#ifdef __MAKEWITH_GNUEFI
+static __attribute__((used)) EFI_STATUS
+#else
+static __attribute__((ms_abi)) EFI_STATUS
+#endif
+security_policy_authentication (
+   const EFI_SECURITY_PROTOCOL *This,
+   UINT32 AuthenticationStatus,
+   const EFI_DEVICE_PATH_PROTOCOL *DevicePathConst
+   )
+{
+   EFI_STATUS 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 = refit_call3_wrapper(esfas, 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;
+
+   status = refit_call3_wrapper(BS->LocateDevicePath, &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 (ShimValidate(FileBuffer, FileSize)) {
+      status = EFI_SUCCESS;
+   } else {
+      status = EFI_ACCESS_DENIED;
+   }
+   FreePool(FileBuffer);
+
+ out:
+   FreePool(OrigDevPath);
+   return status;
+}
+
+#ifdef __MAKEWITH_GNUEFI
+/* 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"
+);
+#endif
+
+EFI_STATUS
+security_policy_install(void)
+{
+   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, (VOID**) &security2_protocol);
+
+   status = uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY_PROTOCOL_GUID, NULL, (VOID**) &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;
+#ifdef __MAKEWITH_GNUEFI
+      security2_protocol->FileAuthentication = thunk_security2_policy_authentication;
+#else
+      security2_protocol->FileAuthentication = security2_policy_authentication;
+#endif
+   }
+
+   esfas = security_protocol->FileAuthenticationState;
+#ifdef __MAKEWITH_GNUEFI
+   security_protocol->FileAuthenticationState = thunk_security_policy_authentication;
+#else
+   security_protocol->FileAuthenticationState = security_policy_authentication;
+#endif
+   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,
+                  (VOID**) &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,
+                  (VOID**) &security2_protocol);
+
+      if (status != EFI_SUCCESS)
+         return status;
+
+      security2_protocol->FileAuthentication = es2fa;
+      es2fa = NULL;
+   }
+
+   return EFI_SUCCESS;
+}
+
+void
+security_protocol_set_hashes(unsigned char *esl, int len)
+{
+   security_policy_esl = esl;
+   security_policy_esl_len = len;
+}