[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