Skip to content

Commit 5cc2d6c

Browse files
committed
Merge branch 'disallow-control-characters-in-sideband-channel'
This addresses: - CVE-2024-52005: Insufficient neutralization of ANSI escape sequences in sideband payload can be used to mislead Git users into believing that certain remote-generated messages actually originate from Git. Signed-off-by: Johannes Schindelin <[email protected]>
2 parents 63cab6a + 65896a3 commit 5cc2d6c

File tree

4 files changed

+124
-2
lines changed

4 files changed

+124
-2
lines changed

Documentation/config.txt

+2
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,8 @@ include::config/sequencer.txt[]
522522

523523
include::config/showbranch.txt[]
524524

525+
include::config/sideband.txt[]
526+
525527
include::config/sparse.txt[]
526528

527529
include::config/splitindex.txt[]

Documentation/config/sideband.txt

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
sideband.allowControlCharacters::
2+
By default, control characters that are delivered via the sideband
3+
are masked, except ANSI color sequences. This prevents potentially
4+
unwanted ANSI escape sequences from being sent to the terminal. Use
5+
this config setting to override this behavior:
6+
+
7+
--
8+
color::
9+
Allow ANSI color sequences, line feeds and horizontal tabs,
10+
but mask all other control characters. This is the default.
11+
false::
12+
Mask all control characters other than line feeds and
13+
horizontal tabs.
14+
true::
15+
Allow all control characters to be sent to the terminal.
16+
--

sideband.c

+76-2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ static struct keyword_entry keywords[] = {
2626
{ "error", GIT_COLOR_BOLD_RED },
2727
};
2828

29+
static enum {
30+
ALLOW_NO_CONTROL_CHARACTERS = 0,
31+
ALLOW_ALL_CONTROL_CHARACTERS = 1,
32+
ALLOW_ANSI_COLOR_SEQUENCES = 2
33+
} allow_control_characters = ALLOW_ANSI_COLOR_SEQUENCES;
34+
2935
/* Returns a color setting (GIT_COLOR_NEVER, etc). */
3036
static int use_sideband_colors(void)
3137
{
@@ -39,6 +45,25 @@ static int use_sideband_colors(void)
3945
if (use_sideband_colors_cached >= 0)
4046
return use_sideband_colors_cached;
4147

48+
switch (git_config_get_maybe_bool("sideband.allowcontrolcharacters", &i)) {
49+
case 0: /* Boolean value */
50+
allow_control_characters = i ? ALLOW_ALL_CONTROL_CHARACTERS :
51+
ALLOW_NO_CONTROL_CHARACTERS;
52+
break;
53+
case -1: /* non-Boolean value */
54+
if (git_config_get_string_tmp("sideband.allowcontrolcharacters",
55+
&value))
56+
; /* huh? `get_maybe_bool()` returned -1 */
57+
else if (!strcmp(value, "color"))
58+
allow_control_characters = ALLOW_ANSI_COLOR_SEQUENCES;
59+
else
60+
warning(_("unrecognized value for `sideband."
61+
"allowControlCharacters`: '%s'"), value);
62+
break;
63+
default:
64+
break; /* not configured */
65+
}
66+
4267
if (!git_config_get_string_tmp(key, &value))
4368
use_sideband_colors_cached = git_config_colorbool(key, value);
4469
else if (!git_config_get_string_tmp("color.ui", &value))
@@ -66,6 +91,55 @@ void list_config_color_sideband_slots(struct string_list *list, const char *pref
6691
list_config_item(list, prefix, keywords[i].keyword);
6792
}
6893

94+
static int handle_ansi_color_sequence(struct strbuf *dest, const char *src, int n)
95+
{
96+
int i;
97+
98+
/*
99+
* Valid ANSI color sequences are of the form
100+
*
101+
* ESC [ [<n> [; <n>]*] m
102+
*/
103+
104+
if (allow_control_characters != ALLOW_ANSI_COLOR_SEQUENCES ||
105+
n < 3 || src[0] != '\x1b' || src[1] != '[')
106+
return 0;
107+
108+
for (i = 2; i < n; i++) {
109+
if (src[i] == 'm') {
110+
strbuf_add(dest, src, i + 1);
111+
return i;
112+
}
113+
if (!isdigit(src[i]) && src[i] != ';')
114+
break;
115+
}
116+
117+
return 0;
118+
}
119+
120+
static void strbuf_add_sanitized(struct strbuf *dest, const char *src, int n)
121+
{
122+
int i;
123+
124+
if (allow_control_characters == ALLOW_ALL_CONTROL_CHARACTERS) {
125+
strbuf_add(dest, src, n);
126+
return;
127+
}
128+
129+
strbuf_grow(dest, n);
130+
for (; n && *src; src++, n--) {
131+
if (!iscntrl(*src) || *src == '\t' || *src == '\n')
132+
strbuf_addch(dest, *src);
133+
else if ((i = handle_ansi_color_sequence(dest, src, n))) {
134+
src += i;
135+
n -= i;
136+
} else {
137+
strbuf_addch(dest, '^');
138+
strbuf_addch(dest, 0x40 + *src);
139+
}
140+
}
141+
}
142+
69143
/*
70144
* Optionally highlight one keyword in remote output if it appears at the start
71145
* of the line. This should be called for a single line only, which is
@@ -81,7 +155,7 @@ static void maybe_colorize_sideband(struct strbuf *dest, const char *src, int n)
81155
int i;
82156

83157
if (!want_color_stderr(use_sideband_colors())) {
84-
strbuf_add(dest, src, n);
158+
strbuf_add_sanitized(dest, src, n);
85159
return;
86160
}
87161

@@ -114,7 +188,7 @@ static void maybe_colorize_sideband(struct strbuf *dest, const char *src, int n)
114188
}
115189
}
116190

117-
strbuf_add(dest, src, n);
191+
strbuf_add_sanitized(dest, src, n);
118192
}
119193

120194

t/t5409-colorize-remote-messages.sh

+30
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,34 @@ test_expect_success 'fallback to color.ui' '
9898
grep "<BOLD;RED>error<RESET>: error" decoded
9999
'
100100

101+
test_expect_success 'disallow (color) control sequences in sideband' '
102+
write_script .git/color-me-surprised <<-\EOF &&
103+
printf "error: Have you \\033[31mread\\033[m this?\\a\\n" >&2
104+
exec "$@"
105+
EOF
106+
test_config_global uploadPack.packObjectshook ./color-me-surprised &&
107+
test_commit need-at-least-one-commit &&
108+
109+
git clone --no-local . throw-away 2>stderr &&
110+
test_decode_color <stderr >decoded &&
111+
test_grep RED decoded &&
112+
test_grep "\\^G" stderr &&
113+
tr -dc "\\007" <stderr >actual &&
114+
test_must_be_empty actual &&
115+
116+
rm -rf throw-away &&
117+
git -c sideband.allowControlCharacters=false \
118+
clone --no-local . throw-away 2>stderr &&
119+
test_decode_color <stderr >decoded &&
120+
test_grep ! RED decoded &&
121+
test_grep "\\^G" stderr &&
122+
123+
rm -rf throw-away &&
124+
git -c sideband.allowControlCharacters clone --no-local . throw-away 2>stderr &&
125+
test_decode_color <stderr >decoded &&
126+
test_grep RED decoded &&
127+
tr -dc "\\007" <stderr >actual &&
128+
test_file_not_empty actual
129+
'
130+
101131
test_done

0 commit comments

Comments
 (0)