]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/efi/shim.c
strv: replace always-true condition with assertion
[thirdparty/systemd.git] / src / boot / efi / shim.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /*
3 * Port to systemd-boot
4 * Copyright © 2017 Max Resch <resch.max@gmail.com>
5 *
6 * Security Policy Handling
7 * Copyright © 2012 <James.Bottomley@HansenPartnership.com>
8 * https://github.com/mjg59/efitools
9 */
10
11 #include "device-path-util.h"
12 #include "secure-boot.h"
13 #include "shim.h"
14 #include "util.h"
15
16 #if defined(__x86_64__) || defined(__i386__)
17 #define __sysv_abi__ __attribute__((sysv_abi))
18 #else
19 #define __sysv_abi__
20 #endif
21
22 struct ShimLock {
23 EFI_STATUS __sysv_abi__ (*shim_verify) (const void *buffer, uint32_t size);
24
25 /* context is actually a struct for the PE header, but it isn't needed so void is sufficient just do define the interface
26 * see shim.c/shim.h and PeHeader.h in the github shim repo */
27 EFI_STATUS __sysv_abi__ (*generate_hash) (void *data, uint32_t datasize, void *context, uint8_t *sha256hash, uint8_t *sha1hash);
28
29 EFI_STATUS __sysv_abi__ (*read_header) (void *data, uint32_t datasize, void *context);
30 };
31
32 #define SHIM_LOCK_GUID \
33 { 0x605dab50, 0xe046, 0x4300, { 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } }
34
35 bool shim_loaded(void) {
36 struct ShimLock *shim_lock;
37
38 return BS->LocateProtocol(MAKE_GUID_PTR(SHIM_LOCK), NULL, (void **) &shim_lock) == EFI_SUCCESS;
39 }
40
41 static bool shim_validate(
42 const void *ctx, const EFI_DEVICE_PATH *device_path, const void *file_buffer, size_t file_size) {
43
44 EFI_STATUS err;
45 _cleanup_free_ char *file_buffer_owned = NULL;
46
47 if (!file_buffer) {
48 if (!device_path)
49 return false;
50
51 EFI_HANDLE device_handle;
52 EFI_DEVICE_PATH *file_dp = (EFI_DEVICE_PATH *) device_path;
53 err = BS->LocateDevicePath(
54 MAKE_GUID_PTR(EFI_SIMPLE_FILE_SYSTEM_PROTOCOL), &file_dp, &device_handle);
55 if (err != EFI_SUCCESS)
56 return false;
57
58 _cleanup_(file_closep) EFI_FILE *root = NULL;
59 err = open_volume(device_handle, &root);
60 if (err != EFI_SUCCESS)
61 return false;
62
63 _cleanup_free_ char16_t *dp_str = NULL;
64 err = device_path_to_str(file_dp, &dp_str);
65 if (err != EFI_SUCCESS)
66 return false;
67
68 err = file_read(root, dp_str, 0, 0, &file_buffer_owned, &file_size);
69 if (err != EFI_SUCCESS)
70 return false;
71
72 file_buffer = file_buffer_owned;
73 }
74
75 struct ShimLock *shim_lock;
76 err = BS->LocateProtocol(MAKE_GUID_PTR(SHIM_LOCK), NULL, (void **) &shim_lock);
77 if (err != EFI_SUCCESS)
78 return false;
79
80 return shim_lock->shim_verify(file_buffer, file_size) == EFI_SUCCESS;
81 }
82
83 EFI_STATUS shim_load_image(EFI_HANDLE parent, const EFI_DEVICE_PATH *device_path, EFI_HANDLE *ret_image) {
84 assert(device_path);
85 assert(ret_image);
86
87 bool have_shim = shim_loaded();
88
89 if (have_shim)
90 install_security_override(shim_validate, NULL);
91
92 EFI_STATUS ret = BS->LoadImage(
93 /*BootPolicy=*/false, parent, (EFI_DEVICE_PATH *) device_path, NULL, 0, ret_image);
94
95 if (have_shim)
96 uninstall_security_override();
97
98 return ret;
99 }
100
101 void shim_retain_protocol(void) {
102 uint8_t value = 1;
103
104 /* Ask Shim to avoid uninstalling its security protocol, so that we can use it from sd-stub to
105 * validate PE addons. By default, Shim uninstalls its protocol when calling StartImage().
106 * Requires Shim 15.8. */
107 (void) efivar_set_raw(MAKE_GUID_PTR(SHIM_LOCK), u"ShimRetainProtocol", &value, sizeof(value), 0);
108 }