Add fu_memmem_safe() with fallback code for win32

This commit is contained in:
Richard Hughes 2021-12-15 10:04:36 +00:00
parent b92fe4a760
commit 52fd89f9ab
5 changed files with 118 additions and 31 deletions

View File

@ -2328,6 +2328,82 @@ fu_memcpy_safe(guint8 *dst,
return TRUE;
}
/**
* fu_memmem_safe:
* @haystack: destination buffer
* @haystack_sz: maximum size of @haystack, typically `sizeof(haystack)`
* @needle: source buffer
* @needle_sz: maximum size of @haystack, typically `sizeof(needle)`
* @offset: (out) (nullable): offset in bytes @needle has been found in @haystack
* @error: (nullable): optional return location for an error
*
* Finds a block of memory in another block of memory in a safe way.
*
* Returns: %TRUE if the needle was found in the haystack, %FALSE otherwise
*
* Since: 1.7.4
**/
gboolean
fu_memmem_safe(const guint8 *haystack,
gsize haystack_sz,
const guint8 *needle,
gsize needle_sz,
gsize *offset,
GError **error)
{
#ifdef HAVE_MEMMEM
const guint8 *tmp;
#endif
g_return_val_if_fail(haystack != NULL, FALSE);
g_return_val_if_fail(needle != NULL, FALSE);
g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
/* nothing to find */
if (needle_sz == 0) {
if (offset != NULL)
*offset = 0;
return TRUE;
}
/* impossible */
if (needle_sz > haystack_sz) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_FOUND,
"needle of 0x%02x bytes is larger than haystack of 0x%02x bytes",
(guint)needle_sz,
(guint)haystack_sz);
return FALSE;
}
#ifdef HAVE_MEMMEM
/* trust glibc to do a binary or linear search as appropriate */
tmp = memmem(haystack, haystack_sz, needle, needle_sz);
if (tmp != NULL) {
if (offset != NULL)
*offset = tmp - haystack;
return TRUE;
}
#else
for (gsize i = 0; i < haystack_sz - needle_sz; i++) {
if (memcmp(haystack + i, needle, needle_sz) == 0) {
if (offset != NULL)
*offset = i;
return TRUE;
}
}
#endif
/* not found */
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_FOUND,
"needle of 0x%02x bytes was not found in haystack of 0x%02x bytes",
(guint)needle_sz,
(guint)haystack_sz);
return FALSE;
}
/**
* fu_memdup_safe:
* @src: source buffer

View File

@ -263,6 +263,13 @@ fu_memcpy_safe(guint8 *dst,
gsize n,
GError **error) G_GNUC_WARN_UNUSED_RESULT;
gboolean
fu_memmem_safe(const guint8 *haystack,
gsize haystack_sz,
const guint8 *needle,
gsize needle_sz,
gsize *offset,
GError **error) G_GNUC_WARN_UNUSED_RESULT;
gboolean
fu_common_read_uint8_safe(const guint8 *buf,
gsize bufsz,
gsize offset,

View File

@ -6,8 +6,6 @@
#include "config.h"
#include <string.h>
#include "fu-common.h"
#include "fu-fmap-firmware.h"
@ -24,31 +22,6 @@
G_DEFINE_TYPE(FuFmapFirmware, fu_fmap_firmware, FU_TYPE_FIRMWARE)
static gboolean
fu_fmap_firmware_find_offset(FuFmapFirmware *self, const guint8 *buf, gsize bufsz, GError **error)
{
#ifdef HAVE_MEMMEM
const guint8 *tmp;
g_return_val_if_fail(buf != NULL, FALSE);
/* trust glibc to do a binary or linear search as appropriate */
tmp = memmem(buf, bufsz, FMAP_SIGNATURE, 8);
if (tmp == NULL) {
g_set_error_literal(error,
G_IO_ERROR,
G_IO_ERROR_INVALID_DATA,
"fmap header not found");
return FALSE;
}
fu_firmware_set_offset(FU_FIRMWARE(self), tmp - buf);
return TRUE;
#else
g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "memmem() not available");
return FALSE;
#endif
}
static gboolean
fu_fmap_firmware_parse(FuFirmware *firmware,
GBytes *fw,
@ -57,7 +30,6 @@ fu_fmap_firmware_parse(FuFirmware *firmware,
FwupdInstallFlags flags,
GError **error)
{
FuFmapFirmware *self = FU_FMAP_FIRMWARE(firmware);
FuFmapFirmwareClass *klass_firmware = FU_FMAP_FIRMWARE_GET_CLASS(firmware);
gsize bufsz;
const guint8 *buf = g_bytes_get_data(fw, &bufsz);
@ -75,8 +47,9 @@ fu_fmap_firmware_parse(FuFirmware *firmware,
/* only search for the fmap signature if not fuzzing */
if ((flags & FWUPD_INSTALL_FLAG_NO_SEARCH) == 0) {
if (!fu_fmap_firmware_find_offset(self, buf, bufsz, error))
if (!fu_memmem_safe(buf, bufsz, (const guint8 *)FMAP_SIGNATURE, 8, &offset, error))
return FALSE;
fu_firmware_set_offset(firmware, offset);
}
/* load header */
@ -85,7 +58,7 @@ fu_fmap_firmware_parse(FuFirmware *firmware,
0x0, /* dst */
buf,
bufsz,
fu_firmware_get_offset(firmware), /* src */
offset, /* src */
sizeof(fmap),
error))
return FALSE;
@ -108,7 +81,7 @@ fu_fmap_firmware_parse(FuFirmware *firmware,
GUINT16_FROM_LE(fmap.nareas));
return FALSE;
}
offset = fu_firmware_get_offset(firmware) + sizeof(fmap);
offset += sizeof(fmap);
for (gsize i = 0; i < GUINT16_FROM_LE(fmap.nareas); i++) {
FuFmapArea area;

View File

@ -479,6 +479,30 @@ _strnsplit_nop_cb(GString *token, guint token_idx, gpointer user_data, GError **
return TRUE;
}
static void
fu_common_memmem_func(void)
{
const guint8 haystack[] = {'H', 'A', 'Y', 'S'};
const guint8 needle[] = {'A', 'Y'};
gboolean ret;
gsize offset = 0;
g_autoptr(GError) error = NULL;
ret = fu_memmem_safe(haystack, sizeof(haystack), needle, sizeof(needle), &offset, &error);
g_assert_no_error(error);
g_assert_true(ret);
g_assert_cmpint(offset, ==, 0x1);
ret = fu_memmem_safe(haystack + 2,
sizeof(haystack) - 2,
needle,
sizeof(needle),
&offset,
&error);
g_assert_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND);
g_assert_false(ret);
}
static void
fu_common_strnsplit_func(void)
{
@ -3789,6 +3813,7 @@ main(int argc, char **argv)
g_setenv("FWUPD_LOCALSTATEDIR", "/tmp/fwupd-self-test/var", TRUE);
g_test_add_func("/fwupd/common{strnsplit}", fu_common_strnsplit_func);
g_test_add_func("/fwupd/common{memmem}", fu_common_memmem_func);
g_test_add_func("/fwupd/progress", fu_progress_func);
g_test_add_func("/fwupd/progress{child}", fu_progress_child_func);
g_test_add_func("/fwupd/progress{parent-1-step}", fu_progress_parent_one_step_proxy_func);

View File

@ -977,3 +977,9 @@ LIBFWUPDPLUGIN_1.7.3 {
fu_common_sum8_bytes;
local: *;
} LIBFWUPDPLUGIN_1.7.2;
LIBFWUPDPLUGIN_1.7.4 {
global:
fu_memmem_safe;
local: *;
} LIBFWUPDPLUGIN_1.7.3;