diff options
author | Uli Schlachter <psychon@znc.in> | 2022-07-07 17:30:15 +0200 |
---|---|---|
committer | Uli Schlachter <psychon@znc.in> | 2022-07-07 17:30:15 +0200 |
commit | 53faf76e577c5f08b4fec6bbd5a2a871834ba597 (patch) | |
tree | 7fe0d52e652d62ede6b97b73260ba24ca132d18d /src/cairo-truetype-subset.c | |
parent | 2ff9afb73751ccf9b1c13d78dad00b7a7dccc9b9 (diff) | |
download | cairo-53faf76e577c5f08b4fec6bbd5a2a871834ba597.tar.gz |
Fix issue 579
cairo-trutype-subset.c would blindly trust a font saying that its name
list has thousands of entries. This commit changes find_name() to also
get the size of the input memory region and to do some bounds checking
on its memory accesses.
Fixes: https://gitlab.freedesktop.org/cairo/cairo/-/issues/579
Signed-off-by: Uli Schlachter <psychon@znc.in>
Diffstat (limited to 'src/cairo-truetype-subset.c')
-rw-r--r-- | src/cairo-truetype-subset.c | 28 |
1 files changed, 16 insertions, 12 deletions
diff --git a/src/cairo-truetype-subset.c b/src/cairo-truetype-subset.c index efb67f9a6..c58b96665 100644 --- a/src/cairo-truetype-subset.c +++ b/src/cairo-truetype-subset.c @@ -1442,17 +1442,17 @@ cleanup: #define MAX_FONT_NAME_LENGTH 127 static cairo_status_t -find_name (tt_name_t *name, int name_id, int platform, int encoding, int language, char **str_out) +find_name (tt_name_t *name, unsigned long size, int name_id, int platform, int encoding, int language, char **str_out) { tt_name_record_t *record; - int i, len; + unsigned int i, len; char *str; char *p; cairo_bool_t has_tag; cairo_status_t status; str = NULL; - for (i = 0; i < be16_to_cpu (name->num_records); i++) { + for (i = 0; i < MIN(be16_to_cpu (name->num_records), size / sizeof(name->records[0])); i++) { record = &(name->records[i]); if (be16_to_cpu (record->name) == name_id && be16_to_cpu (record->platform) == platform && @@ -1466,14 +1466,18 @@ find_name (tt_name_t *name, int name_id, int platform, int encoding, int languag if (len > MAX_FONT_NAME_LENGTH) break; + uint16_t offset = be16_to_cpu (name->strings_offset) + be16_to_cpu (record->offset); + if (offset + len > size) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + str = _cairo_malloc (len + 1); if (str == NULL) return _cairo_error (CAIRO_STATUS_NO_MEMORY); memcpy (str, - ((char*)name) + be16_to_cpu (name->strings_offset) + be16_to_cpu (record->offset), + ((char*)name) + offset, len); - str[be16_to_cpu (record->length)] = 0; + str[len] = 0; break; } } @@ -1487,7 +1491,7 @@ find_name (tt_name_t *name, int name_id, int platform, int encoding, int languag int size = 0; char *utf8; uint16_t *u = (uint16_t *) str; - int u_len = len/2; + unsigned int u_len = len/2; for (i = 0; i < u_len; i++) size += _cairo_ucs4_to_utf8 (be16_to_cpu(u[i]), NULL); @@ -1585,35 +1589,35 @@ _cairo_truetype_read_font_name (cairo_scaled_font_t *scaled_font, /* Find PS Name (name_id = 6). OT spec says PS name must be one of * the following two encodings */ - status = find_name (name, 6, 3, 1, 0x409, &ps_name); /* win, unicode, english-us */ + status = find_name (name, size, 6, 3, 1, 0x409, &ps_name); /* win, unicode, english-us */ if (unlikely(status)) goto fail; if (!ps_name) { - status = find_name (name, 6, 1, 0, 0, &ps_name); /* mac, roman, english */ + status = find_name (name, size, 6, 1, 0, 0, &ps_name); /* mac, roman, english */ if (unlikely(status)) goto fail; } /* Find Family name (name_id = 1) */ - status = find_name (name, 1, 3, 1, 0x409, &family_name); /* win, unicode, english-us */ + status = find_name (name, size, 1, 3, 1, 0x409, &family_name); /* win, unicode, english-us */ if (unlikely(status)) goto fail; if (!family_name) { - status = find_name (name, 1, 3, 0, 0x409, &family_name); /* win, symbol, english-us */ + status = find_name (name, size, 1, 3, 0, 0x409, &family_name); /* win, symbol, english-us */ if (unlikely(status)) goto fail; } if (!family_name) { - status = find_name (name, 1, 1, 0, 0, &family_name); /* mac, roman, english */ + status = find_name (name, size, 1, 1, 0, 0, &family_name); /* mac, roman, english */ if (unlikely(status)) goto fail; } if (!family_name) { - status = find_name (name, 1, 3, 1, -1, &family_name); /* win, unicode, any language */ + status = find_name (name, size, 1, 3, 1, -1, &family_name); /* win, unicode, any language */ if (unlikely(status)) goto fail; } |