From 8328a88016a1c371f40ee280386c4db473df0630 Mon Sep 17 00:00:00 2001 From: giraffedata Date: Fri, 11 Aug 2017 02:23:00 +0000 Subject: Fix buffer overflow in font routines, recognize width=0, height=0 glyphs as valid space glyphs, limit size of glyphs, improve handling of font files corrupt at the beginning git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@3042 9d0c8265-081b-0410-96cb-a4ca84ce46f8 --- doc/HISTORY | 9 +++++++ generator/pbmtext.c | 36 +++++++++++++++------------- lib/libpbmfont.c | 69 ++++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 82 insertions(+), 32 deletions(-) diff --git a/doc/HISTORY b/doc/HISTORY index b4da4c58..05cf713a 100644 --- a/doc/HISTORY +++ b/doc/HISTORY @@ -6,10 +6,19 @@ CHANGE HISTORY not yet BJH Release 10.80.00 + pbmtext, libnetpbm font facilities: allow glyphs in font files + that have no bitmap data; just used for their advance value to + code a space. + + libnetpbm font facilities: consider font invalid if a glyph is + more than 65536 pixels high or wide. + ppmshadow: handle images with a black background and low contrast images (i.e. little difference between foreground and background). + libnetpbm: font facilities: fix invalid memory reference. + libnetpbm: ppm_readcolordict: Improve error message when there is a problem reading the color dictionary. Affects ppmhist. diff --git a/generator/pbmtext.c b/generator/pbmtext.c index 357f0429..80fecdd5 100644 --- a/generator/pbmtext.c +++ b/generator/pbmtext.c @@ -538,22 +538,26 @@ insertCharacter(const struct glyph * const glyphP, Insert one character (whose glyph is 'glyph') into the image bits[]. Its top left corner shall be row 'toprow', column 'leftcol'. -----------------------------------------------------------------------------*/ - unsigned int glyph_y; /* Y position within the glyph */ - - if (leftcol + glyphP->x < 0 || - leftcol + glyphP->x + glyphP->width > cols || - toprow < 0 || - toprow + glyphP->height >rows ) - pm_error("internal error. Rendering out of bounds"); - - for (glyph_y = 0; glyph_y < glyphP->height; ++glyph_y) { - unsigned int glyph_x; /* position within the glyph */ - - for (glyph_x = 0; glyph_x < glyphP->width; ++glyph_x) { - if (glyphP->bmap[glyph_y * glyphP->width + glyph_x]) { - unsigned int const col = leftcol + glyphP->x + glyph_x; - bits[toprow+glyph_y][col/8] |= PBM_BLACK << (7-col%8); - } + if (glyphP->width == 0 && glyphP->height == 0) { + /* No bitmap data. Some BDF files code space this way */ + } else { + unsigned int glyph_y; /* Y position within the glyph */ + + if (leftcol + glyphP->x < 0 || + leftcol + glyphP->x + glyphP->width > cols || + toprow < 0 || + toprow + glyphP->height >rows ) + pm_error("internal error. Rendering out of bounds"); + + for (glyph_y = 0; glyph_y < glyphP->height; ++glyph_y) { + unsigned int glyph_x; /* position within the glyph */ + + for (glyph_x = 0; glyph_x < glyphP->width; ++glyph_x) { + if (glyphP->bmap[glyph_y * glyphP->width + glyph_x]) { + unsigned int const col = leftcol + glyphP->x + glyph_x; + bits[toprow+glyph_y][col/8] |= PBM_BLACK << (7-col%8); + } + } } } } diff --git a/lib/libpbmfont.c b/lib/libpbmfont.c index 5193cd35..4c6ab1e2 100644 --- a/lib/libpbmfont.c +++ b/lib/libpbmfont.c @@ -307,10 +307,13 @@ pbm_loadfont(const char * const filename) { FILE * fileP; struct font * fontP; - char line[256]; + char line[10] = "\0\0\0\0\0\0\0\0\0\0"; + /* Initialize to suppress Valgrind error which is reported when file + is empty or very small. + */ fileP = pm_openr(filename); - fgets(line, 256, fileP); + fgets(line, 10, fileP); pm_close(fileP); if (line[0] == PBM_MAGIC1 && @@ -339,8 +342,23 @@ pbm_loadpbmfont(const char * const filename) { int fcols, frows; ifP = pm_openr(filename); + font = pbm_readpbm(ifP, &fcols, &frows); + + if ((fcols - 1) / 16 >= pbm_maxfontwidth() || + (frows - 1) / 12 >= pbm_maxfontheight()) + pm_error("Absurdly large PBM font file: %s", filename); + else if (fcols < 31 || frows < 23) { + /* Need at least one pixel per character, and this is too small to + have that. + */ + pm_error("PBM font file '%s' too small to be a font file: %u x %u. " + "Minimum sensible size is 31 x 23", + filename, fcols, frows); + } + pm_close(ifP); + return pbm_dissectfont((const bit **)font, frows, fcols); } @@ -406,10 +424,18 @@ pbm_dumpfont(struct font * const fontP, } +/*---------------------------------------------------------------------------- + Routines for loading a BDF font file +-----------------------------------------------------------------------------*/ + + +/* The following do not work: + Vertical writing systems: DWIDTH1, SWIDTH1, VVECTOR + global DWIDTH +*/ -/* Routines for loading a BDF font file */ -#define MAXBDFLINE 1024 +#define MAXBDFLINE 1024 /* Official Adobe document says max length of string is 65535 characters. However the value 1024 is sufficient for practical uses. @@ -428,7 +454,7 @@ typedef struct { It also functions as a work area for readline_read(). */ - const char * arg[32]; + const char * arg[6]; /* These are the words; each entry is a pointer into line[] (above) */ } Readline; @@ -448,15 +474,17 @@ readline_init(Readline * const readlineP, static void tokenize(char * const s, const char ** const words, - unsigned int const maxWordCt) { + unsigned int const wordsSz) { /*---------------------------------------------------------------------------- - Chop up 's' into words by changing space characters to NUL. Return - as 'words' pointer to the beginning of those words in 's'. + Chop up 's' into words by changing space characters to NUL. Return as + 'words' an array of pointers to the beginnings of those words in 's'. + Terminate the words[] list with a null pointer. - If there are more than 'maxWordCt' words in 's', ignore the excess on - the right. + 'wordsSz' is the number of elements of space in 'words'. If there are more + words in 's' than will fit in that space (including the terminating null + pointer), ignore the excess on the right. -----------------------------------------------------------------------------*/ - unsigned int n; + unsigned int n; /* Number of words in words[] so far */ char * p; p = &s[0]; @@ -467,12 +495,13 @@ tokenize(char * const s, *p++ = '\0'; else { words[n++] = p; - if (n >= maxWordCt) + if (n >= wordsSz - 1) break; while (*p && !ISSPACE(*p)) ++p; } } + assert(n <= wordsSz - 1); words[n] = NULL; } @@ -634,6 +663,9 @@ createBmap(unsigned int const glyphWidth, "BDF font file."); if (streq(readlineP->arg[0], "ATTRIBUTES")) { + /* ATTRIBUTES is defined in Glyph Bitmap Distribution Format (BDF) + Specification Version 2.1, but not in Version 2.2. + */ bool eof; readline_read(readlineP, &eof); if (eof) @@ -754,7 +786,7 @@ readEncoding(Readline * const readlineP, static void validateFontLimits(const struct font * const fontP) { - assert( pbm_maxfontheight() > 0 && pbm_maxfontwidth() > 0 ); + assert(pbm_maxfontheight() > 0 && pbm_maxfontwidth() > 0); if (fontP->maxwidth <= 0 || fontP->maxheight <= 0 || @@ -765,7 +797,7 @@ validateFontLimits(const struct font * const fontP) { fontP->x > fontP->maxwidth || fontP->y > fontP->maxheight || fontP->x + fontP->maxwidth > pbm_maxfontwidth() || - fontP->y + fontP->maxheight > pbm_maxfontheight() + fontP->y + fontP->maxheight > pbm_maxfontheight() ) { pm_error("Global font metric(s) out of bounds.\n"); @@ -779,8 +811,13 @@ validateGlyphLimits(const struct font * const fontP, const struct glyph * const glyphP, const char * const charName) { - if (glyphP->width == 0 || - glyphP->height == 0 || + /* Some BDF files code space with zero width and height, + no bitmap data and just the xadd value. + We allow zero width and height, iff both are zero. + */ + + if (((glyphP->width == 0 || glyphP->height == 0) && + !(glyphP->width == 0 && glyphP->height == 0)) || glyphP->width > fontP->maxwidth || glyphP->height > fontP->maxheight || glyphP->x < fontP->x || -- cgit 1.4.1