From ae80ba6d16cd6ea8c04d80c41c64b3954e424a1a Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 9 Feb 2023 20:50:57 +0000 Subject: [PATCH] Fix SMBIOS struct parsing when there are three NULs in a row We need to be careful detecting the end of a string section when the struct ends with NUL NUL NUL. Fixes https://github.com/fwupd/fwupd/issues/5509 --- libfwupdplugin/fu-smbios.c | 46 +++++++++++++++++++--------------- libfwupdplugin/fu-string.c | 29 +++++++++++++++++++++ libfwupdplugin/fu-string.h | 2 ++ libfwupdplugin/fwupdplugin.map | 1 + 4 files changed, 58 insertions(+), 20 deletions(-) diff --git a/libfwupdplugin/fu-smbios.c b/libfwupdplugin/fu-smbios.c index 7e65a9ce3..5867a9c01 100644 --- a/libfwupdplugin/fu-smbios.c +++ b/libfwupdplugin/fu-smbios.c @@ -98,14 +98,21 @@ fu_smbios_setup_from_data(FuSmbios *self, const guint8 *buf, gsize sz, GError ** if (!fu_memread_uint16_safe(buf, sz, i + 0x2, &str_handle, G_LITTLE_ENDIAN, error)) return FALSE; - /* invalid */ - if (str_len == 0x00) - break; + /* sanity check */ + if (str_len < 4) { + g_set_error(error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "structure smaller than allowed @0x%x", + (guint)i); + return FALSE; + } if (i + str_len >= sz) { - g_set_error_literal(error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "structure larger than available data"); + g_set_error(error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "structure larger than available data @0x%x", + (guint)i); return FALSE; } @@ -118,22 +125,21 @@ fu_smbios_setup_from_data(FuSmbios *self, const guint8 *buf, gsize sz, GError ** g_byte_array_append(item->buf, buf + i, str_len); g_ptr_array_add(self->items, item); - /* jump to the end of the struct */ + /* jump to the end of the formatted area of the struct */ i += str_len; - if (buf[i] == '\0' && buf[i + 1] == '\0') { - i++; - continue; - } /* add strings from table */ - for (gsize start_offset = i; i < sz; i++) { - if (buf[i] == '\0') { - if (start_offset == i) - break; - g_ptr_array_add(item->strings, - g_strdup((const gchar *)&buf[start_offset])); - start_offset = i + 1; - } + while (i < sz) { + GString *str; + + /* end of string section */ + if (item->strings->len > 0 && buf[i] == 0x0) + break; + + /* copy into string table */ + str = fu_strdup((const gchar *)buf, sz, i); + i += str->len + 1; + g_ptr_array_add(item->strings, g_string_free(str, FALSE)); } } return TRUE; diff --git a/libfwupdplugin/fu-string.c b/libfwupdplugin/fu-string.c index c0594de70..c7f1d5e34 100644 --- a/libfwupdplugin/fu-string.c +++ b/libfwupdplugin/fu-string.c @@ -171,6 +171,35 @@ fu_strstrip(const gchar *str) return g_strndup(str + head, tail - head + 1); } +/** + * fu_strdup: + * @str: a string, e.g. ` test ` + * @bufsz: the maximum size of @str + * @offset: the offset to start copying from + * + * Copies a string from a buffer of a specified size up to (but not including) `NUL`. + * + * Returns: (transfer full): a #GString, possibly of zero size. + * + * Since: 1.8.11 + **/ +GString * +fu_strdup(const gchar *str, gsize bufsz, gsize offset) +{ + GString *substr; + + g_return_val_if_fail(str != NULL, NULL); + g_return_val_if_fail(offset < bufsz, NULL); + + substr = g_string_new(NULL); + while (offset < bufsz) { + if (str[offset] == '\0') + break; + g_string_append_c(substr, str[offset++]); + } + return substr; +} + /** * fu_string_replace: * @string: the #GString to operate on diff --git a/libfwupdplugin/fu-string.h b/libfwupdplugin/fu-string.h index 27eed8f34..19deca1a6 100644 --- a/libfwupdplugin/fu-string.h +++ b/libfwupdplugin/fu-string.h @@ -33,6 +33,8 @@ gchar ** fu_strsplit(const gchar *str, gsize sz, const gchar *delimiter, gint max_tokens); gchar * fu_strjoin(const gchar *separator, GPtrArray *array); +GString * +fu_strdup(const gchar *str, gsize bufsz, gsize offset); /** * FuStrsplitFunc: diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 6a433c5f5..312659b86 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -1165,5 +1165,6 @@ LIBFWUPDPLUGIN_1.8.11 { fu_device_has_problem; fu_device_sleep; fu_device_sleep_full; + fu_strdup; local: *; } LIBFWUPDPLUGIN_1.8.10;