Add fu_memdup_safe()

See https://mail.gnome.org/archives/desktop-devel-list/2021-February/msg00000.html
for more details.
This commit is contained in:
Richard Hughes 2021-02-04 20:28:49 +00:00
parent b5481f24d3
commit 9b11af985f
9 changed files with 80 additions and 8 deletions

View File

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

View File

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

View File

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

View File

@ -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) {

View File

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

View File

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

View File

@ -10,6 +10,7 @@
#include <glib/gstdio.h>
#include <string.h>
#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 {

View File

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

View File

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