From 769cbbf8af86e527e6439dac67a3f5ef4925e7c8 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Sat, 8 May 2021 15:51:19 +0100 Subject: [PATCH] Add support for the PHAT table On Alterlake and newer hardware the Platform Health Assessment Record data can be used by the IHV to debug why a specific capsule update failed. Any custom firmware loaded by the OEM can be identified and used to further debug the root cause. --- contrib/ci/oss-fuzz.py | 1 + contrib/fwupd.spec.in | 1 + data/installed-tests/fwupd.sh | 1 + libfwupd/fwupd-common.c | 6 +- plugins/acpi-phat/README.md | 23 ++ .../acpi-phat/fu-acpi-phat-health-record.c | 205 +++++++++++ .../acpi-phat/fu-acpi-phat-health-record.h | 14 + .../acpi-phat/fu-acpi-phat-version-element.c | 180 ++++++++++ .../acpi-phat/fu-acpi-phat-version-element.h | 14 + .../acpi-phat/fu-acpi-phat-version-record.c | 103 ++++++ .../acpi-phat/fu-acpi-phat-version-record.h | 14 + plugins/acpi-phat/fu-acpi-phat.c | 327 ++++++++++++++++++ plugins/acpi-phat/fu-acpi-phat.h | 19 + plugins/acpi-phat/fu-plugin-acpi-phat.c | 44 +++ plugins/acpi-phat/fu-self-test.c | 53 +++ plugins/acpi-phat/meson.build | 61 ++++ plugins/meson.build | 1 + plugins/uefi-capsule/fu-plugin-uefi-capsule.c | 1 + src/fuzzing/acpi-phat.builder.xml | 35 ++ src/fuzzing/firmware/acpi-phat.bin | Bin 0 -> 200 bytes src/fuzzing/generate.py | 2 + 21 files changed, 1102 insertions(+), 3 deletions(-) create mode 100644 plugins/acpi-phat/README.md create mode 100644 plugins/acpi-phat/fu-acpi-phat-health-record.c create mode 100644 plugins/acpi-phat/fu-acpi-phat-health-record.h create mode 100644 plugins/acpi-phat/fu-acpi-phat-version-element.c create mode 100644 plugins/acpi-phat/fu-acpi-phat-version-element.h create mode 100644 plugins/acpi-phat/fu-acpi-phat-version-record.c create mode 100644 plugins/acpi-phat/fu-acpi-phat-version-record.h create mode 100644 plugins/acpi-phat/fu-acpi-phat.c create mode 100644 plugins/acpi-phat/fu-acpi-phat.h create mode 100644 plugins/acpi-phat/fu-plugin-acpi-phat.c create mode 100644 plugins/acpi-phat/fu-self-test.c create mode 100644 plugins/acpi-phat/meson.build create mode 100644 src/fuzzing/acpi-phat.builder.xml create mode 100644 src/fuzzing/firmware/acpi-phat.bin diff --git a/contrib/ci/oss-fuzz.py b/contrib/ci/oss-fuzz.py index 8327119ec..5de7d16ca 100755 --- a/contrib/ci/oss-fuzz.py +++ b/contrib/ci/oss-fuzz.py @@ -295,6 +295,7 @@ def _build(bld: Builder) -> None: # plugins for fzr in [ + Fuzzer("acpi-phat", pattern="acpi-phat"), Fuzzer("bcm57xx"), Fuzzer("ccgx-dmc", srcdir="ccgx", globstr="ccgx-dmc*.bin"), Fuzzer("ccgx", globstr="ccgx*.cyacd"), diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 9a5c0d1d2..982f23b7f 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -401,6 +401,7 @@ done %dir %{_libdir}/fwupd-plugins-3 %{_libdir}/fwupd-plugins-3/libfu_plugin_acpi_dmar.so %{_libdir}/fwupd-plugins-3/libfu_plugin_acpi_facp.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_acpi_phat.so %{_libdir}/fwupd-plugins-3/libfu_plugin_altos.so %{_libdir}/fwupd-plugins-3/libfu_plugin_amt.so %{_libdir}/fwupd-plugins-3/libfu_plugin_analogix.so diff --git a/data/installed-tests/fwupd.sh b/data/installed-tests/fwupd.sh index cc82dc296..5b1f5d22b 100755 --- a/data/installed-tests/fwupd.sh +++ b/data/installed-tests/fwupd.sh @@ -13,6 +13,7 @@ run_test() run_test acpi-dmar-self-test run_test acpi-facp-self-test +run_test acpi-phat-self-test run_test ata-self-test run_test nitrokey-self-test run_test linux-swap-self-test diff --git a/libfwupd/fwupd-common.c b/libfwupd/fwupd-common.c index 32725b3b1..07a2789d4 100644 --- a/libfwupd/fwupd-common.c +++ b/libfwupd/fwupd-common.c @@ -745,7 +745,7 @@ fwupd_guid_from_string (const gchar *guidstr, g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, - "is not valid format"); + "GUID is not valid format"); return FALSE; } split = g_strsplit (guidstr, "-", 5); @@ -753,7 +753,7 @@ fwupd_guid_from_string (const gchar *guidstr, g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, - "is not valid format, no dashes"); + "GUID is not valid format, no dashes"); return FALSE; } if (strlen (split[0]) != 8 && strlen (split[1]) != 4 && @@ -762,7 +762,7 @@ fwupd_guid_from_string (const gchar *guidstr, g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, - "is not valid format, not GUID"); + "GUID is not valid format, not GUID"); return FALSE; } diff --git a/plugins/acpi-phat/README.md b/plugins/acpi-phat/README.md new file mode 100644 index 000000000..b80533d4c --- /dev/null +++ b/plugins/acpi-phat/README.md @@ -0,0 +1,23 @@ +Platform Health Assessment Table +================================ + +Introduction +------------ + +The PHAT is an ACPI table where a platform can expose health related telemetry +that may be useful for software running within the constraints of an OS. + +These elements are typically going to encompass things that are likely otherwise +not enumerable during the OS runtime phase of operations, such as version of +pre-OS components. + +The daemon includes some of the PHAT data in the report data sent to the LVFS +so that we can debug failures with the help of the IHV. This allows us to find +the root cause of the problem, and so we know what other OEMs may be affected. + +See https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#platform-health-assessment-table +for more information. + +External interface access +------------------------- +This plugin requires read access to `/sys/firmware/acpi/tables`. diff --git a/plugins/acpi-phat/fu-acpi-phat-health-record.c b/plugins/acpi-phat/fu-acpi-phat-health-record.c new file mode 100644 index 000000000..4718dbaed --- /dev/null +++ b/plugins/acpi-phat/fu-acpi-phat-health-record.c @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2021 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-firmware-common.h" + +#include "fu-acpi-phat.h" +#include "fu-acpi-phat-health-record.h" + +struct _FuAcpiPhatHealthRecord { + FuFirmware parent_instance; + guint8 am_healthy; + gchar *guid; + gchar *device_path; +}; + +G_DEFINE_TYPE (FuAcpiPhatHealthRecord, fu_acpi_phat_health_record, FU_TYPE_FIRMWARE) + +static void +fu_acpi_phat_health_record_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) +{ + FuAcpiPhatHealthRecord *self = FU_ACPI_PHAT_HEALTH_RECORD (firmware); + if (self->guid != NULL) + fu_xmlb_builder_insert_kv (bn, "guid", self->guid); + if (self->device_path != NULL) + fu_xmlb_builder_insert_kv (bn, "device_path", self->device_path); + if (self->am_healthy != 0) + fu_xmlb_builder_insert_kx (bn, "am_healthy", self->am_healthy); +} + +static gboolean +fu_acpi_phat_health_record_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + FuAcpiPhatHealthRecord *self = FU_ACPI_PHAT_HEALTH_RECORD (firmware); + gsize bufsz = 0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + fwupd_guid_t guid = { 0x0 }; + + /* am healthy */ + if (!fu_common_read_uint8_safe (buf, bufsz, 7, &self->am_healthy, error)) + return FALSE; + + /* device signature */ + if (!fu_memcpy_safe ((guint8 *) &guid, sizeof(guid), 0x0, /* dst */ + buf, bufsz, 8, /* src */ + sizeof(guid), error)) + return FALSE; + self->guid = fwupd_guid_to_string (&guid, FWUPD_GUID_FLAG_MIXED_ENDIAN); + + /* device path */ + if (bufsz > 28) { + self->device_path = g_utf16_to_utf8 ((const gunichar2 *) (buf + 28), + (bufsz - 28) / 2, + NULL, NULL, + error); + if (self->device_path == NULL) + return FALSE; + } + + /* success */ + return TRUE; +} + +static GBytes * +fu_acpi_phat_health_record_write (FuFirmware *firmware, GError **error) +{ + FuAcpiPhatHealthRecord *self = FU_ACPI_PHAT_HEALTH_RECORD (firmware); + fwupd_guid_t guid = { 0x0 }; + glong device_path_utf16sz = 0; + g_autofree gunichar2 *device_path_utf16 = NULL; + g_autoptr(GByteArray) buf = g_byte_array_new (); + + /* convert device path ahead of time to get total record length */ + if (self->device_path != NULL) { + device_path_utf16 = g_utf8_to_utf16 (self->device_path, -1, + NULL, &device_path_utf16sz, + error); + if (device_path_utf16 == NULL) + return NULL; + device_path_utf16sz *= 2; + } + + /* data record */ + fu_byte_array_append_uint16 (buf, + FU_ACPI_PHAT_RECORD_TYPE_HEALTH, + G_LITTLE_ENDIAN); + fu_byte_array_append_uint16 (buf, 28 + device_path_utf16sz, G_LITTLE_ENDIAN); + fu_byte_array_append_uint8 (buf, fu_firmware_get_version_raw (firmware)); + fu_byte_array_append_uint8 (buf, 0x00); + fu_byte_array_append_uint8 (buf, 0x00); + fu_byte_array_append_uint8 (buf, self->am_healthy); + + /* device signature */ + if (self->guid != NULL) { + if (!fwupd_guid_from_string (self->guid, &guid, + FWUPD_GUID_FLAG_MIXED_ENDIAN, + error)) + return NULL; + } + g_byte_array_append (buf, guid, sizeof(guid)); + + /* device-specific data unsupported */ + fu_byte_array_append_uint32 (buf, 0x0, G_LITTLE_ENDIAN); + + /* device path */ + if (self->device_path != NULL) { + g_byte_array_append (buf, + (const guint8 *) device_path_utf16, + device_path_utf16sz); + } + + /* success */ + return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); +} + +static void +fu_acpi_phat_health_record_set_guid (FuAcpiPhatHealthRecord *self, + const gchar *guid) +{ + g_free (self->guid); + self->guid = g_strdup (guid); +} + +static void +fu_acpi_phat_health_record_set_device_path (FuAcpiPhatHealthRecord *self, + const gchar *device_path) +{ + g_free (self->device_path); + self->device_path = g_strdup (device_path); +} + +static gboolean +fu_acpi_phat_health_record_build (FuFirmware *firmware, XbNode *n, GError **error) +{ + FuAcpiPhatHealthRecord *self = FU_ACPI_PHAT_HEALTH_RECORD (firmware); + const gchar *tmp; + guint64 tmp64; + + /* optional properties */ + tmp = xb_node_query_text (n, "device_path", NULL); + if (tmp != NULL) + fu_acpi_phat_health_record_set_device_path (self, tmp); + tmp = xb_node_query_text (n, "guid", NULL); + if (tmp != NULL) + fu_acpi_phat_health_record_set_guid (self, tmp); + tmp64 = xb_node_query_text_as_uint (n, "am_healthy", NULL); + if (tmp64 > G_MAXUINT8) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "am_healthy value invalid, got 0x%x", + (guint) tmp64); + return FALSE; + } + self->am_healthy = (guint8) tmp64; + + /* success */ + return TRUE; +} + +static void +fu_acpi_phat_health_record_init (FuAcpiPhatHealthRecord *self) +{ +} + +static void +fu_acpi_phat_health_record_finalize (GObject *object) +{ + FuAcpiPhatHealthRecord *self = FU_ACPI_PHAT_HEALTH_RECORD (object); + g_free (self->guid); + g_free (self->device_path); + G_OBJECT_CLASS (fu_acpi_phat_health_record_parent_class)->finalize (object); +} + +static void +fu_acpi_phat_health_record_class_init (FuAcpiPhatHealthRecordClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + object_class->finalize = fu_acpi_phat_health_record_finalize; + klass_firmware->parse = fu_acpi_phat_health_record_parse; + klass_firmware->write = fu_acpi_phat_health_record_write; + klass_firmware->export = fu_acpi_phat_health_record_export; + klass_firmware->build = fu_acpi_phat_health_record_build; +} + +FuFirmware * +fu_acpi_phat_health_record_new (void) +{ + return FU_FIRMWARE (g_object_new (FU_TYPE_ACPI_PHAT_HEALTH_RECORD, NULL)); +} diff --git a/plugins/acpi-phat/fu-acpi-phat-health-record.h b/plugins/acpi-phat/fu-acpi-phat-health-record.h new file mode 100644 index 000000000..ad74a8520 --- /dev/null +++ b/plugins/acpi-phat/fu-acpi-phat-health-record.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2021 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware.h" + +#define FU_TYPE_ACPI_PHAT_HEALTH_RECORD (fu_acpi_phat_health_record_get_type ()) +G_DECLARE_FINAL_TYPE (FuAcpiPhatHealthRecord, fu_acpi_phat_health_record, FU, ACPI_PHAT_HEALTH_RECORD, FuFirmware) + +FuFirmware *fu_acpi_phat_health_record_new (void); diff --git a/plugins/acpi-phat/fu-acpi-phat-version-element.c b/plugins/acpi-phat/fu-acpi-phat-version-element.c new file mode 100644 index 000000000..1098f7dec --- /dev/null +++ b/plugins/acpi-phat/fu-acpi-phat-version-element.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2021 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-firmware-common.h" +#include "fu-acpi-phat-version-element.h" + +struct _FuAcpiPhatVersionElement { + FuFirmware parent_instance; + gchar *guid; + gchar *producer_id; +}; + +G_DEFINE_TYPE (FuAcpiPhatVersionElement, fu_acpi_phat_version_element, FU_TYPE_FIRMWARE) + +static void +fu_acpi_phat_version_element_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) +{ + FuAcpiPhatVersionElement *self = FU_ACPI_PHAT_VERSION_ELEMENT (firmware); + if (self->guid != NULL) + fu_xmlb_builder_insert_kv (bn, "guid", self->guid); + if (self->producer_id != NULL) + fu_xmlb_builder_insert_kv (bn, "producer_id", self->producer_id); +} + +static gboolean +fu_acpi_phat_version_element_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + FuAcpiPhatVersionElement *self = FU_ACPI_PHAT_VERSION_ELEMENT (firmware); + fwupd_guid_t component_id = { 0x0 }; + gchar producer_id[4] = { '\0' }; + gsize bufsz = 0; + guint64 version_value = 0; + g_autofree gchar *guid_str = NULL; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + + /* hardcoded */ + fu_firmware_set_size (firmware, 28); + + if (!fu_memcpy_safe ((guint8 *) &component_id, sizeof(component_id), 0x0, /* dst */ + buf, bufsz, 0, /* src */ + sizeof(component_id), error)) + return FALSE; + self->guid = fwupd_guid_to_string (&component_id, FWUPD_GUID_FLAG_MIXED_ENDIAN); + + if (!fu_common_read_uint64_safe (buf, bufsz, 16, &version_value, + G_LITTLE_ENDIAN, error)) + return FALSE; + fu_firmware_set_version_raw (firmware, version_value); + if (!fu_memcpy_safe ((guint8 *) producer_id, sizeof(producer_id), 0x0, /* dst */ + buf, bufsz, 24, /* src */ + sizeof(producer_id), error)) + return FALSE; + if (memcmp (producer_id, "\0\0\0\0", 4) == 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "PHAT version element invalid"); + return FALSE; + } + self->producer_id = fu_common_strsafe ((const gchar *) producer_id, + sizeof(producer_id)); + return TRUE; +} + +static GBytes * +fu_acpi_phat_version_element_write (FuFirmware *firmware, GError **error) +{ + FuAcpiPhatVersionElement *self = FU_ACPI_PHAT_VERSION_ELEMENT (firmware); + fwupd_guid_t guid = { 0x0 }; + guint8 producer_id[4] = { '\0' }; + g_autoptr(GByteArray) buf = g_byte_array_new (); + + /* component ID */ + if (self->guid != NULL) { + if (!fwupd_guid_from_string (self->guid, &guid, + FWUPD_GUID_FLAG_MIXED_ENDIAN, + error)) + return NULL; + } + g_byte_array_append (buf, guid, sizeof(guid)); + + /* version value */ + fu_byte_array_append_uint64 (buf, + fu_firmware_get_version_raw (firmware), + G_LITTLE_ENDIAN); + + /* producer ID */ + if (self->producer_id != NULL) { + gsize producer_idsz = strlen (self->producer_id); + if (!fu_memcpy_safe (producer_id, sizeof(producer_id), 0x0, /* dst */ + (const guint8 *) self->producer_id, producer_idsz, 0x0, /* src */ + producer_idsz, error)) + return NULL; + } + g_byte_array_append (buf, producer_id, sizeof(producer_id)); + + /* success */ + return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); +} + +static void +fu_acpi_phat_version_element_set_guid (FuAcpiPhatVersionElement *self, + const gchar *guid) +{ + g_free (self->guid); + self->guid = g_strdup (guid); +} + +static void +fu_acpi_phat_version_element_set_producer_id (FuAcpiPhatVersionElement *self, + const gchar *producer_id) +{ + g_free (self->producer_id); + self->producer_id = g_strdup (producer_id); +} + +static gboolean +fu_acpi_phat_version_element_build (FuFirmware *firmware, XbNode *n, GError **error) +{ + FuAcpiPhatVersionElement *self = FU_ACPI_PHAT_VERSION_ELEMENT (firmware); + const gchar *tmp; + + /* optional properties */ + tmp = xb_node_query_text (n, "producer_id", NULL); + if (tmp != NULL) + fu_acpi_phat_version_element_set_producer_id (self, tmp); + tmp = xb_node_query_text (n, "guid", NULL); + if (tmp != NULL) + fu_acpi_phat_version_element_set_guid (self, tmp); + + /* success */ + return TRUE; +} + +static void +fu_acpi_phat_version_element_init (FuAcpiPhatVersionElement *self) +{ +} + +static void +fu_acpi_phat_version_element_finalize (GObject *object) +{ + FuAcpiPhatVersionElement *self = FU_ACPI_PHAT_VERSION_ELEMENT (object); + g_free (self->guid); + g_free (self->producer_id); + G_OBJECT_CLASS (fu_acpi_phat_version_element_parent_class)->finalize (object); +} + +static void +fu_acpi_phat_version_element_class_init (FuAcpiPhatVersionElementClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + object_class->finalize = fu_acpi_phat_version_element_finalize; + klass_firmware->parse = fu_acpi_phat_version_element_parse; + klass_firmware->write = fu_acpi_phat_version_element_write; + klass_firmware->export = fu_acpi_phat_version_element_export; + klass_firmware->build = fu_acpi_phat_version_element_build; +} + +FuFirmware * +fu_acpi_phat_version_element_new (void) +{ + return FU_FIRMWARE (g_object_new (FU_TYPE_ACPI_PHAT_VERSION_ELEMENT, NULL)); +} diff --git a/plugins/acpi-phat/fu-acpi-phat-version-element.h b/plugins/acpi-phat/fu-acpi-phat-version-element.h new file mode 100644 index 000000000..3ca5dd36e --- /dev/null +++ b/plugins/acpi-phat/fu-acpi-phat-version-element.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2021 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware.h" + +#define FU_TYPE_ACPI_PHAT_VERSION_ELEMENT (fu_acpi_phat_version_element_get_type ()) +G_DECLARE_FINAL_TYPE (FuAcpiPhatVersionElement, fu_acpi_phat_version_element, FU, ACPI_PHAT_VERSION_ELEMENT, FuFirmware) + +FuFirmware *fu_acpi_phat_version_element_new (void); diff --git a/plugins/acpi-phat/fu-acpi-phat-version-record.c b/plugins/acpi-phat/fu-acpi-phat-version-record.c new file mode 100644 index 000000000..98d4009ad --- /dev/null +++ b/plugins/acpi-phat/fu-acpi-phat-version-record.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2021 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-firmware-common.h" +#include "fu-acpi-phat.h" +#include "fu-acpi-phat-version-element.h" +#include "fu-acpi-phat-version-record.h" + +struct _FuAcpiPhatVersionRecord { + FuFirmware parent_instance; +}; + +G_DEFINE_TYPE (FuAcpiPhatVersionRecord, fu_acpi_phat_version_record, FU_TYPE_FIRMWARE) + +static gboolean +fu_acpi_phat_version_record_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + gsize bufsz = 0; + gsize offset = 0; + guint32 record_count = 0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + + if (!fu_common_read_uint32_safe (buf, bufsz, offset + 8, &record_count, + G_LITTLE_ENDIAN, error)) + return FALSE; + for (guint32 i = 0; i < record_count; i++) { + g_autoptr(FuFirmware) firmware_tmp = fu_acpi_phat_version_element_new (); + g_autoptr(GBytes) fw_tmp = NULL; + fw_tmp = fu_common_bytes_new_offset (fw, offset + 12, 28, error); + if (fw_tmp == NULL) + return FALSE; + fu_firmware_set_offset (firmware_tmp, offset + 12); + if (!fu_firmware_parse (firmware_tmp, fw_tmp, flags, error)) + return FALSE; + fu_firmware_add_image (firmware, firmware_tmp); + offset += fu_firmware_get_size (firmware_tmp); + } + return TRUE; +} + +static GBytes * +fu_acpi_phat_version_record_write (FuFirmware *firmware, GError **error) +{ + g_autoptr(GByteArray) buf = g_byte_array_new (); + g_autoptr(GByteArray) buf2 = g_byte_array_new (); + g_autoptr(GPtrArray) images = fu_firmware_get_images (firmware); + + /* write each element so we get the image size */ + for (guint i = 0; i < images->len; i++) { + FuFirmware *img = g_ptr_array_index (images, i); + g_autoptr(GBytes) blob = fu_firmware_write (img, error); + if (blob == NULL) + return NULL; + fu_byte_array_append_bytes (buf2, blob); + } + + /* data record */ + fu_byte_array_append_uint16 (buf, + FU_ACPI_PHAT_RECORD_TYPE_VERSION, + G_LITTLE_ENDIAN); + fu_byte_array_append_uint16 (buf, 12 + buf2->len, G_LITTLE_ENDIAN); + fu_byte_array_append_uint8 (buf, fu_firmware_get_version_raw (firmware)); + fu_byte_array_append_uint8 (buf, 0x00); + fu_byte_array_append_uint8 (buf, 0x00); + fu_byte_array_append_uint8 (buf, 0x00); + fu_byte_array_append_uint32 (buf, images->len, G_LITTLE_ENDIAN); + + /* element data */ + g_byte_array_append (buf, buf2->data, buf2->len); + return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); +} + +static void +fu_acpi_phat_version_record_init (FuAcpiPhatVersionRecord *self) +{ +} + +static void +fu_acpi_phat_version_record_class_init (FuAcpiPhatVersionRecordClass *klass) +{ + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + klass_firmware->parse = fu_acpi_phat_version_record_parse; + klass_firmware->write = fu_acpi_phat_version_record_write; +} + +FuFirmware * +fu_acpi_phat_version_record_new (void) +{ + return FU_FIRMWARE (g_object_new (FU_TYPE_ACPI_PHAT_VERSION_RECORD, NULL)); +} diff --git a/plugins/acpi-phat/fu-acpi-phat-version-record.h b/plugins/acpi-phat/fu-acpi-phat-version-record.h new file mode 100644 index 000000000..8f5be971e --- /dev/null +++ b/plugins/acpi-phat/fu-acpi-phat-version-record.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2021 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware.h" + +#define FU_TYPE_ACPI_PHAT_VERSION_RECORD (fu_acpi_phat_version_record_get_type ()) +G_DECLARE_FINAL_TYPE (FuAcpiPhatVersionRecord, fu_acpi_phat_version_record, FU, ACPI_PHAT_VERSION_RECORD, FuFirmware) + +FuFirmware *fu_acpi_phat_version_record_new (void); diff --git a/plugins/acpi-phat/fu-acpi-phat.c b/plugins/acpi-phat/fu-acpi-phat.c new file mode 100644 index 000000000..a82a7f3ca --- /dev/null +++ b/plugins/acpi-phat/fu-acpi-phat.c @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2021 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-firmware-common.h" +#include "fu-acpi-phat.h" +#include "fu-acpi-phat-health-record.h" +#include "fu-acpi-phat-version-record.h" + +struct _FuAcpiPhat { + FuFirmware parent_instance; + gchar *oem_id; +}; + +G_DEFINE_TYPE (FuAcpiPhat, fu_acpi_phat, FU_TYPE_FIRMWARE) + +static void +fu_acpi_phat_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) +{ + FuAcpiPhat *self = FU_ACPI_PHAT (firmware); + if (self->oem_id != NULL) + fu_xmlb_builder_insert_kv (bn, "oem_id", self->oem_id); +} + +static gboolean +fu_acpi_phat_record_parse (FuFirmware *firmware, + GBytes *fw, + gsize *offset, + FwupdInstallFlags flags, + GError **error) +{ + gsize bufsz = 0; + guint16 record_length = 0; + guint16 record_type = 0; + guint8 revision; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + g_autoptr(FuFirmware) firmware_rcd = NULL; + + /* common header */ + if (!fu_common_read_uint16_safe (buf, bufsz, *offset, &record_type, + G_LITTLE_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint16_safe (buf, bufsz, *offset + 2, &record_length, + G_LITTLE_ENDIAN, error)) + return FALSE; + if (record_length < 5) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "PHAT record length invalid, got 0x%x", + record_length); + return FALSE; + } + if (!fu_common_read_uint8_safe (buf, bufsz, *offset + 4, &revision, error)) + return FALSE; + + /* firmware version data record */ + if (record_type == FU_ACPI_PHAT_RECORD_TYPE_VERSION) { + firmware_rcd = fu_acpi_phat_version_record_new (); + } else if (record_type == FU_ACPI_PHAT_RECORD_TYPE_HEALTH) { + firmware_rcd = fu_acpi_phat_health_record_new (); + } + + /* supported record type */ + if (firmware_rcd != NULL) { + g_autoptr(GBytes) fw_tmp = NULL; + fw_tmp = fu_common_bytes_new_offset (fw, *offset, record_length, error); + if (fw_tmp == NULL) + return FALSE; + fu_firmware_set_size (firmware_rcd, record_length); + fu_firmware_set_offset (firmware_rcd, *offset); + fu_firmware_set_version_raw (firmware_rcd, revision); + if (!fu_firmware_parse (firmware_rcd, fw_tmp, flags, error)) + return FALSE; + fu_firmware_add_image (firmware, firmware_rcd); + } + + *offset += record_length; + return TRUE; +} + +static void +fu_acpi_phat_set_oem_id (FuAcpiPhat *self, const gchar *oem_id) +{ + g_free (self->oem_id); + self->oem_id = g_strdup (oem_id); +} + +static gboolean +fu_acpi_phat_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + FuAcpiPhat *self = FU_ACPI_PHAT (firmware); + gchar oem_id[6] = { '\0' }; + gchar oem_table_id[8] = { '\0' }; + gchar signature[4] = { '\0' }; + gsize bufsz = 0; + guint32 length = 0; + guint32 oem_revision = 0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + g_autofree gchar *oem_id_safe = NULL; + g_autofree gchar *oem_table_id_safe = NULL; + + /* parse table */ + if (!fu_memcpy_safe ((guint8 *) signature, sizeof(signature), 0x0, /* dst */ + buf, bufsz, 0x00, /* src */ + sizeof(signature), error)) + return FALSE; + if (memcmp (signature, "PHAT", 4) != 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "Not a PHAT table, got %s", + signature); + return FALSE; + } + if (!fu_common_read_uint32_safe (buf, bufsz, 4, &length, G_LITTLE_ENDIAN, error)) + return FALSE; + if (bufsz < length) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "PHAT table invalid size, got 0x%x, expected 0x%x", + (guint) bufsz, length); + return FALSE; + } + + /* spec revision */ + if ((flags & FWUPD_INSTALL_FLAG_FORCE) == 0) { + guint8 revision = 0; + if (!fu_common_read_uint8_safe (buf, bufsz, 8, &revision, error)) + return FALSE; + if (revision != FU_ACPI_PHAT_REVISION) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "PHAT table revision invalid, got 0x%x, expected 0x%x", + revision, (guint) FU_ACPI_PHAT_REVISION); + return FALSE; + } + } + + /* verify checksum */ + if ((flags & FWUPD_INSTALL_FLAG_IGNORE_CHECKSUM) == 0) { + guint8 checksum = 0; + for (gsize i = 0; i < length; i++) + checksum += buf[i]; + if (checksum != 0x00) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "PHAT table checksum invalid, got 0x%x", + checksum); + return FALSE; + } + } + + /* OEMID */ + if (!fu_memcpy_safe ((guint8 *) oem_id, sizeof(oem_id), 0x0, /* dst */ + buf, bufsz, 10, /* src */ + sizeof(oem_id), error)) + return FALSE; + oem_id_safe = fu_common_strsafe ((const gchar *) oem_id, sizeof(oem_id)); + fu_acpi_phat_set_oem_id (self, oem_id_safe); + + /* OEM Table ID */ + if (!fu_memcpy_safe ((guint8 *) oem_table_id, sizeof(oem_table_id), 0x0, /* dst */ + buf, bufsz, 16, /* src */ + sizeof(oem_table_id), error)) + return FALSE; + oem_table_id_safe = fu_common_strsafe ((const gchar *) oem_table_id, sizeof(oem_table_id)); + fu_firmware_set_id (firmware, oem_table_id_safe); + if (!fu_common_read_uint32_safe (buf, bufsz, 24, &oem_revision, G_LITTLE_ENDIAN, error)) + return FALSE; + fu_firmware_set_version_raw (firmware, oem_revision); + + /* platform telemetry records */ + for (gsize offset = 36; offset < length;) { + if (!fu_acpi_phat_record_parse (firmware, fw, &offset, flags, error)) + return FALSE; + } + + /* success */ + return TRUE; +} + +static GBytes * +fu_acpi_phat_write (FuFirmware *firmware, GError **error) +{ + FuAcpiPhat *self = FU_ACPI_PHAT (firmware); + const gchar *oem_table_id_str = fu_firmware_get_id (firmware); + guint8 checksum = 0; + guint8 creator_id[] = { 'F', 'W', 'U', 'P' }; + guint8 creator_rev[] = { '0', '0', '0', '0' }; + guint8 oem_id[6] = { '\0' }; + guint8 oem_table_id[8] = { '\0' }; + guint8 signature[] = { 'P', 'H', 'A', 'T' }; + g_autoptr(GByteArray) buf = g_byte_array_new (); + g_autoptr(GByteArray) buf2 = g_byte_array_new (); + g_autoptr(GPtrArray) images = fu_firmware_get_images (firmware); + + /* write each image so we get the total size */ + for (guint i = 0; i < images->len; i++) { + FuFirmware *img = g_ptr_array_index (images, i); + g_autoptr(GBytes) blob = fu_firmware_write (img, error); + if (blob == NULL) + return NULL; + fu_byte_array_append_bytes (buf2, blob); + } + + /* header */ + g_byte_array_append (buf, signature, sizeof(signature)); + fu_byte_array_append_uint32 (buf, buf2->len + 36, G_LITTLE_ENDIAN); + fu_byte_array_append_uint8 (buf, fu_firmware_get_version_raw (firmware)); + fu_byte_array_append_uint8 (buf, 0xFF); /* will fixup */ + if (self->oem_id != NULL) { + gsize oem_id_strlen = strlen (self->oem_id); + if (!fu_memcpy_safe (oem_id, sizeof(oem_id), 0x0, /* dst */ + (const guint8 *) self->oem_id, oem_id_strlen, 0x0, /* src */ + oem_id_strlen, error)) + return NULL; + } + g_byte_array_append (buf, oem_id, sizeof(oem_id)); + if (oem_table_id_str != NULL) { + gsize oem_table_id_strlen = strlen (oem_table_id_str); + if (!fu_memcpy_safe (oem_table_id, sizeof(oem_table_id), 0x0, /* dst */ + (const guint8 *) oem_table_id_str, oem_table_id_strlen, 0x0, /* src */ + oem_table_id_strlen, error)) + return NULL; + } + g_byte_array_append (buf, oem_table_id, sizeof(oem_table_id)); + fu_byte_array_append_uint32 (buf, fu_firmware_get_version_raw (firmware), G_LITTLE_ENDIAN); + g_byte_array_append (buf, creator_id, sizeof(creator_id)); + g_byte_array_append (buf, creator_rev, sizeof(creator_rev)); + g_byte_array_append (buf, buf2->data, buf2->len); + + /* fixup checksum */ + for (gsize i = 0; i < buf->len; i++) + checksum += buf->data[i]; + buf->data[9] = 0xFF - checksum; + + /* success */ + return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); +} + +static gboolean +fu_acpi_phat_build (FuFirmware *firmware, XbNode *n, GError **error) +{ + FuAcpiPhat *self = FU_ACPI_PHAT (firmware); + const gchar *tmp; + + /* optional properties */ + tmp = xb_node_query_text (n, "oem_id", NULL); + if (tmp != NULL) + fu_acpi_phat_set_oem_id (self, tmp); + + /* success */ + return TRUE; +} + +static gboolean +fu_acpi_phat_to_report_string_cb (XbBuilderNode *bn, gpointer user_data) +{ + if (g_strcmp0 (xb_builder_node_get_element (bn), "offset") == 0 || + g_strcmp0 (xb_builder_node_get_element (bn), "flags") == 0 || + g_strcmp0 (xb_builder_node_get_element (bn), "size") == 0) + xb_builder_node_add_flag (bn, XB_BUILDER_NODE_FLAG_IGNORE); + return FALSE; +} + +gchar * +fu_acpi_phat_to_report_string (FuAcpiPhat *self) +{ + g_autoptr(XbBuilderNode) bn = xb_builder_node_new ("firmware"); + fu_firmware_export (FU_FIRMWARE (self), FU_FIRMWARE_EXPORT_FLAG_NONE, bn); + xb_builder_node_traverse (bn, G_PRE_ORDER, G_TRAVERSE_ALL, 3, + fu_acpi_phat_to_report_string_cb, NULL); + return xb_builder_node_export (bn, + XB_NODE_EXPORT_FLAG_FORMAT_MULTILINE | + XB_NODE_EXPORT_FLAG_FORMAT_INDENT, + NULL); +} + +static void +fu_acpi_phat_init (FuAcpiPhat *self) +{ + fu_firmware_add_flag (FU_FIRMWARE (self), FU_FIRMWARE_FLAG_HAS_CHECKSUM); +} + +static void +fu_acpi_phat_finalize (GObject *object) +{ + FuAcpiPhat *self = FU_ACPI_PHAT (object); + g_free (self->oem_id); + G_OBJECT_CLASS (fu_acpi_phat_parent_class)->finalize (object); +} + +static void +fu_acpi_phat_class_init (FuAcpiPhatClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + object_class->finalize = fu_acpi_phat_finalize; + klass_firmware->parse = fu_acpi_phat_parse; + klass_firmware->write = fu_acpi_phat_write; + klass_firmware->export = fu_acpi_phat_export; + klass_firmware->build = fu_acpi_phat_build; +} + +FuFirmware * +fu_acpi_phat_new (void) +{ + return FU_FIRMWARE (g_object_new (FU_TYPE_ACPI_PHAT, NULL)); +} diff --git a/plugins/acpi-phat/fu-acpi-phat.h b/plugins/acpi-phat/fu-acpi-phat.h new file mode 100644 index 000000000..f9d02568d --- /dev/null +++ b/plugins/acpi-phat/fu-acpi-phat.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2021 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include "fu-firmware.h" + +#define FU_TYPE_ACPI_PHAT (fu_acpi_phat_get_type ()) +G_DECLARE_FINAL_TYPE (FuAcpiPhat, fu_acpi_phat, FU, ACPI_PHAT, FuFirmware) + +#define FU_ACPI_PHAT_RECORD_TYPE_VERSION 0x0000 +#define FU_ACPI_PHAT_RECORD_TYPE_HEALTH 0x0001 +#define FU_ACPI_PHAT_REVISION 0x01 + +FuFirmware *fu_acpi_phat_new (void); +gchar *fu_acpi_phat_to_report_string (FuAcpiPhat *self); diff --git a/plugins/acpi-phat/fu-plugin-acpi-phat.c b/plugins/acpi-phat/fu-plugin-acpi-phat.c new file mode 100644 index 000000000..c96bfd692 --- /dev/null +++ b/plugins/acpi-phat/fu-plugin-acpi-phat.c @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-acpi-phat.h" +#include "fu-acpi-phat-health-record.h" +#include "fu-acpi-phat-version-element.h" +#include "fu-acpi-phat-version-record.h" +#include "fu-plugin-vfuncs.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_ACPI_PHAT); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_ACPI_PHAT_HEALTH_RECORD); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_ACPI_PHAT_VERSION_ELEMENT); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_ACPI_PHAT_VERSION_RECORD); +} + +gboolean +fu_plugin_coldplug (FuPlugin *plugin, GError **error) +{ + g_autofree gchar *path = NULL; + g_autofree gchar *fn = NULL; + g_autofree gchar *str = NULL; + g_autoptr(FuFirmware) phat = fu_acpi_phat_new (); + g_autoptr(GBytes) blob = NULL; + + path = fu_common_get_path (FU_PATH_KIND_ACPI_TABLES); + fn = g_build_filename (path, "PHAT", NULL); + blob = fu_common_get_contents_bytes (fn, error); + if (blob == NULL) + return FALSE; + if (!fu_firmware_parse (phat, blob, FWUPD_INSTALL_FLAG_NONE, error)) + return FALSE; + str = fu_acpi_phat_to_report_string (FU_ACPI_PHAT (phat)); + fu_plugin_add_report_metadata (plugin, "PHAT", str); + return TRUE; +} diff --git a/plugins/acpi-phat/fu-self-test.c b/plugins/acpi-phat/fu-self-test.c new file mode 100644 index 000000000..9feef60a1 --- /dev/null +++ b/plugins/acpi-phat/fu-self-test.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" + +#include "fu-acpi-phat.h" + +static void +fu_acpi_phat_parse_func (void) +{ + gboolean ret; + g_autoptr(FuFirmware) phat = fu_acpi_phat_new (); + g_autoptr(GError) error = NULL; + g_autoptr(GBytes) blob = NULL; + g_autofree gchar *str = NULL; + g_autofree gchar *fn = NULL; + + fn = g_test_build_filename (G_TEST_DIST, "tests", "PHAT", NULL); + if (!g_file_test (fn, G_FILE_TEST_EXISTS)) { + g_test_skip ("missing PHAT"); + return; + } + blob = fu_common_get_contents_bytes (fn, &error); + g_assert_no_error (error); + g_assert_nonnull (blob); + ret = fu_firmware_parse (phat, blob, FWUPD_INSTALL_FLAG_FORCE, &error); + g_assert_no_error (error); + g_assert_true (ret); + str = fu_acpi_phat_to_report_string (FU_ACPI_PHAT (phat)); + g_print ("%s\n", str); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); + + /* tests go here */ + g_test_add_func ("/acpi-phat/parse", fu_acpi_phat_parse_func); + + return g_test_run (); +} diff --git a/plugins/acpi-phat/meson.build b/plugins/acpi-phat/meson.build new file mode 100644 index 000000000..82772fb09 --- /dev/null +++ b/plugins/acpi-phat/meson.build @@ -0,0 +1,61 @@ +if host_machine.system() == 'linux' +cargs = ['-DG_LOG_DOMAIN="FuPluginAcpiPhat"'] + +shared_module('fu_plugin_acpi_phat', + fu_hash, + sources : [ + 'fu-plugin-acpi-phat.c', + 'fu-acpi-phat.c', # fuzzing + 'fu-acpi-phat-health-record.c', # fuzzing + 'fu-acpi-phat-version-element.c', # fuzzing + 'fu-acpi-phat-version-record.c', # fuzzing + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) + +if get_option('tests') + testdatadirs = environment() + testdatadirs.set('G_TEST_SRCDIR', meson.current_source_dir()) + testdatadirs.set('G_TEST_BUILDDIR', meson.current_build_dir()) + e = executable( + 'acpi-phat-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-acpi-phat.c', + 'fu-acpi-phat-health-record.c', + 'fu-acpi-phat-version-element.c', + 'fu-acpi-phat-version-record.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + fwupd, + fwupdplugin, + ], + install : true, + install_dir : installed_test_bindir, + ) + test('acpi-phat-self-test', e, env : testdatadirs) # added to installed-tests +endif +endif diff --git a/plugins/meson.build b/plugins/meson.build index 4d9b978bf..470cf8683 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -1,5 +1,6 @@ subdir('acpi-dmar') subdir('acpi-facp') +subdir('acpi-phat') subdir('altos') subdir('amt') subdir('analogix') diff --git a/plugins/uefi-capsule/fu-plugin-uefi-capsule.c b/plugins/uefi-capsule/fu-plugin-uefi-capsule.c index 851a90b03..cbc0ebbc2 100644 --- a/plugins/uefi-capsule/fu-plugin-uefi-capsule.c +++ b/plugins/uefi-capsule/fu-plugin-uefi-capsule.c @@ -43,6 +43,7 @@ fu_plugin_init (FuPlugin *plugin) fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_METADATA_SOURCE, "tpm_eventlog"); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_METADATA_SOURCE, "dell"); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_METADATA_SOURCE, "linux_lockdown"); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_METADATA_SOURCE, "acpi_phat"); fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_CONFLICTS, "uefi"); /* old name */ fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); } diff --git a/src/fuzzing/acpi-phat.builder.xml b/src/fuzzing/acpi-phat.builder.xml new file mode 100644 index 000000000..945ccccfc --- /dev/null +++ b/src/fuzzing/acpi-phat.builder.xml @@ -0,0 +1,35 @@ + + SUDODAVE + 0x1 + HUGHES + + 0x1 + + 0x123 + 40338ceb-b966-4eae-adae-9c32edfcc484 + HUGH + + + 0x124 + 2082b5e0-7a64-478a-b1b2-e3404fab6dad + LENO + + + + 0x1 + + 0x125 + dfbaaded-754b-5214-a5f2-46aa3331e8ce + DELL + + + + 0x1 + + + 0x1 + 0x1 + dfbaaded-754b-5214-a5f2-46aa3331e8ce + /dev/foo + + diff --git a/src/fuzzing/firmware/acpi-phat.bin b/src/fuzzing/firmware/acpi-phat.bin new file mode 100644 index 0000000000000000000000000000000000000000..1aa26cc9b27ebb8f87b981aeae9803c18a865283 GIT binary patch literal 200 zcmWIWa11%Yz`(#b*CW*3!!