diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 2d1f3cd23..4380a5e5d 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -2019,6 +2019,48 @@ fu_memcpy_safe (guint8 *dst, gsize dst_sz, gsize dst_offset, return TRUE; } +/** + * fu_memdup_safe: + * @src: source buffer + * @n: number of bytes to copy from @src + * @error: A #GError or %NULL + * + * Duplicates some memory using memdup 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. + * + * NOTE: This function intentionally limits allocation size to 1GB. + * + * Return value: (transfer full): block of allocated memory, or %NULL for an error. + * + * Since: 1.5.6 + **/ +guint8 * +fu_memdup_safe (const guint8 *src, gsize n, GError **error) +{ + g_autofree guint8 *dst = NULL; + + /* sanity check */ + if (n > 0x40000000) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "cannot allocate %uGB of memory", + (guint) (n / 0x40000000)); + return NULL; + } + + /* linear block of memory */ + dst = g_malloc (n); + if (!fu_memcpy_safe (dst, n, 0x0, /* dst */ + src, n, 0x0, /* src */ + n, error)) + return NULL; + return g_steal_pointer (&dst); +} + /** * fu_common_read_uint8_safe: * @buf: source buffer diff --git a/libfwupdplugin/fu-common.h b/libfwupdplugin/fu-common.h index 390b8ed4e..7e9fab400 100644 --- a/libfwupdplugin/fu-common.h +++ b/libfwupdplugin/fu-common.h @@ -191,6 +191,10 @@ GBytes *fu_common_bytes_new_offset (GBytes *bytes, GError **error) G_GNUC_WARN_UNUSED_RESULT; gsize fu_common_strwidth (const gchar *text); +guint8 *fu_memdup_safe (const guint8 *src, + gsize n, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_memcpy_safe (guint8 *dst, gsize dst_sz, gsize dst_offset, diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 2884a8746..53885fa96 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -748,6 +748,7 @@ LIBFWUPDPLUGIN_1.5.6 { fu_firmware_new_from_gtypes; fu_hwids_add_smbios_override; fu_hwids_get_keys; + fu_memdup_safe; fu_plugin_get_devices; local: *; } LIBFWUPDPLUGIN_1.5.5; diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index e753ddae3..00cca72dd 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -194,7 +194,12 @@ fu_cros_ec_usb_device_do_xfer (FuCrosEcUsbDevice * self, const guint8 *outbuf, { GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); gsize actual = 0; - g_autofree guint8 *outbuf_tmp = g_memdup (outbuf, outlen); + g_autofree guint8 *outbuf_tmp = NULL; + + /* make mutable */ + outbuf_tmp = fu_memdup_safe (outbuf, outlen, error); + if (outbuf_tmp == NULL) + return FALSE; /* send data out */ if (outbuf != NULL && outlen > 0) { diff --git a/plugins/fastboot/fu-fastboot-device.c b/plugins/fastboot/fu-fastboot-device.c index 6e20247b8..6ea2686ed 100644 --- a/plugins/fastboot/fu-fastboot-device.c +++ b/plugins/fastboot/fu-fastboot-device.c @@ -90,7 +90,12 @@ fu_fastboot_device_write (FuDevice *device, const guint8 *buf, gsize buflen, GEr GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (device)); gboolean ret; gsize actual_len = 0; - g_autofree guint8 *buf2 = g_memdup (buf, (guint) buflen); + g_autofree guint8 *buf2 = NULL; + + /* make mutable */ + buf2 = fu_memdup_safe (buf, buflen, error); + if (buf2 == NULL) + return FALSE; fu_fastboot_buffer_dump ("writing", buf, buflen); ret = g_usb_device_bulk_transfer (usb_device, diff --git a/plugins/hailuck/fu-hailuck-bl-device.c b/plugins/hailuck/fu-hailuck-bl-device.c index e1187b959..27cec1f7c 100644 --- a/plugins/hailuck/fu-hailuck-bl-device.c +++ b/plugins/hailuck/fu-hailuck-bl-device.c @@ -219,8 +219,11 @@ fu_hailuck_bl_device_write_firmware (FuDevice *device, /* intentionally corrupt first chunk so that CRC fails */ chk0 = g_ptr_array_index (chunks, 0); - chk0_data = g_memdup (fu_chunk_get_data (chk0), - fu_chunk_get_data_sz (chk0)); + chk0_data = fu_memdup_safe (fu_chunk_get_data (chk0), + fu_chunk_get_data_sz (chk0), + error); + if (chk0_data == NULL) + return FALSE; chk0_data[0] = 0x00; if (!fu_hailuck_bl_device_write_block (self, chk0_data, diff --git a/plugins/optionrom/fu-rom.c b/plugins/optionrom/fu-rom.c index e35464ab5..82e28dbd7 100644 --- a/plugins/optionrom/fu-rom.c +++ b/plugins/optionrom/fu-rom.c @@ -10,6 +10,7 @@ #include #include +#include "fu-common.h" #include "fu-rom.h" static void fu_rom_finalize (GObject *object); @@ -423,7 +424,9 @@ fu_rom_pci_get_header (const guint8 *buffer, guint32 sz) } /* copy this locally to the header */ - hdr->rom_data = g_memdup (buffer, hdr->rom_len); + hdr->rom_data = fu_memdup_safe (buffer, hdr->rom_len, NULL); + if (hdr->rom_data == NULL) + return NULL; /* parse out CPI */ hdr->entry_point = ((guint32) buffer[0x05] << 16) + @@ -582,7 +585,8 @@ fu_rom_load_data (FuRom *self, hdr->last_image = 0x80; hdr->rom_offset = hdr_sz + jump; hdr->rom_len = sz - hdr->rom_offset; - hdr->rom_data = g_memdup (&buffer[hdr->rom_offset], hdr->rom_len); + hdr->rom_data = fu_memdup_safe (&buffer[hdr->rom_offset], + hdr->rom_len, NULL); hdr->image_len = hdr->rom_len; g_ptr_array_add (self->hdrs, hdr); } else { diff --git a/plugins/rts54hub/fu-rts54hub-device.c b/plugins/rts54hub/fu-rts54hub-device.c index d41c40dec..6b3d3e628 100644 --- a/plugins/rts54hub/fu-rts54hub-device.c +++ b/plugins/rts54hub/fu-rts54hub-device.c @@ -95,7 +95,13 @@ fu_rts54hub_device_write_flash (FuRts54HubDevice *self, { GUsbDevice *usb_device = fu_usb_device_get_dev (FU_USB_DEVICE (self)); gsize actual_len = 0; - g_autofree guint8 *datarw = g_memdup (data, datasz); + g_autofree guint8 *datarw = NULL; + + /* make mutable */ + datarw = fu_memdup_safe (data, datasz, error); + if (datarw == NULL) + return FALSE; + if (!g_usb_device_control_transfer (usb_device, G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, G_USB_DEVICE_REQUEST_TYPE_VENDOR, diff --git a/plugins/superio/fu-superio-it89-device.c b/plugins/superio/fu-superio-it89-device.c index 564b2a800..f50034908 100644 --- a/plugins/superio/fu-superio-it89-device.c +++ b/plugins/superio/fu-superio-it89-device.c @@ -412,7 +412,9 @@ fu_plugin_superio_fix_signature (FuSuperioDevice *self, GBytes *fw, GError **err } /* fix signature to match SMT version */ - buf2 = g_memdup (buf, sz); + buf2 = fu_memdup_safe (buf, sz, error); + if (buf2 == NULL) + return NULL; buf2[signature_offset] = 0x7f; return g_bytes_new_take (g_steal_pointer (&buf2), sz); }