[PATCH 1/3] uefi: add sanity check for UEFI ESRT table (LP: #1553043)

Ivan Hu ivan.hu at canonical.com
Fri Mar 4 06:56:29 UTC 2016


Add sanity check for UEFI ESRT table which is  for firmware update function.

Signed-off-by: Ivan Hu <ivan.hu at canonical.com>
---
 src/Makefile.am      |   3 +-
 src/uefi/esrt/esrt.c | 261 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 263 insertions(+), 1 deletion(-)
 create mode 100644 src/uefi/esrt/esrt.c

diff --git a/src/Makefile.am b/src/Makefile.am
index 2de2585..e1332a2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -130,7 +130,8 @@ fwts_SOURCES = main.c 				\
 	uefi/uefivarinfo/uefivarinfo.c		\
 	uefi/uefibootpath/uefibootpath.c	\
 	uefi/uefirtauthvar/uefirtauthvar.c	\
-	uefi/esrtdump/esrtdump.c
+	uefi/esrtdump/esrtdump.c		\
+	uefi/esrt/esrt.c
 
 fwts_LDFLAGS = -lm `pkg-config --libs glib-2.0 gio-2.0`
 
diff --git a/src/uefi/esrt/esrt.c b/src/uefi/esrt/esrt.c
new file mode 100644
index 0000000..897bd6b
--- /dev/null
+++ b/src/uefi/esrt/esrt.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2016 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 <errno.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "fwts.h"
+#include "fwts_uefi.h"
+
+#define FWTS_ESRT_DIR_PATH		"/sys/firmware/efi/esrt"
+#define FWTS_ESRT_ENTRY_PATH		"/sys/firmware/efi/esrt/entries"
+#define FWTS_ESRT_RES_COUNT_PATH	"/sys/firmware/efi/esrt/fw_resource_count"
+#define FWTS_ESRT_RES_COUNT_MAX_PATH	"/sys/firmware/efi/esrt/fw_resource_count_max"
+#define FWTS_ESRT_RES_VERSION_PATH	"/sys/firmware/efi/esrt/fw_resource_version"
+
+/* Current Entry Version */
+#define ESRT_FIRMWARE_RESOURCE_VERSION 1
+
+static int esrt_init(fwts_framework *fw)
+{
+	DIR *dir = opendir(FWTS_ESRT_DIR_PATH);
+
+	if (fwts_firmware_detect() != FWTS_FIRMWARE_UEFI) {
+		fwts_log_info(fw, "Cannot detect any UEFI firmware. Aborted.");
+		return FWTS_ABORTED;
+	}
+
+	if (dir) {
+		/* Directory exists. */
+		closedir(dir);
+		return FWTS_OK;
+	} else if (ENOENT == errno) {
+		/* Directory does not exist. */
+		fwts_log_info(fw, "Cannot find ESRT table, firmware seems not supported. Aborted.");
+		return FWTS_ABORTED;
+	} else {
+		/* opendir() failed for some other reason. */
+		fwts_log_info(fw, "Cannot open ESRT directory on /sys/firmware/efi/, Aborted.");
+		return FWTS_ABORTED;
+	}
+}
+
+static void check_entries(fwts_framework *fw, bool *passed)
+{
+
+	DIR *dir;
+	struct dirent *entry;
+	bool entry_found = false;
+
+	if (!(dir = opendir(FWTS_ESRT_ENTRY_PATH))) {
+		fwts_failed(fw, LOG_LEVEL_MEDIUM, "CannotOpenDir",
+			"Cannot open directory %s", FWTS_ESRT_ENTRY_PATH);
+		*passed = false;
+		return;
+	}
+
+	do {
+		entry = readdir(dir);
+		if (entry && strstr(entry->d_name, "entry")) {
+			char path[PATH_MAX];
+			char *str;
+			uint32_t fwversion;
+			uint32_t lowest_sp_fwversion;
+			bool fwversions_found = true;
+
+			entry_found = true;
+
+			snprintf(path, sizeof(path), FWTS_ESRT_ENTRY_PATH "/%s/fw_class", entry->d_name);
+			if ((str = fwts_get(path)) == NULL) {
+				fwts_failed(fw, LOG_LEVEL_MEDIUM, "CannotGetFwClass",
+						"Missing or failed to get FwClass on %s.", entry->d_name);
+				*passed = false;
+			} else
+				free(str);
+
+			snprintf(path, sizeof(path), FWTS_ESRT_ENTRY_PATH "/%s/fw_type", entry->d_name);
+			if ((str = fwts_get(path)) == NULL) {
+				fwts_failed(fw, LOG_LEVEL_MEDIUM, "CannotGetFwType",
+						"Missing or failed to get FwType on %s.", entry->d_name);
+				*passed = false;
+			} else {
+				uint32_t fwtype = strtoul(str, NULL, 10);
+
+				if (fwtype > ESRT_FW_TYPE_UEFIDRIVER) {
+					fwts_failed(fw, LOG_LEVEL_MEDIUM, "InvalidValue",
+						"The FwType value on %s is %" PRIu32
+						", which is undefined on UEFI Spec."
+						, entry->d_name, fwtype);
+					*passed = false;
+				}
+				free(str);
+			}
+			snprintf(path, sizeof(path), FWTS_ESRT_ENTRY_PATH "/%s/fw_version", entry->d_name);
+			if ((str = fwts_get(path)) == NULL) {
+				fwts_failed(fw, LOG_LEVEL_MEDIUM, "CannotGetFwVersion",
+						"Missing or failed to get FwVersion on %s.", entry->d_name);
+				*passed = false;
+				fwversions_found = false;
+			} else {
+				fwversion = strtoul(str, NULL, 10);
+				free(str);
+			}
+
+			snprintf(path, sizeof(path), FWTS_ESRT_ENTRY_PATH "/%s/lowest_supported_fw_version", entry->d_name);
+			if ((str = fwts_get(path)) == NULL) {
+				fwts_failed(fw, LOG_LEVEL_MEDIUM, "CannotGetLowestSupportedFwVersion",
+						"Missing or failed to get LowestSupportedFwVersion on %s.", entry->d_name);
+				*passed = false;
+				fwversions_found = false;
+			} else {
+				lowest_sp_fwversion = strtoul(str, NULL, 10);
+				free(str);
+			}
+
+			if (fwversions_found)
+				if (fwversion < lowest_sp_fwversion) {
+					fwts_failed(fw, LOG_LEVEL_MEDIUM, "InvalidValue",
+						"The FwVersion is %" PRIu32
+						", the LowestSupportedFwVersion is %" PRIu32
+						", FwVersion shouldn't lower than the "
+						"LowestSupportedFwVersion on %s."
+						, fwversion, lowest_sp_fwversion, entry->d_name);
+					*passed = false;
+			}
+
+			snprintf(path, sizeof(path), FWTS_ESRT_ENTRY_PATH "/%s/capsule_flags", entry->d_name);
+			if ((str = fwts_get(path)) == NULL) {
+				fwts_failed(fw, LOG_LEVEL_MEDIUM, "CannotGetCapsuleFlags",
+						"Missing or failed to get CapsuleFlags on %s.", entry->d_name);
+				*passed = false;
+			} else
+				free(str);
+
+			snprintf(path, sizeof(path), FWTS_ESRT_ENTRY_PATH "/%s/last_attempt_version", entry->d_name);
+			if ((str = fwts_get(path)) == NULL) {
+				fwts_failed(fw, LOG_LEVEL_MEDIUM, "CannotGetLastAttemptVersion",
+						"Missing or failed to get LastAttemptVersion on %s.", entry->d_name);
+				*passed = false;
+			} else
+				free(str);
+
+			snprintf(path, sizeof(path), FWTS_ESRT_ENTRY_PATH "/%s/last_attempt_status", entry->d_name);
+			if ((str = fwts_get(path)) == NULL) {
+				fwts_failed(fw, LOG_LEVEL_MEDIUM, "CannotGetLastAttemptStatus",
+						"Missing or failed to get LastAttemptStatus on %s.", entry->d_name);
+				*passed = false;
+			} else {
+				uint32_t lastattemptst = strtoul(str, NULL, 10);
+
+				if (lastattemptst > LAST_ATTEMPT_STATUS_ERR_PWR_EVT_BATT) {
+					fwts_failed(fw, LOG_LEVEL_MEDIUM, "InvalidValue",
+						"The LastAttemptStatus value on %s is %" PRIu32
+						", which is undefined on UEFI Spec."
+						, entry->d_name, lastattemptst);
+					*passed = false;
+				}
+			}
+		}
+	} while (entry);
+
+	if (!entry_found) {
+		fwts_failed(fw, LOG_LEVEL_MEDIUM,  "CannotFindEntries",
+				"Cannot find any entries on directory %s", FWTS_ESRT_ENTRY_PATH);
+		*passed = false;
+	}
+
+	closedir(dir);
+
+	return;
+
+}
+
+static int esrt_test1(fwts_framework *fw)
+{
+	char *str;
+	uint32_t count = 0;
+	uint32_t countmax = 0;
+	bool passed = true;
+
+	if ((str = fwts_get(FWTS_ESRT_RES_COUNT_PATH)) == NULL) {
+		fwts_failed(fw, LOG_LEVEL_MEDIUM, "CannotGetCount", "Failed to get FwResourceCount.");
+		passed = false;
+	} else {
+		count = strtoul(str, NULL, 10);
+		if (count == 0) {
+			fwts_failed(fw, LOG_LEVEL_MEDIUM, "InvalidValue",
+				"The FwResourceCount value should not be 0.");
+			passed = false;
+		}
+		free(str);
+	}
+
+	if ((str = fwts_get(FWTS_ESRT_RES_COUNT_MAX_PATH)) == NULL) {
+		fwts_failed(fw, LOG_LEVEL_MEDIUM, "CannotGetCountMax", "Failed to get FwResourceCount.");
+		passed = false;
+	} else {
+		countmax = strtoul(str, NULL, 10);
+		if (countmax == 0)
+			fwts_failed(fw, LOG_LEVEL_MEDIUM, "InvalidValue",
+				"The FwResourceCountMax value should not be 0.");
+		free(str);
+	}
+
+	if (count > countmax) {
+		fwts_failed(fw, LOG_LEVEL_MEDIUM, "InvalidValue",
+			"The FwResourceCount shouldn't be larger than FwResourceCountMax.");
+		passed = false;
+	}
+
+	if ((str = fwts_get(FWTS_ESRT_RES_VERSION_PATH)) == NULL) {
+		fwts_failed(fw, LOG_LEVEL_MEDIUM, "CannotGetVersion", "Failed to get FwResourceVersion.");
+		passed = false;
+	} else {
+		uint64_t version = strtoull(str, NULL, 10);
+
+		if (version != ESRT_FIRMWARE_RESOURCE_VERSION) {
+			fwts_failed(fw, LOG_LEVEL_MEDIUM, "InvalidVersion",
+				"The FwResourceVersion is %" PRIu64
+				", should be the same as current entries version 1."
+				, version);
+			passed = false;
+		}
+		free(str);
+	}
+
+	check_entries(fw, &passed);
+	if (passed)
+		fwts_passed(fw, "No issues found in ESRT table.");
+	return FWTS_OK;
+
+}
+
+static fwts_framework_minor_test esrt_tests[] = {
+	{ esrt_test1, "Sanity check UEFI ESRT Table." },
+	{ NULL, NULL }
+};
+
+static fwts_framework_ops esrt_ops = {
+	.description = "Sanity check UEFI ESRT Table.",
+	.init        = esrt_init,
+	.minor_tests = esrt_tests
+};
+
+FWTS_REGISTER("esrt", &esrt_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_TEST_UEFI | FWTS_FLAG_ROOT_PRIV)
-- 
1.9.1




More information about the fwts-devel mailing list