[PATCH][V2] uefi: add a test for sanity checking for the UEFI Boot path (LP: #1316019)

Ivan Hu ivan.hu at canonical.com
Fri May 23 06:01:32 UTC 2014


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);
-- 
1.7.9.5




More information about the fwts-devel mailing list