elantp: Add support for writing the firmware image

This allows for fuzzing.
This commit is contained in:
Richard Hughes 2021-02-24 22:48:14 +00:00
parent 9b304fdfbd
commit ae3ad67710
5 changed files with 77 additions and 3 deletions

View File

@ -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*"),

View File

@ -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;
}

View File

@ -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',
],

View File

@ -0,0 +1,7 @@
<firmware gtype="FuElantpFirmware">
<iap_addr>0xe00</iap_addr>
<module_id>0x2</module_id>
<image>
<data>aGVsbG8gd29ybGQ=</data> <!-- base64 -->
</image>
</firmware>

Binary file not shown.