Commit message: None
CVE: CVE-2013-6462
CWE: CWE-119
Vulnerability description: Stack-based buffer overflow in the bdfReadCharacters function in bitmap/bdfread.c in X.Org libXfont 1.1 through 1.4.6 allows remote attackers to cause a denial of service (crash) or possibly execute arbitrary code via a long string in a character name in a BDF font file.

Project: libxfont

bdfFreeFontBits(FontPtr pFont)
{
    BitmapFontPtr  bitmapFont;
    BitmapExtraPtr bitmapExtra;
    int         i, nencoding;

    bitmapFont = (BitmapFontPtr) pFont->fontPrivate;
    bitmapExtra = (BitmapExtraPtr) bitmapFont->bitmapExtra;
    free(bitmapFont->ink_metrics);
    if(bitmapFont->encoding) {
        nencoding = (pFont->info.lastCol - pFont->info.firstCol + 1) *
	    (pFont->info.lastRow - pFont->info.firstRow + 1);
        for(i=0; i<NUM_SEGMENTS(nencoding); i++)
            free(bitmapFont->encoding[i]);
    }
    free(bitmapFont->encoding);
    for (i = 0; i < bitmapFont->num_chars; i++)
	free(bitmapFont->metrics[i].bits);
    free(bitmapFont->metrics);
    if (bitmapExtra)
    {
	free (bitmapExtra->glyphNames);
	free (bitmapExtra->sWidths);
	free (bitmapExtra);
    }
    free(pFont->info.props);
    free(bitmapFont);
}

Project: libxfont

bdfPadToTerminal(FontPtr pFont)
{
    BitmapFontPtr  bitmapFont;
    BitmapExtraPtr bitmapExtra;
    int         i;
    int         new_size;
    CharInfoRec new;
    int         w,
                h;

    bitmapFont = (BitmapFontPtr) pFont->fontPrivate;

    bzero(&new, sizeof(CharInfoRec));
    new.metrics.ascent = pFont->info.fontAscent;
    new.metrics.descent = pFont->info.fontDescent;
    new.metrics.leftSideBearing = 0;
    new.metrics.rightSideBearing = pFont->info.minbounds.characterWidth;
    new.metrics.characterWidth = new.metrics.rightSideBearing;
    new_size = BYTES_FOR_GLYPH(&new, pFont->glyph);

    for (i = 0; i < bitmapFont->num_chars; i++) {
	new.bits = malloc(new_size);
	if (!new.bits) {
          bdfError("Couldn't allocate bits (%d)\n", new_size);
	    return FALSE;
	}
	FontCharReshape(pFont, &bitmapFont->metrics[i], &new);
        new.metrics.attributes = bitmapFont->metrics[i].metrics.attributes;
	free(bitmapFont->metrics[i].bits);
	bitmapFont->metrics[i] = new;
    }
    bitmapExtra = bitmapFont->bitmapExtra;
    if (bitmapExtra) {
	w = GLYPHWIDTHPIXELS(&new);
	h = GLYPHHEIGHTPIXELS(&new);
	for (i = 0; i < GLYPHPADOPTIONS; i++)
	    bitmapExtra->bitmapsSizes[i] = bitmapFont->num_chars *
		(BYTES_PER_ROW(w, 1 << i) * h);
    }
    return TRUE;
}

Project: libxfont

bdfReadBitmap(CharInfoPtr pCI, FontFilePtr file, int bit, int byte,
	      int glyph, int scan, CARD32 *sizes)
{
    int         widthBits,
                widthBytes,
                widthHexChars;
    int         height,
                row;
    int         i,
                inLineLen,
                nextByte;
    unsigned char *pInBits,
               *picture,
               *line = NULL;
    unsigned char        lineBuf[BDFLINELEN];

    widthBits = GLYPHWIDTHPIXELS(pCI);
    height = GLYPHHEIGHTPIXELS(pCI);

    widthBytes = BYTES_PER_ROW(widthBits, glyph);
    if (widthBytes * height > 0) {
	picture = malloc(widthBytes * height);
	if (!picture) {
          bdfError("Couldn't allocate picture (%d*%d)\n", widthBytes, height);
	    goto BAILOUT;
      }
    } else
	picture = NULL;
    pCI->bits = (char *) picture;

    if (sizes) {
	for (i = 0; i < GLYPHPADOPTIONS; i++)
	    sizes[i] += BYTES_PER_ROW(widthBits, (1 << i)) * height;
    }
    nextByte = 0;
    widthHexChars = BYTES_PER_ROW(widthBits, 1);

/* 5/31/89 (ef) -- hack, hack, hack.  what *am* I supposed to do with */
/*		0 width characters? */

    for (row = 0; row < height; row++) {
	line = bdfGetLine(file, lineBuf, BDFLINELEN);
	if (!line)
	    break;

	if (widthBits == 0) {
	    if ((!line) || (bdfIsPrefix(line, "ENDCHAR")))
		break;
	    else
		continue;
	}
	pInBits = line;
	inLineLen = strlen((char *) pInBits);

	if (inLineLen & 1) {
	    bdfError("odd number of characters in hex encoding\n");
	    line[inLineLen++] = '0';
	    line[inLineLen] = '\0';
	}
	inLineLen >>= 1;
	i = inLineLen;
	if (i > widthHexChars)
	    i = widthHexChars;
	for (; i > 0; i--, pInBits += 2)
	    picture[nextByte++] = bdfHexByte(pInBits);

	/* pad if line is too short */
	if (inLineLen < widthHexChars) {
	    for (i = widthHexChars - inLineLen; i > 0; i--)
		picture[nextByte++] = 0;
	} else {
	    unsigned char mask;

	    mask = 0xff << (8 - (widthBits & 0x7));
	    if (mask && picture[nextByte - 1] & ~mask) {
		picture[nextByte - 1] &= mask;
	    }
	}

	if (widthBytes > widthHexChars) {
	    i = widthBytes - widthHexChars;
	    while (i-- > 0)
		picture[nextByte++] = 0;
	}
    }

    if ((line && (!bdfIsPrefix(line, "ENDCHAR"))) || (height == 0))
	line = bdfGetLine(file, lineBuf, BDFLINELEN);

    if ((!line) || (!bdfIsPrefix(line, "ENDCHAR"))) {
	bdfError("missing 'ENDCHAR'\n");
	goto BAILOUT;
    }
    if (nextByte != height * widthBytes) {
	bdfError("bytes != rows * bytes_per_row (%d != %d * %d)\n",
		 nextByte, height, widthBytes);
	goto BAILOUT;
    }
    if (picture != NULL) {
	if (bit == LSBFirst)
	    BitOrderInvert(picture, nextByte);
	if (bit != byte) {
	    if (scan == 2)
		TwoByteSwap(picture, nextByte);
	    else if (scan == 4)
		FourByteSwap(picture, nextByte);
	}
    }
    return (TRUE);
BAILOUT:
    if (picture)
	free(picture);
    pCI->bits = NULL;
    return (FALSE);
}

Project: libxfont

bdfReadFont(FontPtr pFont, FontFilePtr file,
	    int bit, int byte, int glyph, int scan)
{
    bdfFileState state;
    xCharInfo  *min,
               *max;
    BitmapFontPtr  bitmapFont;

    pFont->fontPrivate = 0;

    bzero(&state, sizeof(bdfFileState));
    bdfFileLineNum = 0;

    if (!bdfReadHeader(file, &state))
	goto BAILOUT;

    bitmapFont = calloc(1, sizeof(BitmapFontRec));
    if (!bitmapFont) {
	bdfError("Couldn't allocate bitmapFontRec (%d)\n",
		 (int) sizeof(BitmapFontRec));
	goto BAILOUT;
    }

    pFont->fontPrivate = (pointer) bitmapFont;
    bitmapFont->metrics = 0;
    bitmapFont->ink_metrics = 0;
    bitmapFont->bitmaps = 0;
    bitmapFont->encoding = 0;
    bitmapFont->pDefault = NULL;

    bitmapFont->bitmapExtra = calloc(1, sizeof(BitmapExtraRec));
    if (!bitmapFont->bitmapExtra) {
	bdfError("Couldn't allocate bitmapExtra (%d)\n",
		 (int) sizeof(BitmapExtraRec));
        goto BAILOUT;
    }

    bitmapFont->bitmapExtra->glyphNames = 0;
    bitmapFont->bitmapExtra->sWidths = 0;

    if (!bdfReadProperties(file, pFont, &state))
	goto BAILOUT;

    if (!bdfReadCharacters(file, pFont, &state, bit, byte, glyph, scan))
	goto BAILOUT;

    if (state.haveDefaultCh) {
	unsigned int r, c, cols;

	r = pFont->info.defaultCh >> 8;
	c = pFont->info.defaultCh & 0xFF;
	if (pFont->info.firstRow <= r && r <= pFont->info.lastRow &&
		pFont->info.firstCol <= c && c <= pFont->info.lastCol) {
	    cols = pFont->info.lastCol - pFont->info.firstCol + 1;
	    r = r - pFont->info.firstRow;
	    c = c - pFont->info.firstCol;
	    bitmapFont->pDefault = ACCESSENCODING(bitmapFont->encoding,
                                                 r * cols + c);
	}
    }
    pFont->bit = bit;
    pFont->byte = byte;
    pFont->glyph = glyph;
    pFont->scan = scan;
    pFont->info.anamorphic = FALSE;
    pFont->info.cachable = TRUE;
    bitmapComputeFontBounds(pFont);
    if (FontCouldBeTerminal(&pFont->info)) {
	bdfPadToTerminal(pFont);
	bitmapComputeFontBounds(pFont);
    }
    FontComputeInfoAccelerators(&pFont->info);
    if (bitmapFont->bitmapExtra)
	FontComputeInfoAccelerators(&bitmapFont->bitmapExtra->info);
    if (pFont->info.constantMetrics) {
      if (!bitmapAddInkMetrics(pFont)) {
        bdfError("Failed to add bitmap ink metrics\n");
        goto BAILOUT;
      }
    }
    if (bitmapFont->bitmapExtra)
	bitmapFont->bitmapExtra->info.inkMetrics = pFont->info.inkMetrics;

    bitmapComputeFontInkBounds(pFont);
/*    ComputeFontAccelerators (pFont); */

    /* generate properties */
    min = &pFont->info.ink_minbounds;
    max = &pFont->info.ink_maxbounds;
    if (state.xHeightProp && (state.xHeightProp->value == -1))
	state.xHeightProp->value = state.exHeight ?
	    state.exHeight : min->ascent;

    if (state.quadWidthProp && (state.quadWidthProp->value == -1))
	state.quadWidthProp->value = state.digitCount ?
	    (INT32) (state.digitWidths / state.digitCount) :
	    (min->characterWidth + max->characterWidth) / 2;

    if (state.weightProp && (state.weightProp->value == -1))
	state.weightProp->value = bitmapComputeWeight(pFont);

    pFont->get_glyphs = bitmapGetGlyphs;
    pFont->get_metrics = bitmapGetMetrics;
    pFont->unload_font = bdfUnloadFont;
    pFont->unload_glyphs = NULL;
    return Successful;
BAILOUT:
    if (pFont->fontPrivate)
	bdfFreeFontBits (pFont);
    return AllocError;
}

Project: libxfont

bdfReadHeader(FontFilePtr file, bdfFileState *pState)
{
    unsigned char *line;
    char        namebuf[BDFLINELEN];
    unsigned char        lineBuf[BDFLINELEN];

    line = bdfGetLine(file, lineBuf, BDFLINELEN);
    if (!line || sscanf((char *) line, "STARTFONT %s", namebuf) != 1 ||
	    !bdfStrEqual(namebuf, "2.1")) {
	bdfError("bad 'STARTFONT'\n");
	return (FALSE);
    }
    line = bdfGetLine(file, lineBuf, BDFLINELEN);
    if (!line || sscanf((char *) line, "FONT %[^\n]", pState->fontName) != 1) {
	bdfError("bad 'FONT'\n");
	return (FALSE);
    }
    line = bdfGetLine(file, lineBuf, BDFLINELEN);
    if (!line || !bdfIsPrefix(line, "SIZE")) {
	bdfError("missing 'SIZE'\n");
	return (FALSE);
    }
    if (sscanf((char *) line, "SIZE %f%d%d", &pState->pointSize,
	       &pState->resolution_x, &pState->resolution_y) != 3) {
	bdfError("bad 'SIZE'\n");
	return (FALSE);
    }
    if (pState->pointSize < 1 ||
	pState->resolution_x < 1 || pState->resolution_y < 1) {
	bdfError("SIZE values must be > 0\n");
	return (FALSE);
    }
    line = bdfGetLine(file, lineBuf, BDFLINELEN);
    if (!line || !bdfIsPrefix(line, "FONTBOUNDINGBOX")) {
	bdfError("missing 'FONTBOUNDINGBOX'\n");
	return (FALSE);
    }
    return (TRUE);
}

Project: libxfont

bdfReadProperties(FontFilePtr file, FontPtr pFont, bdfFileState *pState)
{
    int         nProps, props_left,
                nextProp;
    char       *stringProps;
    FontPropPtr props;
    char        namebuf[BDFLINELEN],
                secondbuf[BDFLINELEN],
                thirdbuf[BDFLINELEN];
    unsigned char *line;
    unsigned char        lineBuf[BDFLINELEN];
    BitmapFontPtr  bitmapFont = (BitmapFontPtr) pFont->fontPrivate;

    line = bdfGetLine(file, lineBuf, BDFLINELEN);
    if (!line || !bdfIsPrefix(line, "STARTPROPERTIES")) {
	bdfError("missing 'STARTPROPERTIES'\n");
	return (FALSE);
    }
    if (sscanf((char *) line, "STARTPROPERTIES %d", &nProps) != 1) {
	bdfError("bad 'STARTPROPERTIES'\n");
	return (FALSE);
    }
    pFont->info.isStringProp = NULL;
    pFont->info.props = NULL;
    pFont->info.nprops = 0;

    stringProps = malloc((nProps + BDF_GENPROPS) * sizeof(char));
    pFont->info.isStringProp = stringProps;
    if (stringProps == NULL) {
	bdfError("Couldn't allocate stringProps (%d*%d)\n",
		 (nProps + BDF_GENPROPS), (int) sizeof(Bool));
	goto BAILOUT;
    }
    pFont->info.props = props = calloc(nProps + BDF_GENPROPS,
				       sizeof(FontPropRec));
    if (props == NULL) {
	bdfError("Couldn't allocate props (%d*%d)\n", nProps + BDF_GENPROPS,
						   (int) sizeof(FontPropRec));
	goto BAILOUT;
    }

    nextProp = 0;
    props_left = nProps;
    while (props_left-- > 0) {
	line = bdfGetLine(file, lineBuf, BDFLINELEN);
	if (line == NULL || bdfIsPrefix(line, "ENDPROPERTIES")) {
	    bdfError("\"STARTPROPERTIES %d\" followed by only %d properties\n",
		     nProps, nProps - props_left - 1);
	    goto BAILOUT;
	}
	while (*line && isspace(*line))
	    line++;

	switch (sscanf((char *) line, "%s%s%s", namebuf, secondbuf, thirdbuf)) {
	default:
	    bdfError("missing '%s' parameter value\n", namebuf);
	    goto BAILOUT;

	case 2:
	    /*
	     * Possibilites include: valid quoted string with no white space
	     * valid integer value invalid value
	     */
	    if (secondbuf[0] == '"') {
		stringProps[nextProp] = TRUE;
		props[nextProp].value =
		    bdfGetPropertyValue((char *)line + strlen(namebuf) + 1);
		if (!props[nextProp].value)
		    goto BAILOUT;
		break;
	    } else if (bdfIsInteger(secondbuf)) {
		stringProps[nextProp] = FALSE;
		props[nextProp].value = atoi(secondbuf);
		break;
	    } else {
		bdfError("invalid '%s' parameter value\n", namebuf);
		goto BAILOUT;
	    }

	case 3:
	    /*
	     * Possibilites include: valid quoted string with some white space
	     * invalid value (reject even if second string is integer)
	     */
	    if (secondbuf[0] == '"') {
		stringProps[nextProp] = TRUE;
		props[nextProp].value =
		    bdfGetPropertyValue((char *)line + strlen(namebuf) + 1);
		if (!props[nextProp].value)
		    goto BAILOUT;
		break;
	    } else {
		bdfError("invalid '%s' parameter value\n", namebuf);
		goto BAILOUT;
	    }
	}
	props[nextProp].name = bdfForceMakeAtom(namebuf, NULL);
	if (props[nextProp].name == None) {
	    bdfError("Empty property name.\n");
	    goto BAILOUT;
	}
	if (!bdfSpecialProperty(pFont, &props[nextProp],
				stringProps[nextProp], pState))
	    nextProp++;
    }

    line = bdfGetLine(file, lineBuf, BDFLINELEN);
    if (!line || !bdfIsPrefix(line, "ENDPROPERTIES")) {
	bdfError("missing 'ENDPROPERTIES'\n");
	goto BAILOUT;
    }
    if (!pState->haveFontAscent || !pState->haveFontDescent) {
	bdfError("missing 'FONT_ASCENT' or 'FONT_DESCENT' properties\n");
	goto BAILOUT;
    }
    if (bitmapFont->bitmapExtra) {
	bitmapFont->bitmapExtra->info.fontAscent = pFont->info.fontAscent;
	bitmapFont->bitmapExtra->info.fontDescent = pFont->info.fontDescent;
    }
    if (!pState->pointSizeProp) {
	props[nextProp].name = bdfForceMakeAtom("POINT_SIZE", NULL);
	props[nextProp].value = (INT32) (pState->pointSize * 10.0);
	stringProps[nextProp] = FALSE;
	pState->pointSizeProp = &props[nextProp];
	nextProp++;
    }
    if (!pState->fontProp) {
	props[nextProp].name = bdfForceMakeAtom("FONT", NULL);
	props[nextProp].value = (INT32) bdfForceMakeAtom(pState->fontName, NULL);
	stringProps[nextProp] = TRUE;
	pState->fontProp = &props[nextProp];
	nextProp++;
    }
    if (!pState->weightProp) {
	props[nextProp].name = bdfForceMakeAtom("WEIGHT", NULL);
	props[nextProp].value = -1;	/* computed later */
	stringProps[nextProp] = FALSE;
	pState->weightProp = &props[nextProp];
	nextProp++;
    }
    if (!pState->resolutionProp &&
	pState->resolution_x == pState->resolution_y) {
	props[nextProp].name = bdfForceMakeAtom("RESOLUTION", NULL);
	props[nextProp].value = (INT32) ((pState->resolution_x * 100.0) / 72.27);
	stringProps[nextProp] = FALSE;
	pState->resolutionProp = &props[nextProp];
	nextProp++;
    }
    if (!pState->resolutionXProp) {
	props[nextProp].name = bdfForceMakeAtom("RESOLUTION_X", NULL);
	props[nextProp].value = (INT32) pState->resolution_x;
	stringProps[nextProp] = FALSE;
	pState->resolutionProp = &props[nextProp];
	nextProp++;
    }
    if (!pState->resolutionYProp) {
	props[nextProp].name = bdfForceMakeAtom("RESOLUTION_Y", NULL);
	props[nextProp].value = (INT32) pState->resolution_y;
	stringProps[nextProp] = FALSE;
	pState->resolutionProp = &props[nextProp];
	nextProp++;
    }
    if (!pState->xHeightProp) {
	props[nextProp].name = bdfForceMakeAtom("X_HEIGHT", NULL);
	props[nextProp].value = -1;	/* computed later */
	stringProps[nextProp] = FALSE;
	pState->xHeightProp = &props[nextProp];
	nextProp++;
    }
    if (!pState->quadWidthProp) {
	props[nextProp].name = bdfForceMakeAtom("QUAD_WIDTH", NULL);
	props[nextProp].value = -1;	/* computed later */
	stringProps[nextProp] = FALSE;
	pState->quadWidthProp = &props[nextProp];
	nextProp++;
    }
    pFont->info.nprops = nextProp;
    return (TRUE);
BAILOUT:
    if (pFont->info.isStringProp) {
	free(pFont->info.isStringProp);
	pFont->info.isStringProp = NULL;
    }
    if (pFont->info.props) {
	free(pFont->info.props);
	pFont->info.props = NULL;
    }
    while (line && bdfIsPrefix(line, "ENDPROPERTIES"))
	line = bdfGetLine(file, lineBuf, BDFLINELEN);
    return (FALSE);
}

Project: libxfont

bdfSkipBitmap(FontFilePtr file, int height)
{
    unsigned char *line;
    int         i = 0;
    unsigned char        lineBuf[BDFLINELEN];

    do {
	line = bdfGetLine(file, lineBuf, BDFLINELEN);
	i++;
    } while (line && !bdfIsPrefix(line, "ENDCHAR") && i <= height);

    if (i > 1 && line && !bdfIsPrefix(line, "ENDCHAR")) {
	bdfError("Error in bitmap, missing 'ENDCHAR'\n");
	return (FALSE);
    }
    return (TRUE);
}