[PATCH] uefi: add a test for sanity checking for the UEFI Boot path (LP: #1316019)
Colin Ian King
colin.king at canonical.com
Tue May 6 09:03:56 UTC 2014
On 05/05/14 07:57, Ivan Hu wrote:
> Add the sanity checking for UEFI Boot Path Boot####.
>
> Signed-off-by: Ivan Hu <ivan.hu at canonical.com>
> ---
> src/Makefile.am | 3 +-
> src/lib/include/fwts_uefi.h | 16 +-
> src/uefi/uefibootpath/uefibootpath.c | 815 ++++++++++++++++++++++++++++++++++
> 3 files changed, 832 insertions(+), 2 deletions(-)
> create mode 100644 src/uefi/uefibootpath/uefibootpath.c
>
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 155cba1..45cc306 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -89,7 +89,8 @@ fwts_SOURCES = main.c \
> uefi/uefirtvariable/uefirtvariable.c \
> uefi/uefirtmisc/uefirtmisc.c \
> uefi/securebootcert/securebootcert.c \
> - uefi/uefivarinfo/uefivarinfo.c
> + uefi/uefivarinfo/uefivarinfo.c \
> + uefi/uefibootpath/uefibootpath.c
>
> fwts_LDFLAGS = -lm
>
> diff --git a/src/lib/include/fwts_uefi.h b/src/lib/include/fwts_uefi.h
> index b28901f..ff2d2b4 100644
> --- a/src/lib/include/fwts_uefi.h
> +++ b/src/lib/include/fwts_uefi.h
> @@ -239,7 +239,8 @@ typedef enum {
> FWTS_UEFI_FILE_PATH_DEVICE_PATH_SUBTYPE = (0x04),
> FWTS_UEFI_PROTOCOL_DEVICE_PATH_SUBTYPE = (0x05),
> FWTS_UEFI_PIWG_FW_FILE_DEVICE_PATH_SUBTYPE = (0x06),
> - FWTS_UEFI_PIWG_FW_VOLUME_DEVICE_PATH_SUBTYPE = (0x07)
> + FWTS_UEFI_PIWG_FW_VOLUME_DEVICE_PATH_SUBTYPE = (0x07),
> + FWTS_UEFI_RELATIVE_OFFSET_RANGE_SUBTYPE = (0x08)
> } media_dev_path_subtypes;
>
> typedef enum {
> @@ -425,6 +426,12 @@ typedef struct {
> typedef struct {
> fwts_uefi_dev_path dev_path;
> fwts_uefi_guid guid;
> + uint32_t flow_control_map;
> +} __attribute__((packed)) fwts_uefi_uart_flowctl_messaging_dev_path;
> +
> +typedef struct {
> + fwts_uefi_dev_path dev_path;
> + fwts_uefi_guid guid;
> uint32_t reserved;
> uint64_t sas_addr;
> uint64_t lun;
> @@ -532,6 +539,13 @@ typedef struct {
>
> typedef struct {
> fwts_uefi_dev_path dev_path;
> + uint32_t reserved;
> + uint64_t starting_offset;
> + uint64_t ending_offset;
> +} __attribute__((packed)) fwts_relative_offset_range_path;
> +
> +typedef struct {
> + fwts_uefi_dev_path dev_path;
> uint16_t device_type;
> uint16_t status_flags;
> char description[0];
> diff --git a/src/uefi/uefibootpath/uefibootpath.c b/src/uefi/uefibootpath/uefibootpath.c
> new file mode 100644
> index 0000000..3e163f5
> --- /dev/null
> +++ b/src/uefi/uefibootpath/uefibootpath.c
> @@ -0,0 +1,815 @@
> +/*
> + * Copyright (C) 2014 Canonical
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + */
> +
> +#include <inttypes.h>
> +#include <stddef.h>
> +#include <ctype.h>
> +
> +#include "fwts.h"
> +#include "fwts_uefi.h"
> +
> +static int errors;
> +
> +static inline bool uefibootpath_check_pnpid(uint32_t id)
> +{
> + return (id & 0xFFFF) == 0x41D0;
> +}
> +
> +static int uefibootpath_init(fwts_framework *fw)
> +{
> + if (fwts_firmware_detect() != FWTS_FIRMWARE_UEFI) {
> + fwts_log_info(fw, "Cannot detect any UEFI firmware. Aborted.");
> + return FWTS_ABORTED;
> + }
> +
> + return FWTS_OK;
> +}
> +
> +static int *uefibootpath_check_dev_path(fwts_framework *fw, fwts_uefi_dev_path *dev_path, const size_t dev_path_len)
> +{
> + uint16_t len;
> +
> + len = dev_path->length[0] | (((uint16_t)dev_path->length[1]) << 8);
> +
> + switch (dev_path->type & 0x7f) {
> + case FWTS_UEFI_END_DEV_PATH_TYPE:
> + switch (dev_path->subtype) {
> + case FWTS_UEFI_END_ENTIRE_DEV_PATH_SUBTYPE:
> + case FWTS_UEFI_END_THIS_DEV_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIEndHwDevPathLength",
> + "The length of End of Hardware Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_dev_path));
> + errors++;
> + }
> + break;
> + default:
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "UEFIEndHwDevPathSubtype",
> + "Unknow subtype of End of Hardware Device Path.");
Unknown rather than Unknow
> + errors++;
> + break;
> + }
> + break;
> +
> + case FWTS_UEFI_HARDWARE_DEV_PATH_TYPE:
> + switch (dev_path->subtype) {
> + case FWTS_UEFI_PCI_DEV_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_pci_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIPCIDevPathLength",
> + "The length of PCI Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_pci_dev_path));
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_PCCARD_DEV_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_pccard_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIPCCARDDevPathLength",
> + "The length of PCCARD Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_pccard_dev_path));
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_MEMORY_MAPPED_DEV_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_mem_mapped_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIMemoryMapDevPathLength",
> + "The length of Memory Mapped Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_mem_mapped_dev_path));
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_VENDOR_DEV_PATH_SUBTYPE:
> + if (len < (sizeof(fwts_uefi_vendor_dev_path) - sizeof(uint8_t))) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIVendorDevPathLength",
> + "The length of Vendor Device Path is %" PRIu16 " bytes "
> + "should not be smaller than UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)(sizeof(fwts_uefi_vendor_dev_path) - sizeof(uint8_t)));
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_CONTROLLER_DEV_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_controller_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIControllerDevPathLength",
> + "The length of Controller Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_controller_dev_path));
> + errors++;
> + }
> + break;
> + default:
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "UEFIHwDevPathSubtype",
> + "Unknow subtype of Hardware Device Path.");
Unknown rather than Unknow
> + errors++;
> + break;
> + }
> + break;
> +
> + case FWTS_UEFI_ACPI_DEVICE_PATH_TYPE:
> + switch (dev_path->subtype) {
> + case FWTS_UEFI_ACPI_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_acpi_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIACPIDevPathLength",
> + "The length of ACPI Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_acpi_dev_path));
> + errors++;
> + }
> +
> + fwts_uefi_acpi_dev_path *a = (fwts_uefi_acpi_dev_path *)dev_path;
> + if (!uefibootpath_check_pnpid(a->hid)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIACPIDevPathPnPId",
> + "The ID value 0x%" PRIx32 " is not complied with "
> + "the compressed EISA-type ID.",
> + a->hid);
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_EXPANDED_ACPI_DEVICE_PATH_SUBTYPE:
> + if (len < (sizeof(fwts_uefi_expanded_acpi_dev_path) + 2*sizeof(char))) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIExpACPIDevPathLength",
> + "The length of Expanded ACPI Device Path is %" PRIu16 " bytes "
> + "should not be smaller than UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)(sizeof(fwts_uefi_expanded_acpi_dev_path) + 2*sizeof(char)));
> + errors++;
> + }
> +
> + fwts_uefi_expanded_acpi_dev_path *e = (fwts_uefi_expanded_acpi_dev_path *)dev_path;
> + if (!uefibootpath_check_pnpid(e->hid)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIExpACPIDevPathPnPId",
> + "The ID value 0x%" PRIx32 " is not complied with "
> + "the compressed EISA-type ID.",
> + e->hid);
> + errors++;
> + }
> +
> + if (!uefibootpath_check_pnpid(e->cid)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIExpACPIDevPathPnPId",
> + "The ID value 0x%" PRIx32 " is not complied with "
> + "the compressed EISA-type ID.",
> + e->cid);
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_ACPI_ADR_DEVICE_PATH_SUBTYPE:
> + if (len < sizeof(fwts_uefi_acpi_adr_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIADRDevPathLength",
> + "The length of _ADR Device Path is %" PRIu16 " bytes "
> + "should not be smaller than UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_acpi_adr_dev_path));
> + errors++;
> + }
> + break;
> + default:
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "UEFIACPIDevPathSubtype",
> + "Unknow subtype of ACPI Device Path.");
Unknown rather than Unknow
> + errors++;
> + break;
> + }
> + break;
> +
> + case FWTS_UEFI_MESSAGING_DEVICE_PATH_TYPE:
> + switch (dev_path->subtype) {
> + case FWTS_UEFI_ATAPI_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_atapi_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIATAPIDevPathLength",
> + "The length of ATAPI Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_atapi_dev_path));
> + errors++;
> + break;
> + }
> +
> + fwts_uefi_atapi_dev_path *a = (fwts_uefi_atapi_dev_path *)dev_path;
> + if (a->primary_secondary > 1) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIATAPIDevPathConfInvalid",
> + "The PrimarySecondary value of ATAPI Device Path is %" PRIu8
> + " which is out of configure range.",
perhaps "out of configuration range" is better.
> + a->primary_secondary);
> + errors++;
> + }
> + if (a->slave_master > 1) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIATAPIDevPathConfInvalid",
> + "The SlaveMaster value of ATAPI Device Path is %" PRIu8
> + " which is out of configure range.",
perhaps "out of configuration range" is better.
> + a->slave_master);
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_SCSI_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_scsi_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFISCSIDevPathLength",
> + "The length of SCSI Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_scsi_dev_path));
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_FIBRE_CHANNEL_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_fibre_channel_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIFibreChannelDevPathLength",
> + "The length of Fibre Channel Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_fibre_channel_dev_path));
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_1394_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_1394_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFI1394DevPathLength",
> + "The length of 1394 Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_1394_dev_path));
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_USB_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_usb_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIUSBDevPathLength",
> + "The length of USB Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_usb_dev_path));
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_USB_CLASS_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_usb_class_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIUSBClassDevPathLength",
> + "The length of USB Class Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_usb_class_dev_path));
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_I2O_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_i2o_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFII2ODevPathLength",
> + "The length of i2o Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_i2o_dev_path));
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_mac_addr_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIMACAddrDevPathLength",
> + "The length of MAC Address Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_mac_addr_dev_path));
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_IPV4_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_ipv4_dev_path_v2) && len != sizeof(fwts_uefi_ipv4_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIIPv4DevPathLength",
> + "The length of IPv4 Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_ipv4_dev_path));
> + errors++;
> + break;
> + }
> +
> + fwts_uefi_ipv4_dev_path *i4 = (fwts_uefi_ipv4_dev_path *)dev_path;
> + if (i4->static_ip_address > 1) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIIPv4DevPathConfInvalid",
> + "The StaticIPAddress value of IPv4 Device Path is %" PRIu8
> + " which is out of configure range.",
perhaps "out of configuration range" is better.
> + i4->static_ip_address);
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_IPV6_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_ipv6_dev_path_v2) && len != sizeof(fwts_uefi_ipv6_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIIPv6DevPathLength",
> + "The length of IPv6 Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_ipv6_dev_path));
> + errors++;
> + break;
> + }
> +
> + fwts_uefi_ipv6_dev_path *i6 = (fwts_uefi_ipv6_dev_path *)dev_path;
> + if (i6->static_ip_address > 2) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIIPV6DevPathConfInvalid",
> + "The IPAddressOrigin value of IPv6 Device Path is %" PRIu8
> + " which is out of configure range.",
perhaps "out of configuration range" is better.
> + i6->static_ip_address);
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_INFINIBAND_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_infiniband_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIInfiniBandDevPathLength",
> + "The length of InfiniBand Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_infiniband_dev_path));
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_UART_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_uart_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIUARTDevPathLength",
> + "The length of UART Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_uart_dev_path));
> + errors++;
> + break;
> + }
> +
> + fwts_uefi_uart_dev_path *u = (fwts_uefi_uart_dev_path *)dev_path;
> + if (u->parity > 5) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIUARTDevPathConfInvalid",
> + "The Parity value of UART Device Path is %" PRIu8
> + " which is out of configure range.",
perhaps "out of configuration range" is better.
> + u->parity);
> + errors++;
> + }
> + if (u->stop_bits > 3) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIUARTDevPathConfInvalid",
> + "The Parity value of UART Device Path is %" PRIu8
> + " which is out of configure range.",
perhaps "out of configuration range" is better.
> + u->parity);
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE:
> + if (len < sizeof(fwts_uefi_vendor_messaging_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIVendorMessagingDevPathLength",
> + "The length of Vendor-Defined Messaging Device Path is %" PRIu16 " bytes "
> + "should not be smaller than UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_vendor_messaging_dev_path));
> + errors++;
> + }
> +
> + size_t i;
> + static const fwts_uefi_guid guid[] = {
> + EFI_PC_ANSI_GUID,
> + EFI_VT_100_GUID,
> + EFI_VT_100_PLUS_GUID,
> + EFI_VT_UTF8_GUID,
> + EFI_UART_DEVICE_PATH_GUID,
> + EFI_SAS_DEVICE_PATH_GUID
> + };
> +
> + fwts_uefi_vendor_messaging_dev_path *v = (fwts_uefi_vendor_messaging_dev_path *)dev_path;
> + for (i = 0; i < sizeof(guid)/sizeof(guid[0]); i++)
> + if (memcmp(&v->guid, &guid[i], sizeof(fwts_uefi_guid)) == 0)
> + break;
> + switch (i) {
> + case 0:
> + case 1:
> + case 2:
> + case 3:
> + if (len != sizeof(fwts_uefi_vendor_messaging_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIVendorMessagingDevPathLength",
> + "The length of Vendor-Defined Messaging Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_vendor_messaging_dev_path));
> + errors++;
> + }
> + break;
> + case 4:
> + if (len != (sizeof(fwts_uefi_uart_flowctl_messaging_dev_path))) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIVendorMessagingDevPathLength",
> + "The length of UART Flow Control Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)(sizeof(fwts_uefi_uart_flowctl_messaging_dev_path)));
> + errors++;
> + }
> + break;
> + case 5:
> + if (len != (sizeof(fwts_uefi_sas_messaging_dev_path))) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIVendorMessagingDevPathLength",
> + "The length of Serial Attached SCSI (SAS) Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)(sizeof(fwts_uefi_sas_messaging_dev_path)));
> + errors++;
> + }
> + break;
> + }
> + break;
> + case FWTS_UEFI_FIBRE_CHANNEL_EX_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_fibre_channel_ex_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIFibreChannelExDevPathLength",
> + "The length of Fibre Channel Ex Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_fibre_channel_ex_dev_path));
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_SATA_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_sata_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFISATADevPathLength",
> + "The length of SATA Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_sata_dev_path));
> + errors++;
> + break;
> + }
> +
> + fwts_uefi_sata_dev_path *s = (fwts_uefi_sata_dev_path *)dev_path;
> + if (s->hbapn == 0xFFFF) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFISATADevPathConfInvalid",
> + "The HBA Port Number value of length of SATA Device Path is %" PRIu16
> + " which is reserved.",
> + s->hbapn);
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_USB_WWID_DEVICE_PATH_SUBTYPE:
> + if (len < sizeof(fwts_uefi_usb_wwid_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIUSBWWIDDevPathLength",
> + "The length of USB WWID Device Path is %" PRIu16 " bytes "
> + "should not be smaller than UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_usb_wwid_dev_path));
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_VLAN_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_vlan_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIVLANDevPathLength",
> + "The length of VLAN Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_vlan_dev_path));
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_LOGICAL_UNIT_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_logical_unit_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIDeviceLogicalUnitLength",
> + "The length of Device Logical Unit is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_logical_unit_dev_path));
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_SAS_EX_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_sas_ex_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFISASExDevPathLength",
> + "The length of Serial Attached SCSI Ex Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_sas_ex_dev_path));
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_ISCSI_DEVICE_PATH_SUBTYPE:
> + if (len < sizeof(fwts_uefi_iscsi_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIiSCSIDevPathLength",
> + "The length of iSCSI Device Path is %" PRIu16 " bytes "
> + "should not be smaller than UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_iscsi_dev_path));
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_NVM_EXPRESS_NAMESP_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_nvm_express_namespace_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFINVMExpressDevPathLength",
> + "The length of NVM Express Namespace Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_nvm_express_namespace_dev_path));
> + errors++;
> + break;
> + }
> +
> + fwts_uefi_nvm_express_namespace_dev_path *n = (fwts_uefi_nvm_express_namespace_dev_path *)dev_path;
> + if ((n->namesp_id == 0xFFFFFFFF) || (n->namesp_id == 0)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFINVMExpressDevPathInvalid",
> + "The Namespace Identifier value of NVM Express namespace Device Path is %" PRIu32
> + " which is invalid.",
> + n->namesp_id);
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_RELATIVE_OFFSET_RANGE_SUBTYPE:
> + if (len != sizeof(fwts_relative_offset_range_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIRelativeOffsetRangeLength",
> + "The length of Relative Offset Range is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_relative_offset_range_path));
> + errors++;
> + }
> + break;
> + default:
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "UEFIMessagingDevPathSubtype",
> + "Unknow subtype of Messaging Device PaERRORth.");
> + errors++;
> + break;
> + }
> + break;
> +
> + case FWTS_UEFI_MEDIA_DEVICE_PATH_TYPE:
> + switch (dev_path->subtype) {
> + case FWTS_UEFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_hard_drive_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIHardDriveDevPathLength",
> + "The length of Hard Drive Media Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_hard_drive_dev_path));
> + errors++;
> + break;
> + }
> +
> + fwts_uefi_hard_drive_dev_path *h = (fwts_uefi_hard_drive_dev_path *)dev_path;
> + if ((h->mbr_type > 2) || (h->mbr_type == 0)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIHardDriveDevPathConfInvalid",
> + "The Partition Format value of Hard Drive Media Device Path is %" PRIu8
> + " which is reserved.",
> + h->mbr_type);
> + errors++;
> + }
> + if (h->signature_type > 2) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIHardDriveDevPathConfInvalid",
> + "The Signature Type value of Hard Drive Media Device Path is %" PRIu8
> + " which is reserved.",
> + h->signature_type);
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_CDROM_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_uefi_cdrom_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFICDROMDevPathLength",
> + "The length of CD-ROM Media Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_cdrom_dev_path));
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_VENDOR_MEDIA_DEVICE_PATH_SUBTYPE:
> + if (len < sizeof(fwts_uefi_vendor_media_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIVendorMediaDevPathLength",
> + "The length of Vendor-Defined Media Device Path is %" PRIu16 " bytes "
> + "should not be smaller than UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_vendor_media_dev_path));
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_FILE_PATH_DEVICE_PATH_SUBTYPE:
> + if (len < sizeof(fwts_uefi_file_path_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIFilePathMediaDevPathLength",
> + "The length of File Path Media Device Path is %" PRIu16 " bytes "
> + "should not be smaller than UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_file_path_dev_path));
> + errors++;
> + break;
> + }
> + fwts_uefi_file_path_dev_path *f = (fwts_uefi_file_path_dev_path *)dev_path;
> + if (len != (sizeof(fwts_uefi_file_path_dev_path) + ((fwts_uefi_str16len(f->path_name) + 1) * sizeof(uint16_t)))) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIFilePathMediaPathLength",
> + "The length of File Path Media Device Path is %" PRIu16 " bytes "
> + "is not matching with adding the length of Path String %" PRIu16 " bytes.",
> + len,
> + (uint16_t)(sizeof(fwts_uefi_file_path_dev_path) + (fwts_uefi_str16len(f->path_name) * sizeof(uint16_t))));
> + errors++;
> + break;
> + }
> + break;
> + case FWTS_UEFI_PROTOCOL_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_media_protocol_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIMediaProtocolDevPathLength",
> + "The length of Media Protocol Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_media_protocol_dev_path));
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_PIWG_FW_FILE_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_piwg_fw_file_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIPIWGFwFileDevPathLength",
> + "The length of PIWG Firmware File Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_piwg_fw_file_dev_path));
> + errors++;
> + }
> + break;
> + case FWTS_UEFI_PIWG_FW_VOLUME_DEVICE_PATH_SUBTYPE:
> + if (len != sizeof(fwts_piwg_fw_volume_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIPIWGFwVolumeDevPathLength",
> + "The length of PIWG Firmware Volume Device Path is %" PRIu16 " bytes "
> + "and differs from UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_piwg_fw_volume_dev_path));
> + errors++;
> + }
> + break;
> + default:
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "UEFIMediaDevPathSubtype",
> + "Unknow subtype of Media Device Path.");
Unknown
> + errors++;
> + break;
> + }
> + break;
> +
> + case FWTS_UEFI_BIOS_DEVICE_PATH_TYPE:
> + switch (dev_path->subtype) {
> + case FWTS_UEFI_BIOS_DEVICE_PATH_SUBTYPE:
> + if (len < sizeof(fwts_uefi_bios_dev_path)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIBiosBootDevPathLength",
> + "The length of BIOS Boot Specification Device Path is %" PRIu16 " bytes "
> + "should not be smaller than UEFI specification defined %" PRIu16 " bytes.",
> + len,
> + (uint16_t)sizeof(fwts_uefi_bios_dev_path));
> + errors++;
> + break;
> + }
> + fwts_uefi_bios_dev_path *b = (fwts_uefi_bios_dev_path *)dev_path;
> + if (len != (sizeof(fwts_uefi_bios_dev_path) + strlen(b->description))) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "UEFIBiosBootDevPathLength",
> + "The length of BIOS Boot Specification Device Path is %" PRIu16 " bytes "
> + "is not matching with adding the length of Description String %" PRIu16 " bytes.",
> + len,
> + (uint16_t)(sizeof(fwts_uefi_bios_dev_path) + strlen(b->description)));
> + errors++;
> + }
> + break;
> + default:
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "UEFIBiosBootSpecDevPathSubtype",
> + "Unknow subtype of BIOS Boot Specification Device Path.");
Unknown
> + errors++;
> + break;
> + }
> + break;
> + default:
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "UEFIDevPathType",
> + "Unknow Type of Device Path.");
Unknown
> + errors++;
> + break;
> +
> + }
> +
> + /* Not end? - collect more */
> + if (!((dev_path->type & 0x7f) == (FWTS_UEFI_END_DEV_PATH_TYPE) &&
> + (dev_path->subtype == FWTS_UEFI_END_ENTIRE_DEV_PATH_SUBTYPE))) {
> + len = dev_path->length[0] | (((uint16_t)dev_path->length[1]) << 8);
> + if (len > 0) {
> + dev_path = (fwts_uefi_dev_path *)((char *)dev_path + len);
> + uefibootpath_check_dev_path(fw, dev_path, dev_path_len - len);
> + }
> + }
> +
> + return FWTS_OK;
> +}
> +
> +static int uefibootpath_info_bootdev(fwts_framework *fw, fwts_uefi_var *var)
> +{
> + fwts_uefi_load_option *load_option;
> + size_t len, offset;
> + char tmp[2048];
> +
> + if (var->datalen < sizeof(fwts_uefi_load_option)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "UEFIBootPathLength",
> + "The length of boot path variable is less than "
> + "the load option structure.");
> + return FWTS_ERROR;
> + }
> +
> + load_option = (fwts_uefi_load_option *)var->data;
> + fwts_uefi_str16_to_str(tmp, sizeof(tmp), load_option->description);
> + len = fwts_uefi_str16len(load_option->description);
> + fwts_log_info_verbatum(fw, "Info: %s\n", tmp);
> +
> + if (var->datalen < (sizeof(uint16_t) * (len + 1))) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "UEFIBootPathDescriptionLength",
> + "The length of description is large than "
> + "the boot path variable length.");
> + return FWTS_ERROR;
> + }
> +
> + /* Skip over description */
> + offset = sizeof(load_option->attributes) +
> + sizeof(load_option->file_path_list_length) +
> + (sizeof(uint16_t) * (len + 1));
> +
> + uefibootpath_check_dev_path(fw, (fwts_uefi_dev_path *)(var->data + offset), var->datalen - offset);
> +
> + return FWTS_OK;
> +
> +}
> +
> +static void uefibootpath_var(fwts_framework *fw, fwts_uefi_var *var)
> +{
> + char varname[512];
> + int ret;
> +
> + fwts_uefi_get_varname(varname, sizeof(varname), var);
> +
> + /* Check the boot load option Boot####. #### is a printed hex value */
> + if ((strlen(varname) == 8) && (strncmp(varname, "Boot", 4) == 0)
> + && isxdigit(varname[4]) && isxdigit(varname[5])
> + && isxdigit(varname[6]) && isxdigit(varname[7])) {
> + fwts_log_info_verbatum(fw, "Name: %s", varname);
> + errors = 0;
> + ret = uefibootpath_info_bootdev(fw, var);
> +
> + if (!errors && (ret == FWTS_OK))
> + fwts_passed(fw, "Check bootpath %s test passed.", varname);
> +
> + return;
> + }
> +
> +}
> +
> +static int uefibootpath_test1(fwts_framework *fw)
> +{
> + fwts_list name_list;
> +
> + if (fwts_uefi_get_variable_names(&name_list) == FWTS_ERROR) {
> + fwts_skipped(fw, "Cannot find any UEFI variables.");
> + return FWTS_SKIP;
> + } else {
> + fwts_list_link *item;
> +
> + fwts_list_foreach(item, &name_list) {
> + fwts_uefi_var var;
> + char *name = fwts_list_data(char *, item);
> +
> + if (fwts_uefi_get_variable(name, &var) == FWTS_OK) {
> + uefibootpath_var(fw, &var);
> + fwts_uefi_free_variable(&var);
> + }
> + }
> + }
> +
> + fwts_uefi_free_variable_names(&name_list);
> +
> + return FWTS_OK;
> +}
> +
> +static fwts_framework_minor_test uefibootpath_tests[] = {
> + { uefibootpath_test1, "Test UEFI Boot Path Boot####." },
> + { NULL, NULL }
> +};
> +
> +static fwts_framework_ops uefibootpath_ops = {
> + .description = "Sanity check for UEFI Boot Path Boot####.",
> + .init = uefibootpath_init,
> + .minor_tests = uefibootpath_tests
> +};
> +
> +FWTS_REGISTER("uefibootpath", &uefibootpath_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_TEST_UEFI | FWTS_FLAG_BATCH | FWTS_FLAG_ROOT_PRIV);
>
Just minor fixes required.
We also need fwts-test updated as this is a new test so some of
fwts-test tests will fail. And once this is accepted update the fwts
wiki with this new test.
Colin
More information about the fwts-devel
mailing list