Commit message: None
CVE: CVE-2014-2013
CWE: CWE-119
Vulnerability description: Stack-based buffer overflow in the xps_parse_color function in xps/xps-common.c in MuPDF 1.3 and earlier allows remote attackers to execute arbitrary code via a large number of entries in the ContextColor value of the Fill attribute in a Path element.

Project: ghostscript
File: xps-common.c

xps_parse_matrix_transform(xps_document *doc, fz_xml *root, fz_matrix *matrix)
{
	char *transform;

	*matrix = fz_identity;

	if (!strcmp(fz_xml_tag(root), "MatrixTransform"))
	{
		transform = fz_xml_att(root, "Matrix");
		if (transform)
			xps_parse_render_transform(doc, transform, matrix);
	}
}

Project: ghostscript
File: xps-common.c

xps_parse_render_transform(xps_document *doc, char *transform, fz_matrix *matrix)
{
	float args[6];
	char *s = transform;
	int i;

	args[0] = 1; args[1] = 0;
	args[2] = 0; args[3] = 1;
	args[4] = 0; args[5] = 0;

	for (i = 0; i < 6 && *s; i++)
	{
		args[i] = fz_atof(s);
		while (*s && *s != ',')
			s++;
		if (*s == ',')
			s++;
	}

	matrix->a = args[0]; matrix->b = args[1];
	matrix->c = args[2]; matrix->d = args[3];
	matrix->e = args[4]; matrix->f = args[5];
}

Project: ghostscript
File: xps-glyphs.c

static inline int ishex(int a)
{
	return (a >= 'A' && a <= 'F') ||
		(a >= 'a' && a <= 'f') ||
		(a >= '0' && a <= '9');
}

Project: ghostscript
File: xps-gradient.c

xps_draw_one_radial_gradient(xps_document *doc, const fz_matrix *ctm,
	struct stop *stops, int count,
	int extend,
	float x0, float y0, float r0,
	float x1, float y1, float r1)
{
	fz_shade *shade;

	/* TODO: this (and the stuff in pdf_shade) should move to res_shade.c */
	shade = fz_malloc_struct(doc->ctx, fz_shade);
	FZ_INIT_STORABLE(shade, 1, fz_free_shade_imp);
	shade->colorspace = fz_device_rgb(doc->ctx);
	shade->bbox = fz_infinite_rect;
	shade->matrix = fz_identity;
	shade->use_background = 0;
	shade->use_function = 1;
	shade->type = FZ_RADIAL;
	shade->u.l_or_r.extend[0] = extend;
	shade->u.l_or_r.extend[1] = extend;

	xps_sample_gradient_stops(shade, stops, count);

	shade->u.l_or_r.coords[0][0] = x0;
	shade->u.l_or_r.coords[0][1] = y0;
	shade->u.l_or_r.coords[0][2] = r0;
	shade->u.l_or_r.coords[1][0] = x1;
	shade->u.l_or_r.coords[1][1] = y1;
	shade->u.l_or_r.coords[1][2] = r1;

	fz_fill_shade(doc->dev, shade, ctm, 1);

	fz_drop_shade(doc->ctx, shade);
}

Project: ghostscript
File: xps-gradient.c

xps_parse_radial_gradient_brush(xps_document *doc, const fz_matrix *ctm, const fz_rect *area,
	char *base_uri, xps_resource *dict, fz_xml *root)
{
	xps_parse_gradient_brush(doc, ctm, area, base_uri, dict, root, xps_draw_radial_gradient);
}

Project: ghostscript
File: xps-path.c

xps_clip(xps_document *doc, const fz_matrix *ctm, xps_resource *dict, char *clip_att, fz_xml *clip_tag)
{
	fz_path *path;
	int fill_rule = 0;

	if (clip_att)
		path = xps_parse_abbreviated_geometry(doc, clip_att, &fill_rule);
	else if (clip_tag)
		path = xps_parse_path_geometry(doc, dict, clip_tag, 0, &fill_rule);
	else
		path = fz_new_path(doc->ctx);
	fz_clip_path(doc->dev, path, NULL, fill_rule == 0, ctm);
	fz_free_path(doc->ctx, path);
}

Project: ghostscript
File: xps-path.c

xps_draw_arc(fz_context *doc, fz_path *path,
	float size_x, float size_y, float rotation_angle,
	int is_large_arc, int is_clockwise,
	float point_x, float point_y)
{
	fz_matrix rotmat, revmat;
	fz_matrix mtx;
	fz_point pt;
	float rx, ry;
	float x1, y1, x2, y2;
	float x1t, y1t;
	float cxt, cyt, cx, cy;
	float t1, t2, t3;
	float sign;
	float th1, dth;

	pt = fz_currentpoint(doc, path);
	x1 = pt.x;
	y1 = pt.y;
	x2 = point_x;
	y2 = point_y;
	rx = size_x;
	ry = size_y;

	if (is_clockwise != is_large_arc)
		sign = 1;
	else
		sign = -1;

	fz_rotate(&rotmat, rotation_angle);
	fz_rotate(&revmat, -rotation_angle);

	/* http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes */
	/* Conversion from endpoint to center parameterization */

	/* F.6.6.1 -- ensure radii are positive and non-zero */
	rx = fabsf(rx);
	ry = fabsf(ry);
	if (rx < 0.001f || ry < 0.001f || (x1 == x2 && y1 == y2))
	{
		fz_lineto(doc, path, x2, y2);
		return;
	}

	/* F.6.5.1 */
	pt.x = (x1 - x2) / 2;
	pt.y = (y1 - y2) / 2;
	fz_transform_vector(&pt, &revmat);
	x1t = pt.x;
	y1t = pt.y;

	/* F.6.6.2 -- ensure radii are large enough */
	t1 = (x1t * x1t) / (rx * rx) + (y1t * y1t) / (ry * ry);
	if (t1 > 1)
	{
		rx = rx * sqrtf(t1);
		ry = ry * sqrtf(t1);
	}

	/* F.6.5.2 */
	t1 = (rx * rx * ry * ry) - (rx * rx * y1t * y1t) - (ry * ry * x1t * x1t);
	t2 = (rx * rx * y1t * y1t) + (ry * ry * x1t * x1t);
	t3 = t1 / t2;
	/* guard against rounding errors; sqrt of negative numbers is bad for your health */
	if (t3 < 0) t3 = 0;
	t3 = sqrtf(t3);

	cxt = sign * t3 * (rx * y1t) / ry;
	cyt = sign * t3 * -(ry * x1t) / rx;

	/* F.6.5.3 */
	pt.x = cxt;
	pt.y = cyt;
	fz_transform_vector(&pt, &rotmat);
	cx = pt.x + (x1 + x2) / 2;
	cy = pt.y + (y1 + y2) / 2;

	/* F.6.5.4 */
	{
		fz_point coord1, coord2, coord3, coord4;
		coord1.x = 1;
		coord1.y = 0;
		coord2.x = (x1t - cxt) / rx;
		coord2.y = (y1t - cyt) / ry;
		coord3.x = (x1t - cxt) / rx;
		coord3.y = (y1t - cyt) / ry;
		coord4.x = (-x1t - cxt) / rx;
		coord4.y = (-y1t - cyt) / ry;
		th1 = angle_between(coord1, coord2);
		dth = angle_between(coord3, coord4);
		if (dth < 0 && !is_clockwise)
			dth += (((float)M_PI / 180) * 360);
		if (dth > 0 && is_clockwise)
			dth -= (((float)M_PI / 180) * 360);
	}

	fz_pre_scale(fz_pre_rotate(fz_translate(&mtx, cx, cy), rotation_angle), rx, ry);
	xps_draw_arc_segment(doc, path, &mtx, th1, th1 + dth, is_clockwise);

	fz_lineto(doc, path, point_x, point_y);
}

Project: ghostscript
File: xps-path.c

xps_parse_line_cap(char *attr)
{
	if (attr)
	{
		if (!strcmp(attr, "Flat")) return 0;
		if (!strcmp(attr, "Round")) return 1;
		if (!strcmp(attr, "Square")) return 2;
		if (!strcmp(attr, "Triangle")) return 3;
	}
	return 0;
}