summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Delvare <[email protected]>2018-08-01 09:54:51 +0200
committerJean Delvare <[email protected]>2018-08-01 09:54:51 +0200
commit4cbba9a8e76ffc640eaf7dd25acbd3c1c6504669 (patch)
tree7c5357f05790aeddd6b3b3de820da961d6d8a028
parent8ff32018e8dd53c26d1f0daef118037fdae58c68 (diff)
downloaddmidecode-4cbba9a8e76ffc640eaf7dd25acbd3c1c6504669.tar.gz
dmidecode: Validate structure completeness before decoding
Ensure that the whole DMI structure fits in the announced table length before performing any action on it. Otherwise we might end up reading beyond the end of our memory buffer. This bug was discovered by Lionel Debroux using the AFL fuzzer and AddressSanitizer. Its probability is very low, as it requires a DMI table corrupted in one of two very specific ways to trigger. This bug exists since dmidecode version 2.9, although it is hard to test because option --from-dump was only introduced in version 2.10. Signed-off-by: Jean Delvare <[email protected]>
-rw-r--r--dmidecode.c39
1 files changed, 22 insertions, 17 deletions
diff --git a/dmidecode.c b/dmidecode.c
index 474ca7b..76faed9 100644
--- a/dmidecode.c
+++ b/dmidecode.c
@@ -4754,6 +4754,7 @@ static void dmi_table_decode(u8 *buf, u32 len, u16 num, u16 ver, u32 flags)
}
break;
}
+ i++;
/* In quiet mode, stop decoding at end of table marker */
if ((opt.flags & FLAG_QUIET) && h.type == 127)
@@ -4764,6 +4765,22 @@ static void dmi_table_decode(u8 *buf, u32 len, u16 num, u16 ver, u32 flags)
printf("Handle 0x%04X, DMI type %d, %d bytes\n",
h.handle, h.type, h.length);
+ /* Look for the next handle */
+ next = data + h.length;
+ while ((unsigned long)(next - buf + 1) < len
+ && (next[0] != 0 || next[1] != 0))
+ next++;
+ next += 2;
+
+ /* Make sure the whole structure fits in the table */
+ if ((unsigned long)(next - buf) > len)
+ {
+ if (display && !(opt.flags & FLAG_QUIET))
+ printf("\t<TRUNCATED>\n\n");
+ data = next;
+ break;
+ }
+
/* assign vendor for vendor-specific decodes later */
if (h.type == 1 && h.length >= 5)
dmi_set_vendor(dmi_string(&h, data[0x04]));
@@ -4772,33 +4789,21 @@ static void dmi_table_decode(u8 *buf, u32 len, u16 num, u16 ver, u32 flags)
if (h.type == 34)
dmi_fixup_type_34(&h, display);
- /* look for the next handle */
- next = data + h.length;
- while ((unsigned long)(next - buf + 1) < len
- && (next[0] != 0 || next[1] != 0))
- next++;
- next += 2;
if (display)
{
- if ((unsigned long)(next - buf) <= len)
+ if (opt.flags & FLAG_DUMP)
{
- if (opt.flags & FLAG_DUMP)
- {
- dmi_dump(&h, "\t");
- printf("\n");
- }
- else
- dmi_decode(&h, ver);
+ dmi_dump(&h, "\t");
+ printf("\n");
}
- else if (!(opt.flags & FLAG_QUIET))
- printf("\t<TRUNCATED>\n\n");
+ else
+ dmi_decode(&h, ver);
}
else if (opt.string != NULL
&& opt.string->type == h.type)
dmi_table_string(&h, data, ver);
data = next;
- i++;
/* SMBIOS v3 requires stopping at this marker */
if (h.type == 127 && (flags & FLAG_STOP_AT_EOT))