Prevent a partial fuzzing DoS when loading corrupt SREC files

The SREC parser attempts to fill 1Mb of data when parsing corrupt data sections
-- which in the static fuzz targets takes a long time. Correctly check that the
data exists to mitigate.

Fixes https://oss-fuzz.com/testcase-detail/6102934106013696
This commit is contained in:
Richard Hughes 2022-09-29 11:42:21 +01:00
parent 66bf03e8eb
commit a8e56396d5

View File

@ -133,6 +133,7 @@ fu_srec_firmware_tokenize_cb(GString *token, guint token_idx, gpointer user_data
FuSrecFirmwareTokenHelper *helper = (FuSrecFirmwareTokenHelper *)user_data; FuSrecFirmwareTokenHelper *helper = (FuSrecFirmwareTokenHelper *)user_data;
FuSrecFirmwarePrivate *priv = GET_PRIVATE(helper->self); FuSrecFirmwarePrivate *priv = GET_PRIVATE(helper->self);
g_autoptr(FuSrecFirmwareRecord) rcd = NULL; g_autoptr(FuSrecFirmwareRecord) rcd = NULL;
gboolean require_data = FALSE;
guint32 rec_addr32; guint32 rec_addr32;
guint16 rec_addr16; guint16 rec_addr16;
guint8 addrsz = 0; /* bytes */ guint8 addrsz = 0; /* bytes */
@ -230,15 +231,19 @@ fu_srec_firmware_tokenize_cb(GString *token, guint token_idx, gpointer user_data
switch (rec_kind) { switch (rec_kind) {
case FU_FIRMWARE_SREC_RECORD_KIND_S0_HEADER: case FU_FIRMWARE_SREC_RECORD_KIND_S0_HEADER:
addrsz = 2; addrsz = 2;
require_data = TRUE;
break; break;
case FU_FIRMWARE_SREC_RECORD_KIND_S1_DATA_16: case FU_FIRMWARE_SREC_RECORD_KIND_S1_DATA_16:
addrsz = 2; addrsz = 2;
require_data = TRUE;
break; break;
case FU_FIRMWARE_SREC_RECORD_KIND_S2_DATA_24: case FU_FIRMWARE_SREC_RECORD_KIND_S2_DATA_24:
addrsz = 3; addrsz = 3;
require_data = TRUE;
break; break;
case FU_FIRMWARE_SREC_RECORD_KIND_S3_DATA_32: case FU_FIRMWARE_SREC_RECORD_KIND_S3_DATA_32:
addrsz = 4; addrsz = 4;
require_data = TRUE;
break; break;
case FU_FIRMWARE_SREC_RECORD_KIND_S5_COUNT_16: case FU_FIRMWARE_SREC_RECORD_KIND_S5_COUNT_16:
addrsz = 2; addrsz = 2;
@ -306,6 +311,14 @@ fu_srec_firmware_tokenize_cb(GString *token, guint token_idx, gpointer user_data
rec_addr32, rec_addr32,
(guint)rec_count - addrsz - 1); (guint)rec_count - addrsz - 1);
} }
if (require_data && rec_count == addrsz) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"S%u required data but not provided",
rec_kind);
return FALSE;
}
/* data */ /* data */
rcd = fu_srec_firmware_record_new(token_idx + 1, rec_kind, rec_addr32); rcd = fu_srec_firmware_record_new(token_idx + 1, rec_kind, rec_addr32);