grub_err_t grub_efi_set_variable(const char *var, const grub_efi_guid_t *guid, void *data, grub_size_t datasize) { grub_efi_status_t status; grub_efi_runtime_services_t *r; grub_efi_char16_t *var16; grub_size_t len, len16; len = grub_strlen (var); len16 = len * GRUB_MAX_UTF16_PER_UTF8; var16 = grub_malloc ((len16 + 1) * sizeof (var16[0])); if (!var16) return grub_errno; len16 = grub_utf8_to_utf16 (var16, len16, (grub_uint8_t *) var, len, NULL); var16[len16] = 0; r = grub_efi_system_table->runtime_services; status = efi_call_5 (r->set_variable, var16, guid, (GRUB_EFI_VARIABLE_NON_VOLATILE | GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS | GRUB_EFI_VARIABLE_RUNTIME_ACCESS), datasize, data); if (status == GRUB_EFI_SUCCESS) return GRUB_ERR_NONE; return grub_error (GRUB_ERR_IO, "could not set EFI variable `%s'", var); }
void * grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, grub_size_t *datasize_out) { grub_efi_status_t status; grub_efi_uintn_t datasize = 0; grub_efi_runtime_services_t *r; grub_efi_char16_t *var16; void *data; grub_size_t len, len16; *datasize_out = 0; len = grub_strlen (var); len16 = len * GRUB_MAX_UTF16_PER_UTF8; var16 = grub_malloc ((len16 + 1) * sizeof (var16[0])); if (!var16) return NULL; len16 = grub_utf8_to_utf16 (var16, len16, (grub_uint8_t *) var, len, NULL); var16[len16] = 0; r = grub_efi_system_table->runtime_services; status = efi_call_5 (r->get_variable, var16, guid, NULL, &datasize, NULL); if (!datasize) return NULL; data = grub_malloc (datasize); if (!data) { grub_free (var16); return NULL; } status = efi_call_5 (r->get_variable, var16, guid, NULL, &datasize, data); grub_free (var16); if (status == GRUB_EFI_SUCCESS) { *datasize_out = datasize; return data; } grub_free (data); return NULL; }
/* Return the array of handles which meet the requirement. If successful, the number of handles is stored in NUM_HANDLES. The array is allocated from the heap. */ grub_efi_handle_t * grub_efi_locate_handle (grub_efi_locate_search_type_t search_type, grub_efi_guid_t *protocol, void *search_key, grub_efi_uintn_t *num_handles) { grub_efi_boot_services_t *b; grub_efi_status_t status; grub_efi_handle_t *buffer; grub_efi_uintn_t buffer_size = 8 * sizeof (grub_efi_handle_t); buffer = grub_malloc (buffer_size); if (! buffer) return 0; b = grub_efi_system_table->boot_services; status = efi_call_5 (b->locate_handle, search_type, protocol, search_key, &buffer_size, buffer); if (status == GRUB_EFI_BUFFER_TOO_SMALL) { grub_free (buffer); buffer = grub_malloc (buffer_size); if (! buffer) return 0; status = efi_call_5 (b->locate_handle, search_type, protocol, search_key, &buffer_size, buffer); } if (status != GRUB_EFI_SUCCESS) { grub_free (buffer); return 0; } *num_handles = buffer_size / sizeof (grub_efi_handle_t); return buffer; }
static grub_err_t grub_tpm2_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, grub_size_t size, grub_uint8_t pcr, const char *description) { EFI_TCG2_EVENT *event; grub_efi_status_t status; grub_efi_tpm2_protocol_t *tpm; tpm = grub_efi_open_protocol (tpm_handle, &tpm2_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (!grub_tpm2_present (tpm)) return 0; event = grub_zalloc (sizeof (EFI_TCG2_EVENT) + grub_strlen (description) + 1); if (!event) return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate TPM event buffer")); event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER); event->Header.HeaderVersion = 1; event->Header.PCRIndex = pcr; event->Header.EventType = EV_IPL; event->Size = sizeof (*event) - sizeof (event->Event) + grub_strlen (description) + 1; grub_memcpy (event->Event, description, grub_strlen (description) + 1); status = efi_call_5 (tpm->hash_log_extend_event, tpm, 0, buf, (grub_uint64_t) size, event); switch (status) { case GRUB_EFI_SUCCESS: return 0; case GRUB_EFI_DEVICE_ERROR: return grub_error (GRUB_ERR_IO, N_("Command failed")); case GRUB_EFI_INVALID_PARAMETER: return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter")); case GRUB_EFI_BUFFER_TOO_SMALL: return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small")); case GRUB_EFI_NOT_FOUND: return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable")); default: return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error")); } }
static grub_efi_boolean_t grub_tpm_present(grub_efi_tpm_protocol_t *tpm) { grub_efi_status_t status; TCG_EFI_BOOT_SERVICE_CAPABILITY caps; grub_uint32_t flags; grub_efi_physical_address_t eventlog, lastevent; caps.Size = (grub_uint8_t)sizeof(caps); status = efi_call_5(tpm->status_check, tpm, &caps, &flags, &eventlog, &lastevent); if (status != GRUB_EFI_SUCCESS || caps.TPMDeactivatedFlag || !caps.TPMPresentFlag) return 0; return 1; }
static grub_err_t grub_tpm2_execute (grub_efi_handle_t tpm_handle, PassThroughToTPM_InputParamBlock *inbuf, PassThroughToTPM_OutputParamBlock *outbuf) { grub_efi_status_t status; grub_efi_tpm2_protocol_t *tpm; grub_uint32_t inhdrsize = sizeof (*inbuf) - sizeof (inbuf->TPMOperandIn); grub_uint32_t outhdrsize = sizeof (*outbuf) - sizeof (outbuf->TPMOperandOut); tpm = grub_efi_open_protocol (tpm_handle, &tpm2_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (!grub_tpm2_present (tpm)) return 0; /* UEFI TPM protocol takes the raw operand block, no param block header. */ status = efi_call_5 (tpm->submit_command, tpm, inbuf->IPBLength - inhdrsize, inbuf->TPMOperandIn, outbuf->OPBLength - outhdrsize, outbuf->TPMOperandOut); switch (status) { case GRUB_EFI_SUCCESS: return 0; case GRUB_EFI_DEVICE_ERROR: return grub_error (GRUB_ERR_IO, N_("Command failed")); case GRUB_EFI_INVALID_PARAMETER: return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter")); case GRUB_EFI_BUFFER_TOO_SMALL: return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small")); case GRUB_EFI_NOT_FOUND: return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable")); default: return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error")); } }
grub_err_t grub_tpm_log_event(unsigned char *buf, grub_size_t size, grub_uint8_t pcr, const char *description) { grub_efi_handle_t tpm_handle; grub_efi_status_t status; grub_efi_tpm_protocol_t *tpm; grub_efi_tpm2_protocol_t *tpm2; grub_efi_physical_address_t lastevent; grub_efi_uint8_t protocol_version; grub_uint32_t eventnum = 0; grub_uint32_t algorithm; Event *event; EFI_TCG2_EVENT *event2; if (!grub_tpm_handle_find(&tpm_handle, &protocol_version)) { return 0; } if (protocol_version == 1) { tpm = grub_efi_open_protocol (tpm_handle, &tpm_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (!grub_tpm_present(tpm)) { return 0; } event = grub_zalloc(sizeof (Event) + grub_strlen(description) + 1); if (!event) { grub_printf("No buffer\n"); return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate TPM event buffer")); } event->pcrindex = pcr; event->eventtype = 0x0d; event->eventsize = grub_strlen(description) + 1; grub_memcpy(event->event, description, event->eventsize); algorithm = 0x00000004; /* SHA 1 */ status = efi_call_7 (tpm->log_extend_event, tpm, buf, (grub_uint64_t) size, algorithm, event, &eventnum, &lastevent); switch (status) { case GRUB_EFI_SUCCESS: return 0; case GRUB_EFI_DEVICE_ERROR: return grub_error (GRUB_ERR_IO, N_("Command failed")); case GRUB_EFI_INVALID_PARAMETER: return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter")); case GRUB_EFI_BUFFER_TOO_SMALL: return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small")); case GRUB_EFI_NOT_FOUND: return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable")); default: return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error")); } } else { tpm2 = grub_efi_open_protocol (tpm_handle, &tpm2_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (!grub_tpm2_present(tpm2)) { return 0; } event2 = grub_zalloc(sizeof (Event) + grub_strlen(description) + 1); if (!event2) { grub_printf("No buffer\n"); return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate TPM event buffer")); } event2->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER); event2->Header.HeaderVersion = 1; event2->Header.PCRIndex = pcr; event2->Header.EventType = 0x0d; event2->Size = sizeof(*event2) - sizeof(event2->Event) + grub_strlen(description) + 1; grub_memcpy(event2->Event, description, grub_strlen(description) + 1); status = efi_call_5 (tpm2->hash_log_extend_event, tpm2, 0, buf, (grub_uint64_t) size, event2); switch (status) { case GRUB_EFI_SUCCESS: return 0; case GRUB_EFI_DEVICE_ERROR: return grub_error (GRUB_ERR_IO, N_("Command failed")); case GRUB_EFI_INVALID_PARAMETER: return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter")); case GRUB_EFI_BUFFER_TOO_SMALL: return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small")); case GRUB_EFI_NOT_FOUND: return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable")); default: return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error")); } } }