summaryrefslogtreecommitdiff
path: root/src/cairo-type1-subset.c
diff options
context:
space:
mode:
authorUli Schlachter <psychon@znc.in>2021-04-11 16:35:02 +0000
committerHeiko Lewin <hlewin@gmx.de>2021-04-11 16:35:02 +0000
commit1484cfa55146cf6c77f8ad60911f999ead0c12ff (patch)
treeb65bf1768ed550c22cb09866bec049b865d81f44 /src/cairo-type1-subset.c
parent26663cf3be1d7f67b49aa02428d7e303b7286f98 (diff)
downloadcairo-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.c26
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 {