Skip to content

Commit cbc8fee

Browse files
peffgitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 2b87d3a commit cbc8fee

File tree

1 file changed

+26
-15
lines changed

1 file changed

+26
-15
lines changed

color.c

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -150,22 +150,24 @@ int color_parse(const char *value, char *dst)
150150
* already have the ANSI escape code in it. "out" should have enough
151151
* space in it to fit any color.
152152
*/
153-
static char *color_output(char *out, const struct color *c, char type)
153+
static char *color_output(char *out, int len, const struct color *c, char type)
154154
{
155155
switch (c->type) {
156156
case COLOR_UNSPECIFIED:
157157
case COLOR_NORMAL:
158158
break;
159159
case COLOR_ANSI:
160+
if (len < 2)
161+
die("BUG: color parsing ran out of space");
160162
*out++ = type;
161163
*out++ = '0' + c->value;
162164
break;
163165
case COLOR_256:
164-
out += sprintf(out, "%c8;5;%d", type, c->value);
166+
out += xsnprintf(out, len, "%c8;5;%d", type, c->value);
165167
break;
166168
case COLOR_RGB:
167-
out += sprintf(out, "%c8;2;%d;%d;%d", type,
168-
c->red, c->green, c->blue);
169+
out += xsnprintf(out, len, "%c8;2;%d;%d;%d", type,
170+
c->red, c->green, c->blue);
169171
break;
170172
}
171173
return out;
@@ -180,12 +182,13 @@ int color_parse_mem(const char *value, int value_len, char *dst)
180182
{
181183
const char *ptr = value;
182184
int len = value_len;
185+
char *end = dst + COLOR_MAXLEN;
183186
unsigned int attr = 0;
184187
struct color fg = { COLOR_UNSPECIFIED };
185188
struct color bg = { COLOR_UNSPECIFIED };
186189

187190
if (!strncasecmp(value, "reset", len)) {
188-
strcpy(dst, GIT_COLOR_RESET);
191+
xsnprintf(dst, end - dst, GIT_COLOR_RESET);
189192
return 0;
190193
}
191194

@@ -224,40 +227,48 @@ int color_parse_mem(const char *value, int value_len, char *dst)
224227
goto bad;
225228
}
226229

230+
#undef OUT
231+
#define OUT(x) do { \
232+
if (dst == end) \
233+
die("BUG: color parsing ran out of space"); \
234+
*dst++ = (x); \
235+
} while(0)
236+
227237
if (attr || !color_empty(&fg) || !color_empty(&bg)) {
228238
int sep = 0;
229239
int i;
230240

231-
*dst++ = '\033';
232-
*dst++ = '[';
241+
OUT('\033');
242+
OUT('[');
233243

234244
for (i = 0; attr; i++) {
235245
unsigned bit = (1 << i);
236246
if (!(attr & bit))
237247
continue;
238248
attr &= ~bit;
239249
if (sep++)
240-
*dst++ = ';';
241-
dst += sprintf(dst, "%d", i);
250+
OUT(';');
251+
dst += xsnprintf(dst, end - dst, "%d", i);
242252
}
243253
if (!color_empty(&fg)) {
244254
if (sep++)
245-
*dst++ = ';';
255+
OUT(';');
246256
/* foreground colors are all in the 3x range */
247-
dst = color_output(dst, &fg, '3');
257+
dst = color_output(dst, end - dst, &fg, '3');
248258
}
249259
if (!color_empty(&bg)) {
250260
if (sep++)
251-
*dst++ = ';';
261+
OUT(';');
252262
/* background colors are all in the 4x range */
253-
dst = color_output(dst, &bg, '4');
263+
dst = color_output(dst, end - dst, &bg, '4');
254264
}
255-
*dst++ = 'm';
265+
OUT('m');
256266
}
257-
*dst = 0;
267+
OUT(0);
258268
return 0;
259269
bad:
260270
return error(_("invalid color value: %.*s"), value_len, value);
271+
#undef OUT
261272
}
262273

263274
int git_config_colorbool(const char *var, const char *value)

0 commit comments

Comments
 (0)