* 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"
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,
};
-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,
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)
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;
}
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;
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;
return EFI_SUCCESS;
}
-
-void
-security_protocol_set_hashes(unsigned char *esl, int len)
-{
- security_policy_esl = esl;
- security_policy_esl_len = len;
-}