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
This commit is contained in:
Richard Hughes 2023-02-09 20:50:57 +00:00
parent d911ca60c5
commit ae80ba6d16
4 changed files with 58 additions and 20 deletions

View File

@ -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;
if (i + str_len >= sz) {
g_set_error_literal(error,
/* sanity check */
if (str_len < 4) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"structure larger than available data");
"structure smaller than allowed @0x%x",
(guint)i);
return FALSE;
}
if (i + str_len >= sz) {
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)
while (i < sz) {
GString *str;
/* end of string section */
if (item->strings->len > 0 && buf[i] == 0x0)
break;
g_ptr_array_add(item->strings,
g_strdup((const gchar *)&buf[start_offset]));
start_offset = i + 1;
}
/* 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;

View File

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

View File

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

View File

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