diff -up ./config.c.original ./config.c --- ./config.c.original 2023-05-18 15:11:28.221121569 +0900 +++ ./config.c 2023-05-18 15:24:30.178828343 +0900 @@ -1701,6 +1701,8 @@ static int section_name_is_ok(const char return 1; } +#define GIT_CONFIG_MAX_LINE_LEN (512 * 1024) + /* if new_name == NULL, the section is removed instead */ int git_config_rename_section_in_file(const char *config_filename, const char *old_name, const char *new_name) @@ -1709,8 +1711,9 @@ int git_config_rename_section_in_file(co char *filename_buf = NULL; struct lock_file *lock; int out_fd; - char buf[1024]; + struct strbuf buf = STRBUF_INIT; FILE *config_file; + uint32_t line_nr = 0; if (new_name && !section_name_is_ok(new_name)) { ret = error("invalid section name: %s", new_name); @@ -1732,15 +1735,25 @@ int git_config_rename_section_in_file(co goto unlock_and_out; } - while (fgets(buf, sizeof(buf), config_file)) { + while (!strbuf_getwholeline(&buf, config_file, '\n')) { int i; int length; - char *output = buf; - for (i = 0; buf[i] && isspace(buf[i]); i++) + char *output = buf.buf; + + line_nr++; + + if (buf.len >= GIT_CONFIG_MAX_LINE_LEN) { + ret = error(_("refusing to work with overly long line " + "in '%s' on line %"PRIuMAX), + config_filename, (uintmax_t)line_nr); + goto out; + } + + for (i = 0; buf.buf[i] && isspace(buf.buf[i]); i++) ; /* do nothing */ - if (buf[i] == '[') { + if (buf.buf[i] == '[') { /* it's a section */ - int offset = section_name_match(&buf[i], old_name); + int offset = section_name_match(&buf.buf[i], old_name); if (offset > 0) { ret++; if (new_name == NULL) { @@ -1785,6 +1798,7 @@ unlock_and_out: ret = error("could not commit config file %s", config_filename); out: free(filename_buf); + strbuf_release(&buf); return ret; } diff -up ./t/t1300-repo-config.sh.original ./t/t1300-repo-config.sh --- ./t/t1300-repo-config.sh.original 2023-05-18 15:17:53.636877440 +0900 +++ ./t/t1300-repo-config.sh 2023-05-18 15:25:16.931647850 +0900 @@ -1122,4 +1122,34 @@ test_expect_failure 'adding a key into a test_cmp expect .git/config ' +test_expect_success 'renaming a section with a long line' ' + { + printf "[b]\\n" && + printf " c = d %1024s [a] e = f\\n" " " && + printf "[a] g = h\\n" + } >y && + git config -f y --rename-section a xyz && + test_must_fail git config -f y b.e +' + +test_expect_success 'renaming an embedded section with a long line' ' + { + printf "[b]\\n" && + printf " c = d %1024s [a] [foo] e = f\\n" " " && + printf "[a] g = h\\n" + } >y && + git config -f y --rename-section a xyz && + test_must_fail git config -f y foo.e +' + +test_expect_success 'renaming a section with an overly-long line' ' + { + printf "[b]\\n" && + printf " c = d %525000s e" " " && + printf "[a] g = h\\n" + } >y && + test_must_fail git config -f y --rename-section a xyz 2>err && + test_i18ngrep "refusing to work with overly long line in .y. on line 2" err +' + test_done