From ae3ad67710a9b71147023e2fca4bc3653bd501c9 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 24 Feb 2021 22:48:14 +0000 Subject: [PATCH] elantp: Add support for writing the firmware image This allows for fuzzing. --- contrib/ci/oss-fuzz.py | 1 + plugins/elantp/fu-elantp-firmware.c | 70 +++++++++++++++++++++++++++- plugins/elantp/meson.build | 2 +- src/fuzzing/elantp.builder.xml | 7 +++ src/fuzzing/firmware/elantp.bin | Bin 0 -> 3599 bytes 5 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 src/fuzzing/elantp.builder.xml create mode 100644 src/fuzzing/firmware/elantp.bin diff --git a/contrib/ci/oss-fuzz.py b/contrib/ci/oss-fuzz.py index c7116a234..fc3d7045e 100755 --- a/contrib/ci/oss-fuzz.py +++ b/contrib/ci/oss-fuzz.py @@ -303,6 +303,7 @@ def _build(bld: Builder) -> None: ("ccgx", "ccgx-dmc", "ccgx-dmc*.bin"), ("cros-ec", "cros-ec", "cros-ec*"), ("ebitdo", "ebitdo", "ebitdo*"), + ("elantp", "elantp", "elantp*"), ("hailuck", "hailuck-kbd", "ihex*"), ("pixart-rf", "pxi", "pixart*"), ("solokey", "solokey", "solokey*"), diff --git a/plugins/elantp/fu-elantp-firmware.c b/plugins/elantp/fu-elantp-firmware.c index bd9288b3f..34d18555a 100644 --- a/plugins/elantp/fu-elantp-firmware.c +++ b/plugins/elantp/fu-elantp-firmware.c @@ -20,7 +20,7 @@ struct _FuElantpFirmware { G_DEFINE_TYPE (FuElantpFirmware, fu_elantp_firmware, FU_TYPE_FIRMWARE) /* firmware block update */ -#define ETP_IAP_START_ADDR 0x0083 +#define ETP_IAP_START_ADDR_WRDS 0x008 guint16 fu_elantp_firmware_get_module_id (FuElantpFirmware *self) @@ -60,15 +60,31 @@ fu_elantp_firmware_parse (FuFirmware *firmware, g_autoptr(FuFirmwareImage) img = fu_firmware_image_new (fw); /* presumably in words */ - if (!fu_common_read_uint16_safe (buf, bufsz, ETP_IAP_START_ADDR * 2, + if (!fu_common_read_uint16_safe (buf, bufsz, ETP_IAP_START_ADDR_WRDS * 2, &iap_addr_wrds, G_LITTLE_ENDIAN, error)) return FALSE; + if (iap_addr_wrds < ETP_IAP_START_ADDR_WRDS || iap_addr_wrds > 0x7FFF) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "IAP address invalid: 0x%x", + iap_addr_wrds); + return FALSE; + } self->iap_addr = iap_addr_wrds * 2; /* read module ID */ if (!fu_common_read_uint16_safe (buf, bufsz, self->iap_addr, &module_id_wrds, G_LITTLE_ENDIAN, error)) return FALSE; + if (module_id_wrds > 0x7FFF) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "module ID address invalid: 0x%x", + module_id_wrds); + return FALSE; + } if (!fu_common_read_uint16_safe (buf, bufsz, module_id_wrds * 2, &self->module_id, G_LITTLE_ENDIAN, error)) return FALSE; @@ -78,6 +94,54 @@ fu_elantp_firmware_parse (FuFirmware *firmware, return TRUE; } +static gboolean +fu_elantp_firmware_build (FuFirmware *firmware, XbNode *n, GError **error) +{ + FuElantpFirmware *self = FU_ELANTP_FIRMWARE (firmware); + guint64 tmp; + + /* two simple properties */ + tmp = xb_node_query_text_as_uint (n, "module_id", NULL); + if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT16) + self->module_id = tmp; + tmp = xb_node_query_text_as_uint (n, "iap_addr", NULL); + if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT16) + self->iap_addr = tmp; + + /* success */ + return TRUE; +} + +static GBytes * +fu_elantp_firmware_write (FuFirmware *firmware, GError **error) +{ + FuElantpFirmware *self = FU_ELANTP_FIRMWARE (firmware); + g_autoptr(GByteArray) buf = g_byte_array_new (); + g_autoptr(GBytes) blob = NULL; + + /* only one image supported */ + blob = fu_firmware_get_image_default_bytes (firmware, error); + if (blob == NULL) + return NULL; + + /* lets build a simple firmware like this: + * ------ 0x0 + * HEADER (containing IAP offset and module ID) + * ------ ~0x10a + * DATA + * ------ + */ + fu_byte_array_set_size (buf, self->iap_addr + 0x2 + 0x2); + fu_common_write_uint16 (buf->data + ETP_IAP_START_ADDR_WRDS * 2, + self->iap_addr / 2, G_LITTLE_ENDIAN); + fu_common_write_uint16 (buf->data + self->iap_addr, + (self->iap_addr + 2) / 2, G_LITTLE_ENDIAN); + fu_common_write_uint16 (buf->data + self->iap_addr + 0x2, + self->module_id, G_LITTLE_ENDIAN); + g_byte_array_append (buf, g_bytes_get_data (blob, NULL), g_bytes_get_size (blob)); + return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); +} + static void fu_elantp_firmware_init (FuElantpFirmware *self) { @@ -88,6 +152,8 @@ fu_elantp_firmware_class_init (FuElantpFirmwareClass *klass) { FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); klass_firmware->parse = fu_elantp_firmware_parse; + klass_firmware->build = fu_elantp_firmware_build; + klass_firmware->write = fu_elantp_firmware_write; klass_firmware->to_string = fu_elantp_firmware_to_string; } diff --git a/plugins/elantp/meson.build b/plugins/elantp/meson.build index d67e20e82..be0403c32 100644 --- a/plugins/elantp/meson.build +++ b/plugins/elantp/meson.build @@ -12,7 +12,7 @@ shared_module('fu_plugin_elantp', sources : [ 'fu-plugin-elantp.c', 'fu-elantp-common.c', - 'fu-elantp-firmware.c', + 'fu-elantp-firmware.c', # fuzzing 'fu-elantp-hid-device.c', 'fu-elantp-i2c-device.c', ], diff --git a/src/fuzzing/elantp.builder.xml b/src/fuzzing/elantp.builder.xml new file mode 100644 index 000000000..b9286a022 --- /dev/null +++ b/src/fuzzing/elantp.builder.xml @@ -0,0 +1,7 @@ + + 0xe00 + 0x2 + + aGVsbG8gd29ybGQ= + + diff --git a/src/fuzzing/firmware/elantp.bin b/src/fuzzing/firmware/elantp.bin new file mode 100644 index 0000000000000000000000000000000000000000..6e16cd8f0c5986097d28a58db7c4c6deb6f4ff20 GIT binary patch literal 3599 zcmeIu!3h8$3I IYn