diff options
author | Uli Schlachter <psychon@znc.in> | 2021-04-11 16:35:02 +0000 |
---|---|---|
committer | Heiko Lewin <hlewin@gmx.de> | 2021-04-11 16:35:02 +0000 |
commit | 1484cfa55146cf6c77f8ad60911f999ead0c12ff (patch) | |
tree | b65bf1768ed550c22cb09866bec049b865d81f44 /src/cairo-type1-subset.c | |
parent | 26663cf3be1d7f67b49aa02428d7e303b7286f98 (diff) | |
download | cairo-1484cfa55146cf6c77f8ad60911f999ead0c12ff.tar.gz |
Fix out of bounds access in cairo_type1_font_subset_find_segments
This function parses some raw font data and it trusts the font to be
well-formed. This means that a font can just say "this segment is a
gigabyte large" and the code will happily jump ahead in memory. Bad
things then happen in practice.
Fix this by adding lots of bounds check.
Also, an existing bounds check makes sure we are still before the end of
the data, but then happily reads the next six bytes. Fix this by making
sure we actually have six bytes of data.
No regression test since the last few times I tried to do this for font
issues, I ended up with a large/huge blob of font data. Too large for
the test suite.
Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=27969
Signed-off-by: Uli Schlachter <psychon@znc.in>
Diffstat (limited to 'src/cairo-type1-subset.c')
-rw-r--r-- | src/cairo-type1-subset.c | 26 |
1 files changed, 16 insertions, 10 deletions
diff --git a/src/cairo-type1-subset.c b/src/cairo-type1-subset.c index 2f04c8e10..a51e34f62 100644 --- a/src/cairo-type1-subset.c +++ b/src/cairo-type1-subset.c @@ -121,15 +121,15 @@ typedef struct _cairo_type1_font_subset { char *type1_end; char *header_segment; - int header_segment_size; + unsigned int header_segment_size; char *eexec_segment; - int eexec_segment_size; + unsigned int eexec_segment_size; cairo_bool_t eexec_segment_is_ascii; char *cleartext; char *cleartext_end; - int header_size; + unsigned int header_size; unsigned short eexec_key; cairo_bool_t hex_encode; @@ -216,25 +216,31 @@ cairo_type1_font_subset_find_segments (cairo_type1_font_subset_t *font) { unsigned char *p; const char *eexec_token; - int size, i; + unsigned int size, i; p = (unsigned char *) font->type1_data; font->type1_end = font->type1_data + font->type1_length; - if (p[0] == 0x80 && p[1] == 0x01) { + if (font->type1_length >= 2 && p[0] == 0x80 && p[1] == 0x01) { + if (font->type1_end < (char *)(p + 6)) + return CAIRO_INT_STATUS_UNSUPPORTED; font->header_segment_size = - p[2] | (p[3] << 8) | (p[4] << 16) | ((uint32_t)p[5] << 24); + p[2] | (p[3] << 8) | (p[4] << 16) | ((unsigned int) p[5] << 24); font->header_segment = (char *) p + 6; p += 6 + font->header_segment_size; + if (font->type1_end < (char *)(p + 6)) + return CAIRO_INT_STATUS_UNSUPPORTED; font->eexec_segment_size = - p[2] | (p[3] << 8) | (p[4] << 16) | ((uint32_t)p[5] << 24); + p[2] | (p[3] << 8) | (p[4] << 16) | ((unsigned int) p[5] << 24); font->eexec_segment = (char *) p + 6; font->eexec_segment_is_ascii = (p[1] == 1); p += 6 + font->eexec_segment_size; - while (p < (unsigned char *) (font->type1_end) && p[1] != 0x03) { - size = p[2] | (p[3] << 8) | (p[4] << 16) | ((uint32_t)p[5] << 24); - p += 6 + size; + while (font->type1_end >= (char *)(p + 6) && p[1] != 0x03) { + size = p[2] | (p[3] << 8) | (p[4] << 16) | ((unsigned int) p[5] << 24); + if (font->type1_end < (char *)(p + 6 + size)) + return CAIRO_INT_STATUS_UNSUPPORTED; + p += 6 + size; } font->type1_end = (char *) p; } else { |