1
0
mirror of https://github.com/git/git.git synced 2024-09-21 12:02:17 +02:00

color: add overflow checks for parsing colors

Our color parsing is designed to never exceed COLOR_MAXLEN
bytes. But the relationship between that hand-computed
number and the parsing code is not at all obvious, and we
merely hope that it has been computed correctly for all
cases.

Let's mark the expected "end" pointer for the destination
buffer and make sure that we do not exceed it.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Jeff King 2015-09-24 17:08:07 -04:00 committed by Junio C Hamano
parent 2b87d3a896
commit cbc8feeaf9

41
color.c
View File

@ -150,22 +150,24 @@ int color_parse(const char *value, char *dst)
* already have the ANSI escape code in it. "out" should have enough * already have the ANSI escape code in it. "out" should have enough
* space in it to fit any color. * space in it to fit any color.
*/ */
static char *color_output(char *out, const struct color *c, char type) static char *color_output(char *out, int len, const struct color *c, char type)
{ {
switch (c->type) { switch (c->type) {
case COLOR_UNSPECIFIED: case COLOR_UNSPECIFIED:
case COLOR_NORMAL: case COLOR_NORMAL:
break; break;
case COLOR_ANSI: case COLOR_ANSI:
if (len < 2)
die("BUG: color parsing ran out of space");
*out++ = type; *out++ = type;
*out++ = '0' + c->value; *out++ = '0' + c->value;
break; break;
case COLOR_256: case COLOR_256:
out += sprintf(out, "%c8;5;%d", type, c->value); out += xsnprintf(out, len, "%c8;5;%d", type, c->value);
break; break;
case COLOR_RGB: case COLOR_RGB:
out += sprintf(out, "%c8;2;%d;%d;%d", type, out += xsnprintf(out, len, "%c8;2;%d;%d;%d", type,
c->red, c->green, c->blue); c->red, c->green, c->blue);
break; break;
} }
return out; return out;
@ -180,12 +182,13 @@ int color_parse_mem(const char *value, int value_len, char *dst)
{ {
const char *ptr = value; const char *ptr = value;
int len = value_len; int len = value_len;
char *end = dst + COLOR_MAXLEN;
unsigned int attr = 0; unsigned int attr = 0;
struct color fg = { COLOR_UNSPECIFIED }; struct color fg = { COLOR_UNSPECIFIED };
struct color bg = { COLOR_UNSPECIFIED }; struct color bg = { COLOR_UNSPECIFIED };
if (!strncasecmp(value, "reset", len)) { if (!strncasecmp(value, "reset", len)) {
strcpy(dst, GIT_COLOR_RESET); xsnprintf(dst, end - dst, GIT_COLOR_RESET);
return 0; return 0;
} }
@ -224,12 +227,19 @@ int color_parse_mem(const char *value, int value_len, char *dst)
goto bad; goto bad;
} }
#undef OUT
#define OUT(x) do { \
if (dst == end) \
die("BUG: color parsing ran out of space"); \
*dst++ = (x); \
} while(0)
if (attr || !color_empty(&fg) || !color_empty(&bg)) { if (attr || !color_empty(&fg) || !color_empty(&bg)) {
int sep = 0; int sep = 0;
int i; int i;
*dst++ = '\033'; OUT('\033');
*dst++ = '['; OUT('[');
for (i = 0; attr; i++) { for (i = 0; attr; i++) {
unsigned bit = (1 << i); unsigned bit = (1 << i);
@ -237,27 +247,28 @@ int color_parse_mem(const char *value, int value_len, char *dst)
continue; continue;
attr &= ~bit; attr &= ~bit;
if (sep++) if (sep++)
*dst++ = ';'; OUT(';');
dst += sprintf(dst, "%d", i); dst += xsnprintf(dst, end - dst, "%d", i);
} }
if (!color_empty(&fg)) { if (!color_empty(&fg)) {
if (sep++) if (sep++)
*dst++ = ';'; OUT(';');
/* foreground colors are all in the 3x range */ /* foreground colors are all in the 3x range */
dst = color_output(dst, &fg, '3'); dst = color_output(dst, end - dst, &fg, '3');
} }
if (!color_empty(&bg)) { if (!color_empty(&bg)) {
if (sep++) if (sep++)
*dst++ = ';'; OUT(';');
/* background colors are all in the 4x range */ /* background colors are all in the 4x range */
dst = color_output(dst, &bg, '4'); dst = color_output(dst, end - dst, &bg, '4');
} }
*dst++ = 'm'; OUT('m');
} }
*dst = 0; OUT(0);
return 0; return 0;
bad: bad:
return error(_("invalid color value: %.*s"), value_len, value); return error(_("invalid color value: %.*s"), value_len, value);
#undef OUT
} }
int git_config_colorbool(const char *var, const char *value) int git_config_colorbool(const char *var, const char *value)