ACK: [PATCH][V2] uefi: add a test for sanity checking for the UEFI Boot path (LP: #1316019)
Keng-Yu Lin
keng-yu.lin at canonical.com
Thu Jul 10 08:06:54 UTC 2014
On Wed, Jun 11, 2014 at 1:25 AM, Alex Hung <alex.hung at canonical.com> wrote:
> On 05/22/2014 11:01 PM, Ivan Hu wrote:
>> Add the sanity checking for UEFI Boot Path Boot####.
>>
>> Signed-off-by: Ivan Hu <ivan.hu at canonical.com>
>> ---
>> .../arg-show-tests-0001/arg-show-tests-0001.log | 2 +
>> .../arg-show-tests-full-0001.log | 6 +-
>> src/Makefile.am | 3 +-
>> src/lib/include/fwts_uefi.h | 16 +-
>> src/uefi/uefibootpath/uefibootpath.c | 794 ++++++++++++++++++++
>> 5 files changed, 818 insertions(+), 3 deletions(-)
>> create mode 100644 src/uefi/uefibootpath/uefibootpath.c
>>
>> diff --git a/fwts-test/arg-show-tests-0001/arg-show-tests-0001.log b/fwts-test/arg-show-tests-0001/arg-show-tests-0001.log
>> index 9833208..1e82885 100644
>> --- a/fwts-test/arg-show-tests-0001/arg-show-tests-0001.log
>> +++ b/fwts-test/arg-show-tests-0001/arg-show-tests-0001.log
>> @@ -37,6 +37,7 @@ Batch tests:
>> pnp BIOS Support Installation structure test.
>> securebootcert UEFI secure boot test.
>> syntaxcheck Re-assemble DSDT and find syntax errors and warnings.
>> + uefibootpath Sanity check for UEFI Boot Path Boot####.
>> version Gather kernel system information.
>> virt CPU Virtualisation Configuration test.
>> wakealarm ACPI Wakealarm tests.
>> @@ -77,6 +78,7 @@ Unsafe tests:
>> UEFI tests:
>> csm UEFI Compatibility Support Module test.
>> securebootcert UEFI secure boot test.
>> + uefibootpath Sanity check for UEFI Boot Path Boot####.
>> uefirtmisc UEFI miscellaneous runtime service interface tests.
>> uefirttime UEFI Runtime service time interface tests.
>> uefirtvariable UEFI Runtime service variable interface tests.
>> diff --git a/fwts-test/arg-show-tests-full-0001/arg-show-tests-full-0001.log b/fwts-test/arg-show-tests-full-0001/arg-show-tests-full-0001.log
>> index 074a0f1..a9e743b 100644
>> --- a/fwts-test/arg-show-tests-full-0001/arg-show-tests-full-0001.log
>> +++ b/fwts-test/arg-show-tests-full-0001/arg-show-tests-full-0001.log
>> @@ -258,6 +258,8 @@ Batch tests:
>> syntaxcheck (2 tests):
>> Disassemble and reassemble DSDT
>> Disassemble and reassemble SSDT
>> + uefibootpath (1 test):
>> + Test UEFI Boot Path Boot####.
>> version (4 tests):
>> Gather kernel signature.
>> Gather kernel system information.
>> @@ -350,6 +352,8 @@ UEFI tests:
>> UEFI Compatibility Support Module test.
>> securebootcert (1 test):
>> UEFI secure boot test.
>> + uefibootpath (1 test):
>> + Test UEFI Boot Path Boot####.
>> uefirtmisc (2 tests):
>> Test for UEFI miscellaneous runtime service interfaces.
>> Stress test for UEFI miscellaneous runtime service interfaces.
>> @@ -367,4 +371,4 @@ UEFI tests:
>> Test UEFI RT service set variable interface stress test.
>> Test UEFI RT service query variable info interface stress test.
>>
>> -Total of 286 tests
>> +Total of 288 tests
>> diff --git a/src/Makefile.am b/src/Makefile.am
>> index 492eb46..8de4331 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..007aa0f
>> --- /dev/null
>> +++ b/src/uefi/uefibootpath/uefibootpath.c
>> @@ -0,0 +1,794 @@
>> +/*
>> + * 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_log_info_verbatum(fw, "Unknow subtype of End of Hardware Device Path.");
>> + 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_log_info_verbatum(fw, "Unknow subtype of Hardware Device Path.");
>> + 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_log_info_verbatum(fw, "Unknow subtype of ACPI Device Path.");
>> + 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 configuration range.",
>> + 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 configuration range.",
>> + 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 configuration range.",
>> + 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 configuration range.",
>> + 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 configuration range.",
>> + 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 configuration range.",
>> + 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_log_info_verbatum(fw, "Unknow subtype of Messaging Device PaERRORth.");
>> + 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_log_info_verbatum(fw, "Unknow subtype of Media Device Path.");
>> + 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_log_info_verbatum(fw, "Unknow subtype of BIOS Boot Specification Device Path.");
>> + break;
>> + }
>> + break;
>> + default:
>> + fwts_log_info_verbatum(fw, "Unknow Type of Device Path.");
>> + 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);
>>
>
> Acked-by: Alex Hung <alex.hung at canonical.com>
>
Acked-by: Keng-Yu Lin <kengyu at canonical.com>
More information about the fwts-devel
mailing list