diff options
| author | Tom Rini <[email protected]> | 2021-08-15 13:42:42 -0400 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2021-08-15 13:42:42 -0400 |
| commit | fdc4fda33051bcb9eb782001afe2bdd3c0d09eae (patch) | |
| tree | 24dac98ec7eb2c13c8d35275c4cd2a8a37debf44 /lib | |
| parent | 85ccbf666e549f0b06c29d565b9e4fdd87cf6600 (diff) | |
| parent | 61ee780352e054df587d8781f23b323c967b5d2a (diff) | |
Merge tag 'efi-2021-10-rc2-2' of https://source.denx.de/u-boot/custodians/u-boot-efi
Pull request for efi-2021-10-rc2-2
Documentation:
* Require Sphinx >= 2.4.4 for 'make htmldocs'
* Move devicetree documentation to restructured text and update it
* Document stm32mp1 devicetree bindings
UEFI
* Extend measurement to UEFI variables and ExitBootServices()
* Support Uri() node in devicetree to text protocol
* Add Linux magic token to RISC-V EFI test binaries
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/efi_loader/efi_boottime.c | 25 | ||||
| -rw-r--r-- | lib/efi_loader/efi_device_path_to_text.c | 13 | ||||
| -rw-r--r-- | lib/efi_loader/efi_tcg2.c | 356 |
3 files changed, 388 insertions, 6 deletions
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 0b98e918137..f0283b539e4 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -2182,6 +2182,11 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, efi_set_watchdog(0); WATCHDOG_RESET(); out: + if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) { + if (ret != EFI_SUCCESS) + efi_tcg2_notify_exit_boot_services_failed(); + } + return EFI_EXIT(ret); } @@ -2994,6 +2999,16 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, image_obj->exit_status = &exit_status; image_obj->exit_jmp = &exit_jmp; + if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) { + if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION) { + ret = efi_tcg2_measure_efi_app_invocation(); + if (ret != EFI_SUCCESS) { + log_warning("tcg2 measurement fails(0x%lx)\n", + ret); + } + } + } + /* call the image! */ if (setjmp(&exit_jmp)) { /* @@ -3252,6 +3267,16 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, exit_status != EFI_SUCCESS) efi_delete_image(image_obj, loaded_image_protocol); + if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) { + if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION) { + ret = efi_tcg2_measure_efi_app_exit(); + if (ret != EFI_SUCCESS) { + log_warning("tcg2 measurement fails(0x%lx)\n", + ret); + } + } + } + /* Make sure entry/exit counts for EFI world cross-overs match */ EFI_EXIT(exit_status); diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index 675e80bcb8a..d46327a1c94 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -190,6 +190,19 @@ static char *dp_msging(char *s, struct efi_device_path *dp) break; } + case DEVICE_PATH_SUB_TYPE_MSG_URI: { + struct efi_device_path_uri *udp = + (struct efi_device_path_uri *)dp; + int n; + + n = (int)udp->dp.length - sizeof(struct efi_device_path_uri); + + s += sprintf(s, "Uri("); + if (n > 0 && n < MAX_NODE_LEN - 6) + s += snprintf(s, n, "%s", (char *)udp->uri); + s += sprintf(s, ")"); + break; + } case DEVICE_PATH_SUB_TYPE_MSG_SD: case DEVICE_PATH_SUB_TYPE_MSG_MMC: { const char *typename = diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c index 1319a8b3786..35e69b91129 100644 --- a/lib/efi_loader/efi_tcg2.c +++ b/lib/efi_loader/efi_tcg2.c @@ -35,6 +35,7 @@ struct event_log_buffer { }; static struct event_log_buffer event_log; +static bool tcg2_efi_app_invoked; /* * When requesting TPM2_CAP_TPM_PROPERTIES the value is on a standard offset. * Since the current tpm2_get_capability() response buffers starts at @@ -78,6 +79,19 @@ static const struct digest_info hash_algo_list[] = { }, }; +struct variable_info { + u16 *name; + const efi_guid_t *guid; +}; + +static struct variable_info secure_variables[] = { + {L"SecureBoot", &efi_global_variable_guid}, + {L"PK", &efi_global_variable_guid}, + {L"KEK", &efi_global_variable_guid}, + {L"db", &efi_guid_image_security_database}, + {L"dbx", &efi_guid_image_security_database}, +}; + #define MAX_HASH_COUNT ARRAY_SIZE(hash_algo_list) /** @@ -1265,6 +1279,39 @@ free_pool: } /** + * tcg2_measure_event() - common function to add event log and extend PCR + * + * @dev: TPM device + * @pcr_index: PCR index + * @event_type: type of event added + * @size: event size + * @event: event data + * + * Return: status code + */ +static efi_status_t +tcg2_measure_event(struct udevice *dev, u32 pcr_index, u32 event_type, + u32 size, u8 event[]) +{ + struct tpml_digest_values digest_list; + efi_status_t ret; + + ret = tcg2_create_digest(event, size, &digest_list); + if (ret != EFI_SUCCESS) + goto out; + + ret = tcg2_pcr_extend(dev, pcr_index, &digest_list); + if (ret != EFI_SUCCESS) + goto out; + + ret = tcg2_agile_log_append(pcr_index, event_type, &digest_list, + size, event); + +out: + return ret; +} + +/** * efi_append_scrtm_version - Append an S-CRTM EV_S_CRTM_VERSION event on the * eventlog and extend the PCRs * @@ -1274,27 +1321,308 @@ free_pool: */ static efi_status_t efi_append_scrtm_version(struct udevice *dev) { - struct tpml_digest_values digest_list; u8 ver[] = U_BOOT_VERSION_STRING; - const int pcr_index = 0; efi_status_t ret; - ret = tcg2_create_digest(ver, sizeof(ver), &digest_list); + ret = tcg2_measure_event(dev, 0, EV_S_CRTM_VERSION, sizeof(ver), ver); + + return ret; +} + +/** + * tcg2_measure_variable() - add variable event log and extend PCR + * + * @dev: TPM device + * @pcr_index: PCR index + * @event_type: type of event added + * @var_name: variable name + * @guid: guid + * @data_size: variable data size + * @data: variable data + * + * Return: status code + */ +static efi_status_t tcg2_measure_variable(struct udevice *dev, u32 pcr_index, + u32 event_type, u16 *var_name, + const efi_guid_t *guid, + efi_uintn_t data_size, u8 *data) +{ + u32 event_size; + efi_status_t ret; + struct efi_tcg2_uefi_variable_data *event; + + event_size = sizeof(event->variable_name) + + sizeof(event->unicode_name_length) + + sizeof(event->variable_data_length) + + (u16_strlen(var_name) * sizeof(u16)) + data_size; + event = malloc(event_size); + if (!event) + return EFI_OUT_OF_RESOURCES; + + guidcpy(&event->variable_name, guid); + event->unicode_name_length = u16_strlen(var_name); + event->variable_data_length = data_size; + memcpy(event->unicode_name, var_name, + (event->unicode_name_length * sizeof(u16))); + if (data) { + memcpy((u16 *)event->unicode_name + event->unicode_name_length, + data, data_size); + } + ret = tcg2_measure_event(dev, pcr_index, event_type, event_size, + (u8 *)event); + free(event); + return ret; +} + +/** + * tcg2_measure_boot_variable() - measure boot variables + * + * @dev: TPM device + * + * Return: status code + */ +static efi_status_t tcg2_measure_boot_variable(struct udevice *dev) +{ + u16 *boot_order; + u16 *boot_index; + u16 var_name[] = L"BootOrder"; + u16 boot_name[] = L"Boot####"; + u8 *bootvar; + efi_uintn_t var_data_size; + u32 count, i; + efi_status_t ret; + + boot_order = efi_get_var(var_name, &efi_global_variable_guid, + &var_data_size); + if (!boot_order) { + ret = EFI_NOT_FOUND; + goto error; + } + + ret = tcg2_measure_variable(dev, 1, EV_EFI_VARIABLE_BOOT2, var_name, + &efi_global_variable_guid, var_data_size, + (u8 *)boot_order); + if (ret != EFI_SUCCESS) + goto error; + + count = var_data_size / sizeof(*boot_order); + boot_index = boot_order; + for (i = 0; i < count; i++) { + efi_create_indexed_name(boot_name, sizeof(boot_name), + "Boot", *boot_index++); + + bootvar = efi_get_var(boot_name, &efi_global_variable_guid, + &var_data_size); + + if (!bootvar) { + log_info("%ls not found\n", boot_name); + continue; + } + + ret = tcg2_measure_variable(dev, 1, EV_EFI_VARIABLE_BOOT2, + boot_name, + &efi_global_variable_guid, + var_data_size, bootvar); + free(bootvar); + if (ret != EFI_SUCCESS) + goto error; + } + +error: + free(boot_order); + return ret; +} + +/** + * efi_tcg2_measure_efi_app_invocation() - measure efi app invocation + * + * Return: status code + */ +efi_status_t efi_tcg2_measure_efi_app_invocation(void) +{ + efi_status_t ret; + u32 pcr_index; + struct udevice *dev; + u32 event = 0; + + if (tcg2_efi_app_invoked) + return EFI_SUCCESS; + + ret = platform_get_tpm2_device(&dev); + if (ret != EFI_SUCCESS) + return ret; + + ret = tcg2_measure_boot_variable(dev); if (ret != EFI_SUCCESS) goto out; - ret = tcg2_pcr_extend(dev, pcr_index, &digest_list); + ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION, + strlen(EFI_CALLING_EFI_APPLICATION), + (u8 *)EFI_CALLING_EFI_APPLICATION); if (ret != EFI_SUCCESS) goto out; - ret = tcg2_agile_log_append(pcr_index, EV_S_CRTM_VERSION, &digest_list, - sizeof(ver), ver); + for (pcr_index = 0; pcr_index <= 7; pcr_index++) { + ret = tcg2_measure_event(dev, pcr_index, EV_SEPARATOR, + sizeof(event), (u8 *)&event); + if (ret != EFI_SUCCESS) + goto out; + } + tcg2_efi_app_invoked = true; out: return ret; } /** + * efi_tcg2_measure_efi_app_exit() - measure efi app exit + * + * Return: status code + */ +efi_status_t efi_tcg2_measure_efi_app_exit(void) +{ + efi_status_t ret; + struct udevice *dev; + + ret = platform_get_tpm2_device(&dev); + if (ret != EFI_SUCCESS) + return ret; + + ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION, + strlen(EFI_RETURNING_FROM_EFI_APPLICATION), + (u8 *)EFI_RETURNING_FROM_EFI_APPLICATION); + return ret; +} + +/** + * efi_tcg2_notify_exit_boot_services() - ExitBootService callback + * + * @event: callback event + * @context: callback context + */ +static void EFIAPI +efi_tcg2_notify_exit_boot_services(struct efi_event *event, void *context) +{ + efi_status_t ret; + struct udevice *dev; + + EFI_ENTRY("%p, %p", event, context); + + ret = platform_get_tpm2_device(&dev); + if (ret != EFI_SUCCESS) + goto out; + + ret = tcg2_measure_event(dev, 5, EV_EFI_ACTION, + strlen(EFI_EXIT_BOOT_SERVICES_INVOCATION), + (u8 *)EFI_EXIT_BOOT_SERVICES_INVOCATION); + if (ret != EFI_SUCCESS) + goto out; + + ret = tcg2_measure_event(dev, 5, EV_EFI_ACTION, + strlen(EFI_EXIT_BOOT_SERVICES_SUCCEEDED), + (u8 *)EFI_EXIT_BOOT_SERVICES_SUCCEEDED); + +out: + EFI_EXIT(ret); +} + +/** + * efi_tcg2_notify_exit_boot_services_failed() + * - notify ExitBootServices() is failed + * + * Return: status code + */ +efi_status_t efi_tcg2_notify_exit_boot_services_failed(void) +{ + struct udevice *dev; + efi_status_t ret; + + ret = platform_get_tpm2_device(&dev); + if (ret != EFI_SUCCESS) + goto out; + + ret = tcg2_measure_event(dev, 5, EV_EFI_ACTION, + strlen(EFI_EXIT_BOOT_SERVICES_INVOCATION), + (u8 *)EFI_EXIT_BOOT_SERVICES_INVOCATION); + if (ret != EFI_SUCCESS) + goto out; + + ret = tcg2_measure_event(dev, 5, EV_EFI_ACTION, + strlen(EFI_EXIT_BOOT_SERVICES_FAILED), + (u8 *)EFI_EXIT_BOOT_SERVICES_FAILED); + +out: + return ret; +} + +/** + * tcg2_measure_secure_boot_variable() - measure secure boot variables + * + * @dev: TPM device + * + * Return: status code + */ +static efi_status_t tcg2_measure_secure_boot_variable(struct udevice *dev) +{ + u8 *data; + efi_uintn_t data_size; + u32 count, i; + efi_status_t ret; + + count = ARRAY_SIZE(secure_variables); + for (i = 0; i < count; i++) { + /* + * According to the TCG2 PC Client PFP spec, "SecureBoot", + * "PK", "KEK", "db" and "dbx" variables must be measured + * even if they are empty. + */ + data = efi_get_var(secure_variables[i].name, + secure_variables[i].guid, + &data_size); + + ret = tcg2_measure_variable(dev, 7, + EV_EFI_VARIABLE_DRIVER_CONFIG, + secure_variables[i].name, + secure_variables[i].guid, + data_size, data); + free(data); + if (ret != EFI_SUCCESS) + goto error; + } + + /* + * TCG2 PC Client PFP spec says "dbt" and "dbr" are + * measured if present and not empty. + */ + data = efi_get_var(L"dbt", + &efi_guid_image_security_database, + &data_size); + if (data) { + ret = tcg2_measure_variable(dev, 7, + EV_EFI_VARIABLE_DRIVER_CONFIG, + L"dbt", + &efi_guid_image_security_database, + data_size, data); + free(data); + } + + data = efi_get_var(L"dbr", + &efi_guid_image_security_database, + &data_size); + if (data) { + ret = tcg2_measure_variable(dev, 7, + EV_EFI_VARIABLE_DRIVER_CONFIG, + L"dbr", + &efi_guid_image_security_database, + data_size, data); + free(data); + } + +error: + return ret; +} + +/** * efi_tcg2_register() - register EFI_TCG2_PROTOCOL * * If a TPM2 device is available, the TPM TCG2 Protocol is registered @@ -1305,6 +1633,7 @@ efi_status_t efi_tcg2_register(void) { efi_status_t ret = EFI_SUCCESS; struct udevice *dev; + struct efi_event *event; ret = platform_get_tpm2_device(&dev); if (ret != EFI_SUCCESS) { @@ -1328,6 +1657,21 @@ efi_status_t efi_tcg2_register(void) tcg2_uninit(); goto fail; } + + ret = efi_create_event(EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK, + efi_tcg2_notify_exit_boot_services, NULL, + NULL, &event); + if (ret != EFI_SUCCESS) { + tcg2_uninit(); + goto fail; + } + + ret = tcg2_measure_secure_boot_variable(dev); + if (ret != EFI_SUCCESS) { + tcg2_uninit(); + goto fail; + } + return ret; fail: |
