1 #include "efidef.h" 2 #include <efi.h> 3 #include <efilib.h> 4 #include <lib.h> 5 #include <dragonstub/dragonstub.h> 6 7 enum efistub_event { 8 EFISTUB_EVT_INITRD, 9 EFISTUB_EVT_LOAD_OPTIONS, 10 EFISTUB_EVT_COUNT, 11 }; 12 13 #define STR_WITH_SIZE(s) sizeof(s), s 14 15 static const struct { 16 u32 pcr_index; 17 u32 event_id; 18 u32 event_data_len; 19 u8 event_data[52]; 20 } events[] = { 21 [EFISTUB_EVT_INITRD] = { 9, INITRD_EVENT_TAG_ID, 22 STR_WITH_SIZE("Linux initrd") }, 23 [EFISTUB_EVT_LOAD_OPTIONS] = { 9, LOAD_OPTIONS_EVENT_TAG_ID, 24 STR_WITH_SIZE( 25 "LOADED_IMAGE::LoadOptions") }, 26 }; 27 28 static efi_status_t efi_measure_tagged_event(unsigned long load_addr, 29 unsigned long load_size, 30 enum efistub_event event) 31 { 32 efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID; 33 efi_tcg2_protocol_t *tcg2 = NULL; 34 efi_status_t status; 35 36 efi_bs_call(LocateProtocol, &tcg2_guid, NULL, (void **)&tcg2); 37 if (tcg2) { 38 struct efi_measured_event { 39 efi_tcg2_event_t event_data; 40 efi_tcg2_tagged_event_t tagged_event; 41 u8 tagged_event_data[]; 42 } * evt; 43 int size = sizeof(*evt) + events[event].event_data_len; 44 45 status = efi_bs_call(AllocatePool, EfiLoaderData, size, 46 (void **)&evt); 47 if (status != EFI_SUCCESS) 48 goto fail; 49 50 evt->event_data = (struct efi_tcg2_event){ 51 .event_size = size, 52 .event_header.header_size = 53 sizeof(evt->event_data.event_header), 54 .event_header.header_version = 55 EFI_TCG2_EVENT_HEADER_VERSION, 56 .event_header.pcr_index = events[event].pcr_index, 57 .event_header.event_type = EV_EVENT_TAG, 58 }; 59 60 evt->tagged_event = (struct efi_tcg2_tagged_event){ 61 .tagged_event_id = events[event].event_id, 62 .tagged_event_data_size = events[event].event_data_len, 63 }; 64 65 memcpy(evt->tagged_event_data, events[event].event_data, 66 events[event].event_data_len); 67 68 status = efi_call_proto(tcg2, hash_log_extend_event, 0, 69 load_addr, load_size, &evt->event_data); 70 efi_bs_call(FreePool, evt); 71 72 if (status != EFI_SUCCESS) 73 goto fail; 74 return EFI_SUCCESS; 75 } 76 77 return EFI_UNSUPPORTED; 78 fail: 79 efi_warn("Failed to measure data for event %d: 0x%lx\n", event, status); 80 return status; 81 } 82 83 /* 84 * At least some versions of Dell firmware pass the entire contents of the 85 * Boot#### variable, i.e. the EFI_LOAD_OPTION descriptor, rather than just the 86 * OptionalData field. 87 * 88 * Detect this case and extract OptionalData. 89 */ 90 void efi_apply_loadoptions_quirk(const void **load_options, 91 u32 *load_options_size) 92 { 93 #ifndef CONFIG_X86 94 return; 95 #else 96 const efi_load_option_t *load_option = *load_options; 97 efi_load_option_unpacked_t load_option_unpacked; 98 if (!load_option) 99 return; 100 if (*load_options_size < sizeof(*load_option)) 101 return; 102 if ((load_option->attributes & ~EFI_LOAD_OPTION_BOOT_MASK) != 0) 103 return; 104 105 if (!efi_load_option_unpack(&load_option_unpacked, load_option, 106 *load_options_size)) 107 return; 108 109 efi_warn_once(FW_BUG "LoadOptions is an EFI_LOAD_OPTION descriptor\n"); 110 efi_warn_once(FW_BUG "Using OptionalData as a workaround\n"); 111 112 *load_options = load_option_unpacked.optional_data; 113 *load_options_size = load_option_unpacked.optional_data_size; 114 #endif 115 } 116 117 /* 118 * Convert the unicode UEFI command line to ASCII to pass to kernel. 119 * Size of memory allocated return in *cmd_line_len. 120 * Returns NULL on error. 121 */ 122 char *efi_convert_cmdline(EFI_LOADED_IMAGE *image, int *cmd_line_len) 123 { 124 const efi_char16_t *options = efi_table_attr(image, LoadOptions); 125 u32 options_size = efi_table_attr(image, LoadOptionsSize); 126 int options_bytes = 0, safe_options_bytes = 0; /* UTF-8 bytes */ 127 unsigned long cmdline_addr = 0; 128 const efi_char16_t *s2; 129 bool in_quote = false; 130 efi_status_t status; 131 u32 options_chars; 132 133 if (options_size > 0) 134 efi_measure_tagged_event((unsigned long)options, options_size, 135 EFISTUB_EVT_LOAD_OPTIONS); 136 137 efi_apply_loadoptions_quirk((const void **)&options, &options_size); 138 options_chars = options_size / sizeof(efi_char16_t); 139 140 if (options) { 141 s2 = options; 142 while (options_bytes < COMMAND_LINE_SIZE && options_chars--) { 143 efi_char16_t c = *s2++; 144 145 if (c < 0x80) { 146 if (c == L'\0' || c == L'\n') 147 break; 148 if (c == L'"') 149 in_quote = !in_quote; 150 else if (!in_quote && isspace((char)c)) 151 safe_options_bytes = options_bytes; 152 153 options_bytes++; 154 continue; 155 } 156 157 /* 158 * Get the number of UTF-8 bytes corresponding to a 159 * UTF-16 character. 160 * The first part handles everything in the BMP. 161 */ 162 options_bytes += 2 + (c >= 0x800); 163 /* 164 * Add one more byte for valid surrogate pairs. Invalid 165 * surrogates will be replaced with 0xfffd and take up 166 * only 3 bytes. 167 */ 168 if ((c & 0xfc00) == 0xd800) { 169 /* 170 * If the very last word is a high surrogate, 171 * we must ignore it since we can't access the 172 * low surrogate. 173 */ 174 if (!options_chars) { 175 options_bytes -= 3; 176 } else if ((*s2 & 0xfc00) == 0xdc00) { 177 options_bytes++; 178 options_chars--; 179 s2++; 180 } 181 } 182 } 183 if (options_bytes >= COMMAND_LINE_SIZE) { 184 options_bytes = safe_options_bytes; 185 efi_err("Command line is too long: truncated to %d bytes\n", 186 options_bytes); 187 } 188 } 189 190 options_bytes++; /* NUL termination */ 191 192 status = efi_bs_call(AllocatePool, EfiLoaderData, options_bytes, 193 (void **)&cmdline_addr); 194 if (status != EFI_SUCCESS) 195 return NULL; 196 197 snprintf((char *)cmdline_addr, options_bytes, "%.*ls", 198 options_bytes - 1, options); 199 200 *cmd_line_len = options_bytes; 201 return (char *)cmdline_addr; 202 } 203