dfu: Fix the SREC parser to correctly parse 32 bit address values

This commit is contained in:
Richard Hughes 2018-05-25 11:36:50 +01:00
parent 849d841ca9
commit 38d064a7f3

View File

@ -103,8 +103,8 @@ dfu_image_from_srec (DfuImage *image,
while (offset < len_in) { while (offset < len_in) {
DfuSrecClassType rec_class = DFU_SREC_RECORD_CLASS_UNKNOWN; DfuSrecClassType rec_class = DFU_SREC_RECORD_CLASS_UNKNOWN;
guint32 rec_addr32; guint32 rec_addr32;
guint8 rec_count; guint8 rec_count; /* bytes */
guint8 rec_datalen; guint8 rec_dataoffset; /* bytes */
guint8 rec_kind; guint8 rec_kind;
/* check starting token */ /* check starting token */
@ -141,9 +141,6 @@ dfu_image_from_srec (DfuImage *image,
return FALSE; return FALSE;
} }
/* remove the length of the checksum */
rec_datalen = rec_count - 1;
/* checksum check */ /* checksum check */
if ((flags & DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST) == 0) { if ((flags & DFU_FIRMWARE_PARSE_FLAG_NO_CRC_TEST) == 0) {
guint8 rec_csum = 0; guint8 rec_csum = 0;
@ -162,11 +159,14 @@ dfu_image_from_srec (DfuImage *image,
} }
} }
/* record kind + record count (in bytes, not chars) */
rec_dataoffset = 2;
/* parse record */ /* parse record */
switch (rec_kind) { switch (rec_kind) {
case '0': case '0':
rec_class = DFU_SREC_RECORD_CLASS_HEADER; rec_class = DFU_SREC_RECORD_CLASS_HEADER;
rec_datalen -= 2; rec_dataoffset += 2;
rec_addr32 = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 4); rec_addr32 = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 4);
if (rec_addr32 != 0x0) { if (rec_addr32 != 0x0) {
g_set_error (error, g_set_error (error,
@ -177,8 +177,8 @@ dfu_image_from_srec (DfuImage *image,
return FALSE; return FALSE;
} }
/* could be anything, lets assume text */ /* could be anything, lets assume text */
for (guint i = 0; i < rec_datalen; i++) { for (guint8 i = rec_dataoffset; i <= rec_count; i++) {
guint8 tmp = dfu_utils_buffer_parse_uint8 (in_buffer + offset + 8 + (i * 2)); guint8 tmp = dfu_utils_buffer_parse_uint8 (in_buffer + offset + (i * 2));
if (!g_ascii_isgraph (tmp)) if (!g_ascii_isgraph (tmp))
break; break;
g_string_append_c (modname, tmp); g_string_append_c (modname, tmp);
@ -188,40 +188,36 @@ dfu_image_from_srec (DfuImage *image,
break; break;
case '1': case '1':
rec_class = DFU_SREC_RECORD_CLASS_DATA; rec_class = DFU_SREC_RECORD_CLASS_DATA;
rec_datalen -= 2; rec_dataoffset += 2;
rec_addr32 = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 4); rec_addr32 = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 4);
break; break;
case '2': case '2':
rec_class = DFU_SREC_RECORD_CLASS_DATA; rec_class = DFU_SREC_RECORD_CLASS_DATA;
rec_datalen -= 3; rec_dataoffset += 3;
rec_addr32 = dfu_utils_buffer_parse_uint24 (in_buffer + offset + 4); rec_addr32 = dfu_utils_buffer_parse_uint24 (in_buffer + offset + 4);
break; break;
case '3': case '3':
rec_class = DFU_SREC_RECORD_CLASS_DATA; rec_class = DFU_SREC_RECORD_CLASS_DATA;
rec_datalen -= 4; rec_dataoffset += 4;
rec_addr32 = dfu_utils_buffer_parse_uint32 (in_buffer + offset + 4); rec_addr32 = dfu_utils_buffer_parse_uint32 (in_buffer + offset + 4);
break; break;
case '9': case '9':
rec_class = DFU_SREC_RECORD_CLASS_TERMINATION; rec_class = DFU_SREC_RECORD_CLASS_TERMINATION;
rec_datalen -= 2;
rec_addr32 = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 4); rec_addr32 = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 4);
got_eof = TRUE; got_eof = TRUE;
break; break;
case '8': case '8':
rec_class = DFU_SREC_RECORD_CLASS_TERMINATION; rec_class = DFU_SREC_RECORD_CLASS_TERMINATION;
rec_datalen -= 3;
rec_addr32 = dfu_utils_buffer_parse_uint24 (in_buffer + offset + 4); rec_addr32 = dfu_utils_buffer_parse_uint24 (in_buffer + offset + 4);
got_eof = TRUE; got_eof = TRUE;
break; break;
case '7': case '7':
rec_class = DFU_SREC_RECORD_CLASS_TERMINATION; rec_class = DFU_SREC_RECORD_CLASS_TERMINATION;
rec_datalen -= 4;
rec_addr32 = dfu_utils_buffer_parse_uint32 (in_buffer + offset + 4); rec_addr32 = dfu_utils_buffer_parse_uint32 (in_buffer + offset + 4);
got_eof = TRUE; got_eof = TRUE;
break; break;
case '5': case '5':
rec_class = DFU_SREC_RECORD_CLASS_COUNT; rec_class = DFU_SREC_RECORD_CLASS_COUNT;
rec_datalen -= 2;
rec_addr32 = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 4); rec_addr32 = dfu_utils_buffer_parse_uint16 (in_buffer + offset + 4);
if (rec_addr32 != class_data_cnt) { if (rec_addr32 != class_data_cnt) {
g_set_error (error, g_set_error (error,
@ -262,8 +258,8 @@ dfu_image_from_srec (DfuImage *image,
g_debug ("ignoring data at 0x%x as before start address 0x%x", g_debug ("ignoring data at 0x%x as before start address 0x%x",
(guint) rec_addr32, (guint) start_addr); (guint) rec_addr32, (guint) start_addr);
} else { } else {
for (guint i = 0; i < rec_datalen; i++) { for (guint8 i = rec_dataoffset; i <= rec_count; i++) {
guint8 tmp = dfu_utils_buffer_parse_uint8 (in_buffer + offset + 8 + (i * 2)); guint8 tmp = dfu_utils_buffer_parse_uint8 (in_buffer + offset + (i * 2));
g_string_append_c (outbuf, tmp); g_string_append_c (outbuf, tmp);
} }
if (element_address == 0x0) if (element_address == 0x0)