aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <JBottomley@Parallels.com>2012-12-07 13:17:40 +0000
committerJames Bottomley <JBottomley@Parallels.com>2012-12-07 13:17:40 +0000
commit3747f0c2a7f62d7a7d2c1e002df68d0aef289fb8 (patch)
treedb716dd119e3db3821b56d80d12ddd7b7109178e
parentb5bf63ed5595b137b8deeadb332d9d9915a89f3a (diff)
downloadefitools-3747f0c2a7f62d7a7d2c1e002df68d0aef289fb8.tar.gz
security_policy: Make it functional on PI 1.2 systems
Apparently security2_policy was a PI 1.2.1 addition, so most current UEFI systems only support the prior security_policy. Fix our security policy to check for security2 first and fall back if it's not found Also fix up the thunking between EFI and ELF so it actually works Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r--Make.rules6
-rw-r--r--include/guid.h1
-rw-r--r--include/simple_file.h2
-rw-r--r--lib/guid.c1
-rw-r--r--lib/security_policy.c254
5 files changed, 223 insertions, 41 deletions
diff --git a/Make.rules b/Make.rules
index 478ff20..000faa0 100644
--- a/Make.rules
+++ b/Make.rules
@@ -50,7 +50,11 @@ endif
$(CC) $(INCDIR) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
%.efi.o: %.c
- $(CC) $(INCDIR) $(CFLAGS) $(CPPFLAGS) -DBUILD_EFI -c $< -o $@
+ $(CC) $(INCDIR) $(CFLAGS) $(CPPFLAGS) -fno-toplevel-reorder -DBUILD_EFI -c $< -o $@
+
+%.efi.s: %.c
+ $(CC) -S $(INCDIR) $(CFLAGS) $(CPPFLAGS) -fno-toplevel-reorder -DBUILD_EFI -c $< -o $@
+
%.cer: %.crt
openssl x509 -in $< -out $@ -outform DER
diff --git a/include/guid.h b/include/guid.h
index 166667c..10f865a 100644
--- a/include/guid.h
+++ b/include/guid.h
@@ -14,4 +14,5 @@ extern EFI_GUID IMAGE_PROTOCOL;
extern EFI_GUID SIMPLE_FS_PROTOCOL;
extern EFI_GUID EFI_CERT_SHA256_GUID;
extern EFI_GUID MOK_OWNER;
+extern EFI_GUID SECURITY_PROTOCOL_GUID;
extern EFI_GUID SECURITY2_PROTOCOL_GUID;
diff --git a/include/simple_file.h b/include/simple_file.h
index 57bebb0..fe4fd97 100644
--- a/include/simple_file.h
+++ b/include/simple_file.h
@@ -1,6 +1,8 @@
EFI_STATUS
simple_file_open (EFI_HANDLE image, CHAR16 *name, EFI_FILE **file, UINT64 mode);
EFI_STATUS
+simple_file_open_by_handle(EFI_HANDLE device, CHAR16 *name, EFI_FILE **file, UINT64 mode);
+EFI_STATUS
simple_file_read_all(EFI_FILE *file, UINTN *size, void **buffer);
EFI_STATUS
simple_file_write_all(EFI_FILE *file, UINTN size, void *buffer);
diff --git a/lib/guid.c b/lib/guid.c
index a7dabee..25db91a 100644
--- a/lib/guid.c
+++ b/lib/guid.c
@@ -43,4 +43,5 @@ EFI_GUID IMAGE_PROTOCOL = LOADED_IMAGE_PROTOCOL;
EFI_GUID SIMPLE_FS_PROTOCOL = SIMPLE_FILE_SYSTEM_PROTOCOL;
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
index 64110fc..74f49aa 100644
--- a/lib/security_policy.c
+++ b/lib/security_policy.c
@@ -12,6 +12,7 @@
#include <guid.h>
#include <sha256.h>
#include <variables.h>
+#include <simple_file.h>
#include <errors.h>
#include <security_policy.h>
@@ -20,10 +21,17 @@
* 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;
typedef struct _EFI_DEVICE_PATH_PROTOCOL 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,
@@ -36,6 +44,11 @@ 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;
@@ -92,8 +105,99 @@ security_policy_check_mok(void *data, UINTN len)
return EFI_SECURITY_VIOLATION;
}
+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;
+
+ status = security_policy_check_mok(FileBuffer, FileSize);
+
+ if (status == EFI_SUCCESS)
+ return status;
+
+ /* chain previous policy (UEFI security validation) */
+ status = uefi_call_wrapper(es2fa, 5, This, DevicePath, FileBuffer,
+ FileSize, BootPolicy);
+
+ return status;
+}
+
+static __attribute__((used)) 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;
+
+ status = uefi_call_wrapper(BS->LocateDevicePath, 3,
+ &SIMPLE_FS_PROTOCOL, &DevPath, &h);
+ if (status != EFI_SUCCESS)
+ goto chain;
+
+ DevPathStr = DevicePathToStr(DevPath);
+
+ status = simple_file_open_by_handle(h, DevPathStr, &f,
+ EFI_FILE_MODE_READ);
+ FreePool(DevPathStr);
+ if (status != EFI_SUCCESS)
+ goto chain;
+
+ status = simple_file_read_all(f, &FileSize, &FileBuffer);
+ simple_file_close(f);
+ if (status != EFI_SUCCESS)
+ goto chain;
+
+ status = security_policy_check_mok(FileBuffer, FileSize);
+ FreePool(FileBuffer);
+
+ if (status == EFI_SUCCESS)
+ goto out;
+
+ chain:
+ status = uefi_call_wrapper(esfas, 3, This, AuthenticationStatus,
+ DevicePathConst);
+
+ out:
+ FreePool(OrigDevPath);
+ return status;
+}
+
+
/* Nasty: ELF and EFI have different calling conventions. Here is the map for
* calling ELF -> EFI
*
@@ -118,51 +222,105 @@ static EFI_SECURITY2_FILE_AUTHENTICATION es2fa = NULL;
* 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.
*/
-static UINT64 security_policy_authentication (
- UINT64 ARG1, UINT64 ARG2, UINT64 ARG3, UINT64 ARG4, UINT64 ARG5,
- UINT64 ARG6, UINT64 ARG7, UINT64 ARG8, UINT64 ARG9, UINT64 ARG10,
- UINT32 ARG11)
-{
- EFI_STATUS status;
- const EFI_SECURITY2_PROTOCOL *This = (void *)ARG4;
- const EFI_DEVICE_PATH_PROTOCOL *DevicePath = (void *)ARG3;
- VOID *FileBuffer = (void *)ARG5;
- UINTN FileSize = ARG6;
- BOOLEAN BootPolicy = ARG11;
-
- status = security_policy_check_mok(FileBuffer, FileSize);
-
- if (status == EFI_SUCCESS)
- return status;
-
- /* chain previous policy (UEFI security validation) */
- status = uefi_call_wrapper(es2fa, 5, This, DevicePath, FileBuffer,
- FileSize, BootPolicy);
-
- return status;
-}
+asm (
+".type security2_policy_authentication,@function\n"
+"thunk_security2_policy_authentication:\n\t"
+ "mov 32(%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(void)
{
- EFI_SECURITY2_PROTOCOL *security2_protocol;
+ EFI_SECURITY_PROTOCOL *security_protocol;
+ EFI_SECURITY2_PROTOCOL *security2_protocol = NULL;
EFI_STATUS status;
- if (es2fa)
+ if (es2fa || esfas)
/* Already Installed */
return EFI_ALREADY_STARTED;
status = uefi_call_wrapper(BS->LocateProtocol, 3,
&SECURITY2_PROTOCOL_GUID, NULL,
&security2_protocol);
+
+ if (status == EFI_NOT_FOUND)
+ status = uefi_call_wrapper(BS->LocateProtocol, 3,
+ &SECURITY_PROTOCOL_GUID, NULL,
+ &security_protocol);
if (status != EFI_SUCCESS)
return status;
- es2fa = security2_protocol->FileAuthentication;
- security2_protocol->FileAuthentication =
- (EFI_SECURITY2_FILE_AUTHENTICATION)security_policy_authentication;
+ if (security2_protocol) {
+ es2fa = security2_protocol->FileAuthentication;
+ security2_protocol->FileAuthentication =
+ thunk_security2_policy_authentication;
+ } else {
+ esfas = security_protocol->FileAuthenticationState;
+ security_protocol->FileAuthenticationState =
+ thunk_security_policy_authentication;
+ }
return EFI_SUCCESS;
}
@@ -170,24 +328,40 @@ security_policy_install(void)
EFI_STATUS
security_policy_uninstall(void)
{
- EFI_SECURITY2_PROTOCOL *security2_protocol;
EFI_STATUS status;
- if (!es2fa)
- /* Not Installed */
- return EFI_NOT_STARTED;
+ if (esfas) {
+ EFI_SECURITY_PROTOCOL *security_protocol;
- status = 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)
- return status;
+ if (status != EFI_SUCCESS)
+ return status;
- security2_protocol->FileAuthentication = es2fa;
- es2fa = NULL;
+ security_protocol->FileAuthenticationState = esfas;
+ esfas = NULL;
- return EFI_SUCCESS;
+ return EFI_SUCCESS;
+ } else 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;
+
+ return EFI_SUCCESS;
+ } else {
+ /* nothing installed */
+ return EFI_NOT_STARTED;
+ }
}
void