]> code.delx.au - refind/blobdiff - mok/security_policy.c
Sort Fedora's rescue kernel (vmlinuz-0-rescue*) to the end of the list
[refind] / mok / security_policy.c
index 086ef6acfa232533a4914ccfdd7542d2f09c5107..33d3be7cf647ea941dde2aa3f7c35c7be782b67c 100644 (file)
@@ -6,15 +6,11 @@
  * 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 "../refind/lib.h"
 #include "simple_file.h"
-//#include "errors.h"
 #include "../include/refit_call_wrapper.h"
 #include "mok.h"
 
@@ -28,16 +24,19 @@ 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;
+
+#if defined(EFIX64)
+#define MSABI __attribute__((ms_abi))
+#else
+#define MSABI
 #endif
 
-typedef EFI_STATUS (EFIAPI *EFI_SECURITY_FILE_AUTHENTICATION_STATE) (
+typedef EFI_STATUS (MSABI *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) (
+typedef EFI_STATUS (MSABI *EFI_SECURITY2_FILE_AUTHENTICATION) (
          const EFI_SECURITY2_PROTOCOL *This,
          const EFI_DEVICE_PATH_PROTOCOL *DevicePath,
          VOID *FileBuffer,
@@ -54,35 +53,16 @@ struct _EFI_SECURITY_PROTOCOL {
 };
 
 
-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
+// Perform shim/MOK and Secure Boot authentication on a binary that's already been
+// loaded into memory. This function does the platform SB authentication first
+// but preserves its return value in case of its failure, so that it can be
+// returned in case of a shim/MOK authentication failure. This is done because
+// the SB failure code seems to vary from one implementation to another, and I
+// don't want to interfere with that at this time.
+static MSABI EFI_STATUS
 security2_policy_authentication (
    const EFI_SECURITY2_PROTOCOL *This,
    const EFI_DEVICE_PATH_PROTOCOL *DevicePath,
@@ -91,176 +71,78 @@ security2_policy_authentication (
    BOOLEAN  BootPolicy
              )
 {
-   EFI_STATUS status;
+   EFI_STATUS Status;
 
    /* Chain original security policy */
-   status = uefi_call_wrapper(es2fa, 5, This, DevicePath, FileBuffer, FileSize, BootPolicy);
+   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 (Status == EFI_SUCCESS)
+      return Status;
 
    if (ShimValidate(FileBuffer, FileSize)) {
-      status = EFI_SUCCESS;
+      return EFI_SUCCESS;
    } else {
-      status = EFI_ACCESS_DENIED;
+      return Status;
    }
-
-//   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
+} // EFI_STATUS security2_policy_authentication()
+
+// Perform both shim/MOK and platform Secure Boot authentication. This function loads
+// the file and performs shim/MOK authentication first simply to avoid double loads
+// of Linux kernels, which are much more likely to be shim/MOK-signed than platform-signed,
+// since kernels are big and can take several seconds to load on some computers and
+// filesystems. This also has the effect of returning whatever the platform code is for
+// authentication failure, be it EFI_ACCESS_DENIED, EFI_SECURITY_VIOLATION, or something
+// else. (This seems to vary between implementations.)
+static MSABI EFI_STATUS
 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);
+   EFI_STATUS        Status;
+   EFI_DEVICE_PATH   *DevPath, *OrigDevPath;
+   EFI_HANDLE        h;
+   EFI_FILE          *f;
+   VOID              *FileBuffer;
+   UINTN             FileSize;
+   CHAR16            *DevPathStr;
+
+   if (DevicePathConst == NULL) {
+      return EFI_INVALID_PARAMETER;
+   } else {
+      DevPath = OrigDevPath = DuplicateDevicePath((EFI_DEVICE_PATH *)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)
+   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)
+   Status = simple_file_open_by_handle(h, DevPathStr, &f, EFI_FILE_MODE_READ);
+   MyFreePool(DevPathStr);
+   if (Status != EFI_SUCCESS)
       goto out;
 
-   status = simple_file_read_all(f, &FileSize, &FileBuffer);
+   Status = simple_file_read_all(f, &FileSize, &FileBuffer);
    simple_file_close(f);
-   if (status != EFI_SUCCESS)
+   if (Status != EFI_SUCCESS)
       goto out;
 
    if (ShimValidate(FileBuffer, FileSize)) {
-      status = EFI_SUCCESS;
+      Status = EFI_SUCCESS;
    } else {
-      status = EFI_ACCESS_DENIED;
+      // Try using the platform's native policy....
+      Status = uefi_call_wrapper(esfas, 3, This, AuthenticationStatus, DevicePathConst);
    }
    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
+   MyFreePool(OrigDevPath);
+   return Status;
+} // EFI_STATUS security_policy_authentication()
 
 EFI_STATUS
 security_policy_install(void)
@@ -286,19 +168,11 @@ security_policy_install(void)
 
    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;
 }
 
@@ -310,9 +184,7 @@ security_policy_uninstall(void)
    if (esfas) {
       EFI_SECURITY_PROTOCOL *security_protocol;
 
-      status = uefi_call_wrapper(BS->LocateProtocol, 3,
-                  &SECURITY_PROTOCOL_GUID, NULL,
-                  (VOID**) &security_protocol);
+      status = uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY_PROTOCOL_GUID, NULL, (VOID**) &security_protocol);
 
       if (status != EFI_SUCCESS)
          return status;
@@ -327,9 +199,7 @@ security_policy_uninstall(void)
    if (es2fa) {
       EFI_SECURITY2_PROTOCOL *security2_protocol;
 
-      status = uefi_call_wrapper(BS->LocateProtocol, 3,
-                  &SECURITY2_PROTOCOL_GUID, NULL,
-                  (VOID**) &security2_protocol);
+      status = uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY2_PROTOCOL_GUID, NULL, (VOID**) &security2_protocol);
 
       if (status != EFI_SUCCESS)
          return status;
@@ -340,10 +210,3 @@ security_policy_uninstall(void)
 
    return EFI_SUCCESS;
 }
-
-void
-security_protocol_set_hashes(unsigned char *esl, int len)
-{
-   security_policy_esl = esl;
-   security_policy_esl_len = len;
-}