diff --git a/libfwupdplugin/fu-efi-firmware-section.c b/libfwupdplugin/fu-efi-firmware-section.c index e9075453a..73d868f46 100644 --- a/libfwupdplugin/fu-efi-firmware-section.c +++ b/libfwupdplugin/fu-efi-firmware-section.c @@ -123,14 +123,13 @@ fu_efi_firmware_section_parse(FuFirmware *firmware, const guint8 *buf = g_bytes_get_data(fw, &bufsz); g_autoptr(GBytes) blob = NULL; - if (!fu_memread_uint32_safe(buf, - bufsz, /* uint24_t! */ + if (!fu_memread_uint24_safe(buf, + bufsz, FU_EFI_FIRMWARE_SECTION_OFFSET_SIZE, &size, G_LITTLE_ENDIAN, error)) return FALSE; - size &= 0xFFFFFF; if (size < FU_EFI_FIRMWARE_SECTION_SIZE) { g_set_error(error, FWUPD_ERROR, diff --git a/libfwupdplugin/fu-mem.c b/libfwupdplugin/fu-mem.c index 773fb5f8e..6cb7dceba 100644 --- a/libfwupdplugin/fu-mem.c +++ b/libfwupdplugin/fu-mem.c @@ -578,6 +578,52 @@ fu_memread_uint16_safe(const guint8 *buf, return TRUE; } +/** + * fu_memread_uint24_safe: + * @buf: source buffer + * @bufsz: maximum size of @buf, typically `sizeof(buf)` + * @offset: offset in bytes into @buf to copy from + * @value: (out) (nullable): the parsed value + * @endian: an endian type, e.g. %G_LITTLE_ENDIAN + * @error: (nullable): optional return location for an error + * + * Read a value from a buffer using a specified endian in a safe way. + * + * You don't need to use this function in "obviously correct" cases, nor should + * you use it when performance is a concern. Only us it when you're not sure if + * malicious data from a device or firmware could cause memory corruption. + * + * Returns: %TRUE if @value was set, %FALSE otherwise + * + * Since: 1.8.3 + **/ +gboolean +fu_memread_uint24_safe(const guint8 *buf, + gsize bufsz, + gsize offset, + guint32 *value, + FuEndianType endian, + GError **error) +{ + guint8 dst[3] = {0x0}; + + g_return_val_if_fail(buf != NULL, FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + if (!fu_memcpy_safe(dst, + sizeof(dst), + 0x0, /* dst */ + buf, + bufsz, + offset, /* src */ + sizeof(dst), + error)) + return FALSE; + if (value != NULL) + *value = fu_memread_uint24(dst, endian); + return TRUE; +} + /** * fu_memread_uint32_safe: * @buf: source buffer diff --git a/libfwupdplugin/fu-mem.h b/libfwupdplugin/fu-mem.h index 1ce8aee50..d7a5fb291 100644 --- a/libfwupdplugin/fu-mem.h +++ b/libfwupdplugin/fu-mem.h @@ -42,6 +42,13 @@ fu_memread_uint16_safe(const guint8 *buf, FuEndianType endian, GError **error) G_GNUC_WARN_UNUSED_RESULT; gboolean +fu_memread_uint24_safe(const guint8 *buf, + gsize bufsz, + gsize offset, + guint32 *value, + FuEndianType endian, + GError **error) G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_memread_uint32_safe(const guint8 *buf, gsize bufsz, gsize offset, diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 9d288a835..89ca63bd3 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -1059,3 +1059,9 @@ LIBFWUPDPLUGIN_1.8.2 { fu_volume_new_esp_for_path; local: *; } LIBFWUPDPLUGIN_1.8.1; + +LIBFWUPDPLUGIN_1.8.3 { + global: + fu_memread_uint24_safe; + local: *; +} LIBFWUPDPLUGIN_1.8.2;