Skip to content

Commit 528290f

Browse files
ttaylorrdscho
authored andcommitted
Merge branch 'tb/config-copy-or-rename-in-file-injection'
Avoids issues with renaming or deleting sections with long lines, where configuration values may be interpreted as sections, leading to configuration injection. Addresses CVE-2023-29007. * tb/config-copy-or-rename-in-file-injection: config.c: disallow overly-long lines in `copy_or_rename_section_in_file()` config.c: avoid integer truncation in `copy_or_rename_section_in_file()` config: avoid fixed-sized buffer when renaming/deleting a section t1300: demonstrate failure when renaming sections with long lines Signed-off-by: Taylor Blau <[email protected]>
2 parents 4fe5d0b + 3bb3d6b commit 528290f

File tree

2 files changed

+55
-11
lines changed

2 files changed

+55
-11
lines changed

config.c

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3027,9 +3027,10 @@ void git_config_set_multivar(const char *key, const char *value,
30273027
flags);
30283028
}
30293029

3030-
static int section_name_match (const char *buf, const char *name)
3030+
static size_t section_name_match (const char *buf, const char *name)
30313031
{
3032-
int i = 0, j = 0, dot = 0;
3032+
size_t i = 0, j = 0;
3033+
int dot = 0;
30333034
if (buf[i] != '[')
30343035
return 0;
30353036
for (i = 1; buf[i] && buf[i] != ']'; i++) {
@@ -3082,6 +3083,8 @@ static int section_name_is_ok(const char *name)
30823083
return 1;
30833084
}
30843085

3086+
#define GIT_CONFIG_MAX_LINE_LEN (512 * 1024)
3087+
30853088
/* if new_name == NULL, the section is removed instead */
30863089
static int git_config_copy_or_rename_section_in_file(const char *config_filename,
30873090
const char *old_name,
@@ -3091,11 +3094,12 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
30913094
char *filename_buf = NULL;
30923095
struct lock_file lock = LOCK_INIT;
30933096
int out_fd;
3094-
char buf[1024];
3097+
struct strbuf buf = STRBUF_INIT;
30953098
FILE *config_file = NULL;
30963099
struct stat st;
30973100
struct strbuf copystr = STRBUF_INIT;
30983101
struct config_store_data store;
3102+
uint32_t line_nr = 0;
30993103

31003104
memset(&store, 0, sizeof(store));
31013105

@@ -3132,16 +3136,25 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
31323136
goto out;
31333137
}
31343138

3135-
while (fgets(buf, sizeof(buf), config_file)) {
3136-
unsigned i;
3137-
int length;
3139+
while (!strbuf_getwholeline(&buf, config_file, '\n')) {
3140+
size_t i, length;
31383141
int is_section = 0;
3139-
char *output = buf;
3140-
for (i = 0; buf[i] && isspace(buf[i]); i++)
3142+
char *output = buf.buf;
3143+
3144+
line_nr++;
3145+
3146+
if (buf.len >= GIT_CONFIG_MAX_LINE_LEN) {
3147+
ret = error(_("refusing to work with overly long line "
3148+
"in '%s' on line %"PRIuMAX),
3149+
config_filename, (uintmax_t)line_nr);
3150+
goto out;
3151+
}
3152+
3153+
for (i = 0; buf.buf[i] && isspace(buf.buf[i]); i++)
31413154
; /* do nothing */
3142-
if (buf[i] == '[') {
3155+
if (buf.buf[i] == '[') {
31433156
/* it's a section */
3144-
int offset;
3157+
size_t offset;
31453158
is_section = 1;
31463159

31473160
/*
@@ -3158,7 +3171,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
31583171
strbuf_reset(&copystr);
31593172
}
31603173

3161-
offset = section_name_match(&buf[i], old_name);
3174+
offset = section_name_match(&buf.buf[i], old_name);
31623175
if (offset > 0) {
31633176
ret++;
31643177
if (new_name == NULL) {
@@ -3233,6 +3246,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
32333246
out_no_rollback:
32343247
free(filename_buf);
32353248
config_store_data_clear(&store);
3249+
strbuf_release(&buf);
32363250
return ret;
32373251
}
32383252

t/t1300-config.sh

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,36 @@ test_expect_success 'renaming to bogus section is rejected' '
613613
test_must_fail git config --rename-section branch.zwei "bogus name"
614614
'
615615

616+
test_expect_success 'renaming a section with a long line' '
617+
{
618+
printf "[b]\\n" &&
619+
printf " c = d %1024s [a] e = f\\n" " " &&
620+
printf "[a] g = h\\n"
621+
} >y &&
622+
git config -f y --rename-section a xyz &&
623+
test_must_fail git config -f y b.e
624+
'
625+
626+
test_expect_success 'renaming an embedded section with a long line' '
627+
{
628+
printf "[b]\\n" &&
629+
printf " c = d %1024s [a] [foo] e = f\\n" " " &&
630+
printf "[a] g = h\\n"
631+
} >y &&
632+
git config -f y --rename-section a xyz &&
633+
test_must_fail git config -f y foo.e
634+
'
635+
636+
test_expect_success 'renaming a section with an overly-long line' '
637+
{
638+
printf "[b]\\n" &&
639+
printf " c = d %525000s e" " " &&
640+
printf "[a] g = h\\n"
641+
} >y &&
642+
test_must_fail git config -f y --rename-section a xyz 2>err &&
643+
test_i18ngrep "refusing to work with overly long line in .y. on line 2" err
644+
'
645+
616646
cat >> .git/config << EOF
617647
[branch "zwei"] a = 1 [branch "vier"]
618648
EOF

0 commit comments

Comments
 (0)