From 32ffdb2677ce080f7740f9788652a3f3eb7eaffc Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 4 Mar 2021 17:38:12 +0000 Subject: [PATCH] Add helper API to write in a safer way --- libfwupdplugin/fu-common.c | 109 +++++++++++++++++++++++++++++++++ libfwupdplugin/fu-common.h | 20 ++++++ libfwupdplugin/fwupdplugin.map | 3 + 3 files changed, 132 insertions(+) diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 3a472fd23..5b3de312a 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -2179,6 +2179,115 @@ fu_common_read_uint32_safe (const guint8 *buf, return TRUE; } +/** + * fu_common_write_uint8_safe: + * @buf: source buffer + * @bufsz: maximum size of @buf, typically `sizeof(buf)` + * @offset: offset in bytes into @buf to write to + * @value: the value to write + * @error: A #GError or %NULL + * + * Write a value to a buffer 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. + * + * Return value: %TRUE if @value was written, %FALSE otherwise + * + * Since: 1.5.8 + **/ +gboolean +fu_common_write_uint8_safe (guint8 *buf, + gsize bufsz, + gsize offset, + guint8 value, + GError **error) +{ + g_return_val_if_fail (buf != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + return fu_memcpy_safe (buf, bufsz, offset, /* dst */ + &value, sizeof(value), 0x0, /* src */ + sizeof(value), error); +} + +/** + * fu_common_write_uint16_safe: + * @buf: source buffer + * @bufsz: maximum size of @buf, typically `sizeof(buf)` + * @offset: offset in bytes into @buf to write to + * @value: the value to write + * @endian: A #FuEndianType, e.g. %G_LITTLE_ENDIAN + * @error: A #GError or %NULL + * + * Write a value to 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. + * + * Return value: %TRUE if @value was written, %FALSE otherwise + * + * Since: 1.5.8 + **/ +gboolean +fu_common_write_uint16_safe (guint8 *buf, + gsize bufsz, + gsize offset, + guint16 value, + FuEndianType endian, + GError **error) +{ + guint8 tmp[2] = { 0x0 }; + + g_return_val_if_fail (buf != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + fu_common_write_uint16 (tmp, value, endian); + return fu_memcpy_safe (buf, bufsz, offset, /* dst */ + tmp, sizeof(tmp), 0x0, /* src */ + sizeof(tmp), error); +} + +/** + * fu_common_write_uint32_safe: + * @buf: source buffer + * @bufsz: maximum size of @buf, typically `sizeof(buf)` + * @offset: offset in bytes into @buf to write to + * @value: the value to write + * @endian: A #FuEndianType, e.g. %G_LITTLE_ENDIAN + * @error: A #GError or %NULL + * + * Write a value to 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. + * + * Return value: %TRUE if @value was written, %FALSE otherwise + * + * Since: 1.5.8 + **/ +gboolean +fu_common_write_uint32_safe (guint8 *buf, + gsize bufsz, + gsize offset, + guint32 value, + FuEndianType endian, + GError **error) +{ + guint8 tmp[4] = { 0x0 }; + + g_return_val_if_fail (buf != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + fu_common_write_uint32 (tmp, value, endian); + return fu_memcpy_safe (buf, bufsz, offset, /* dst */ + tmp, sizeof(tmp), 0x0, /* src */ + sizeof(tmp), error); +} + /** * fu_byte_array_append_uint8: * @array: A #GByteArray diff --git a/libfwupdplugin/fu-common.h b/libfwupdplugin/fu-common.h index 7e9fab400..13d8996af 100644 --- a/libfwupdplugin/fu-common.h +++ b/libfwupdplugin/fu-common.h @@ -224,6 +224,26 @@ gboolean fu_common_read_uint32_safe (const guint8 *buf, FuEndianType endian, GError **error) G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_common_write_uint8_safe (guint8 *buf, + gsize bufsz, + gsize offset, + guint8 value, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_common_write_uint16_safe (guint8 *buf, + gsize bufsz, + gsize offset, + guint16 value, + FuEndianType endian, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_common_write_uint32_safe (guint8 *buf, + gsize bufsz, + gsize offset, + guint32 value, + FuEndianType endian, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; void fu_byte_array_set_size (GByteArray *array, guint length); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index e35c970da..b20eac58e 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -775,6 +775,9 @@ LIBFWUPDPLUGIN_1.5.8 { global: fu_bluez_device_notify_start; fu_bluez_device_notify_stop; + fu_common_write_uint16_safe; + fu_common_write_uint32_safe; + fu_common_write_uint8_safe; fu_device_get_backend_id; fu_device_set_backend_id; fu_plugin_add_possible_quirk_key;