diff --git a/0001-git-svn-control-destruction-order-to-avoid-segfault.patch b/0001-git-svn-control-destruction-order-to-avoid-segfault.patch new file mode 100644 index 0000000..8518dd5 --- /dev/null +++ b/0001-git-svn-control-destruction-order-to-avoid-segfault.patch @@ -0,0 +1,40 @@ +From 7f6f75e97acd25f8e95ce431e16d2e1c2093845d Mon Sep 17 00:00:00 2001 +From: Eric Wong +Date: Mon, 29 Jan 2018 23:11:07 +0000 +Subject: [PATCH] git-svn: control destruction order to avoid segfault + +It seems necessary to control destruction ordering to avoid a +segfault with SVN 1.9.5 when using "git svn branch". I've also +reported the problem against libsvn-perl to Debian [Bug #888791], +but releasing the SVN::Client instance can be beneficial anyways to +save memory. + +ref: https://bugs.debian.org/888791 +Tested-by: Todd Zullinger +Reported-by: brian m. carlson +Signed-off-by: Eric Wong +Signed-off-by: Junio C Hamano +Signed-off-by: Todd Zullinger +--- + git-svn.perl | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/git-svn.perl b/git-svn.perl +index aa242d4f4f..b012980246 100755 +--- a/git-svn.perl ++++ b/git-svn.perl +@@ -1199,6 +1199,11 @@ sub cmd_branch { + $ctx->copy($src, $rev, $dst) + unless $_dry_run; + ++ # Release resources held by ctx before creating another SVN::Ra ++ # so destruction is orderly. This seems necessary with SVN 1.9.5 ++ # to avoid segfaults. ++ $ctx = undef; ++ + $gs->fetch_all; + } + +-- +2.16.1 + diff --git a/0001-revision-quit-pruning-diff-more-quickly-when-possibl.patch b/0001-revision-quit-pruning-diff-more-quickly-when-possibl.patch new file mode 100644 index 0000000..7b686c4 --- /dev/null +++ b/0001-revision-quit-pruning-diff-more-quickly-when-possibl.patch @@ -0,0 +1,129 @@ +From 8d9fe98846cf5533cb2488c22046ad934c7d24d8 Mon Sep 17 00:00:00 2001 +From: Jeff King +Date: Fri, 13 Oct 2017 11:27:45 -0400 +Subject: [PATCH] revision: quit pruning diff more quickly when possible + +When the revision traversal machinery is given a pathspec, +we must compute the parent-diff for each commit to determine +which ones are TREESAME. We set the QUICK diff flag to avoid +looking at more entries than we need; we really just care +whether there are any changes at all. + +But there is one case where we want to know a bit more: if +--remove-empty is set, we care about finding cases where the +change consists only of added entries (in which case we may +prune the parent in try_to_simplify_commit()). To cover that +case, our file_add_remove() callback does not quit the diff +upon seeing an added entry; it keeps looking for other types +of entries. + +But this means when --remove-empty is not set (and it is not +by default), we compute more of the diff than is necessary. +You can see this in a pathological case where a commit adds +a very large number of entries, and we limit based on a +broad pathspec. E.g.: + + perl -e ' + chomp(my $blob = `git hash-object -w --stdin remove_empty_trees. This callback parameter could be +passed to the "add_remove" and "change" callbacks, but +there's not much point. They already receive the +diff_options struct, and doing it this way avoids having to +update the function signature of the other callbacks +(arguably the format_callback and output_prefix functions +could benefit from the same simplification). + +Signed-off-by: Jeff King +Signed-off-by: Junio C Hamano +(cherry picked from commit a937b37e766479c8e780b17cce9c4b252fd97e40) +--- + diff.h | 1 + + revision.c | 16 +++++++++++++--- + 2 files changed, 14 insertions(+), 3 deletions(-) + +diff --git a/diff.h b/diff.h +index 5be1ee77a7..a2e76b6d26 100644 +--- a/diff.h ++++ b/diff.h +@@ -180,6 +180,7 @@ struct diff_options { + pathchange_fn_t pathchange; + change_fn_t change; + add_remove_fn_t add_remove; ++ void *change_fn_data; + diff_format_fn_t format_callback; + void *format_callback_data; + diff_prefix_fn_t output_prefix; +diff --git a/revision.c b/revision.c +index 5dfb322ccd..45654204f3 100644 +--- a/revision.c ++++ b/revision.c +@@ -394,8 +394,16 @@ static struct commit *one_relevant_parent(const struct rev_info *revs, + * if the whole diff is removal of old data, and otherwise + * REV_TREE_DIFFERENT (of course if the trees are the same we + * want REV_TREE_SAME). +- * That means that once we get to REV_TREE_DIFFERENT, we do not +- * have to look any further. ++ * ++ * The only time we care about the distinction is when ++ * remove_empty_trees is in effect, in which case we care only about ++ * whether the whole change is REV_TREE_NEW, or if there's another type ++ * of change. Which means we can stop the diff early in either of these ++ * cases: ++ * ++ * 1. We're not using remove_empty_trees at all. ++ * ++ * 2. We saw anything except REV_TREE_NEW. + */ + static int tree_difference = REV_TREE_SAME; + +@@ -406,9 +414,10 @@ static void file_add_remove(struct diff_options *options, + const char *fullpath, unsigned dirty_submodule) + { + int diff = addremove == '+' ? REV_TREE_NEW : REV_TREE_OLD; ++ struct rev_info *revs = options->change_fn_data; + + tree_difference |= diff; +- if (tree_difference == REV_TREE_DIFFERENT) ++ if (!revs->remove_empty_trees || tree_difference != REV_TREE_NEW) + DIFF_OPT_SET(options, HAS_CHANGES); + } + +@@ -1346,6 +1355,7 @@ void init_revisions(struct rev_info *revs, const char *prefix) + DIFF_OPT_SET(&revs->pruning, QUICK); + revs->pruning.add_remove = file_add_remove; + revs->pruning.change = file_change; ++ revs->pruning.change_fn_data = revs; + revs->sort_order = REV_SORT_IN_GRAPH_ORDER; + revs->dense = 1; + revs->prefix = prefix; +-- +2.15.0 + diff --git a/git.spec b/git.spec index ba54484..ff2bff6 100644 --- a/git.spec +++ b/git.spec @@ -44,8 +44,8 @@ %endif Name: git -Version: 2.13.4 -Release: 1%{?dist} +Version: 2.13.6 +Release: 3%{?dist} Summary: Fast Version Control System License: GPLv2 Group: Development/Tools @@ -75,6 +75,14 @@ Source16: git.socket Patch0: git-1.8-gitweb-home-link.patch # https://bugzilla.redhat.com/490602 Patch1: git-cvsimport-Ignore-cvsps-2.2b1-Branches-output.patch +Patch2: worktree-config.patch + +# https://bugzilla.redhat.com/1510455 (CVE-2017-15298) +# https://github.com/git/git/commit/a937b37e76 +Patch3: 0001-revision-quit-pruning-diff-more-quickly-when-possibl.patch + +# https://github.com/git/git/commit/7f6f75e97a +Patch4: 0001-git-svn-control-destruction-order-to-avoid-segfault.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -346,6 +354,9 @@ rm -rf "$tar" "$gpghome" # Cleanup tar files and tmp gpg home dir %setup -q %patch0 -p1 %patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 # Remove git-archimport from command list sed -i '/^git-archimport/d' command-list.txt @@ -726,6 +737,23 @@ rm -rf %{buildroot} # No files for you! %changelog +* Fri Feb 16 2018 Todd Zullinger - 2.13.6-3 +- git-svn: avoid segfaults in 'git svn branch' + +* Tue Nov 07 2017 Todd Zullinger - 2.13.6-2 +- Fix git-clone memory exhaustion (CVE-2017-15298) + Resolves: #1510455, #1510457 + +* Tue Sep 26 2017 Todd Zullinger - 2.13.6-1 +- Update to 2.13.6 + +* Wed Sep 06 2017 Petr Stodulka - 2.13.5-2 +- Process local aliases under linked worktree + Resolves: #1488133 + +* Thu Aug 10 2017 Todd Zullinger - 2.13.5-1 +- Update to 2.13.5 (resolves CVE-2017-1000117) + * Tue Aug 01 2017 Todd Zullinger - 2.13.4-1 - Update to 2.13.4 - Remove EL-5 and old Fedora conditionals diff --git a/sources b/sources index fbf1068..1e33410 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (git-2.13.4.tar.sign) = 0849c3a861d632d7413a788913af7e4537c6329535c734b75072e6c3587800addb6ab7be6ea550f46e4c17b717a1bbcc44493292bd1b53b54ab7195d2bc9e2d2 -SHA512 (git-2.13.4.tar.xz) = dbe6c08a6cb4931f0d1c16dabc23595c8e328a397552817ceb29cb1bf38f546e3a6ec9943db06e3adb39b15772f9e79e94c08fb4cd1f1807663602cb132983f5 +SHA512 (git-2.13.6.tar.xz) = ed39784205e1077f886eebdfb34a205fb0433071de29f673a79ea32bca31a2ba9bdabba208c9679ea2f6f295bafad52a7e7852b5bd2ccb1e6c99a1d2e76e8ada +SHA512 (git-2.13.6.tar.sign) = d7839b3d1ac9343f7424fea248370ec09a8ec362cb3aa65b987d295c6bab415f3cfb00b8c70d4d323612105d377c68c51d402d79a3a1a604e5ebe9eba6d8d23c diff --git a/worktree-config.patch b/worktree-config.patch new file mode 100644 index 0000000..9e5714d --- /dev/null +++ b/worktree-config.patch @@ -0,0 +1,191 @@ +diff --git a/builtin/config.c b/builtin/config.c +index 7f6c25d..5065d70 100644 +--- a/builtin/config.c ++++ b/builtin/config.c +@@ -538,6 +538,10 @@ int cmd_config(int argc, const char **argv, const char *prefix) + config_options.respect_includes = !given_config_source.file; + else + config_options.respect_includes = respect_includes_opt; ++ if (!nongit) { ++ config_options.commondir = get_git_common_dir(); ++ config_options.git_dir = get_git_dir(); ++ } + + if (end_null) { + term = '\0'; +diff --git a/cache.h b/cache.h +index c1041cc..804bb6c 100644 +--- a/cache.h ++++ b/cache.h +@@ -525,12 +525,15 @@ extern void set_git_work_tree(const char *tree); + + extern void setup_work_tree(void); + /* +- * Find GIT_DIR of the repository that contains the current working directory, +- * without changing the working directory or other global state. The result is +- * appended to gitdir. The return value is either NULL if no repository was +- * found, or pointing to the path inside gitdir's buffer. +- */ +-extern const char *discover_git_directory(struct strbuf *gitdir); ++ * Find the commondir and gitdir of the repository that contains the current ++ * working directory, without changing the working directory or other global ++ * state. The result is appended to commondir and gitdir. If the discovered ++ * gitdir does not correspond to a worktree, then 'commondir' and 'gitdir' will ++ * both have the same result appended to the buffer. The return value is ++ * either 0 upon success and non-zero if no repository was found. ++ */ ++extern int discover_git_directory(struct strbuf *commondir, ++ struct strbuf *gitdir); + extern const char *setup_git_directory_gently(int *); + extern const char *setup_git_directory(void); + extern char *prefix_path(const char *prefix, int len, const char *path); +@@ -1908,6 +1911,7 @@ enum config_origin_type { + + struct config_options { + unsigned int respect_includes : 1; ++ const char *commondir; + const char *git_dir; + }; + +diff --git a/config.c b/config.c +index f0511e5..54f869a 100644 +--- a/config.c ++++ b/config.c +@@ -217,8 +217,6 @@ static int include_by_gitdir(const struct config_options *opts, + + if (opts->git_dir) + git_dir = opts->git_dir; +- else if (have_git_dir()) +- git_dir = get_git_dir(); + else + goto done; + +@@ -1530,10 +1528,8 @@ static int do_git_config_sequence(const struct config_options *opts, + char *user_config = expand_user_path("~/.gitconfig", 0); + char *repo_config; + +- if (opts->git_dir) +- repo_config = mkpathdup("%s/config", opts->git_dir); +- else if (have_git_dir()) +- repo_config = git_pathdup("config"); ++ if (opts->commondir) ++ repo_config = mkpathdup("%s/config", opts->commondir); + else + repo_config = NULL; + +@@ -1597,6 +1593,11 @@ static void git_config_raw(config_fn_t fn, void *data) + struct config_options opts = {0}; + + opts.respect_includes = 1; ++ if (have_git_dir()) { ++ opts.commondir = get_git_common_dir(); ++ opts.git_dir = get_git_dir(); ++ } ++ + if (git_config_with_options(fn, data, NULL, &opts) < 0) + /* + * git_config_with_options() normally returns only +@@ -1638,11 +1639,13 @@ static void configset_iter(struct config_set *cs, config_fn_t fn, void *data) + void read_early_config(config_fn_t cb, void *data) + { + struct config_options opts = {0}; +- struct strbuf buf = STRBUF_INIT; ++ struct strbuf commondir = STRBUF_INIT; ++ struct strbuf gitdir = STRBUF_INIT; + + opts.respect_includes = 1; + +- if (have_git_dir()) ++ if (have_git_dir()) { ++ opts.commondir = get_git_common_dir(); + opts.git_dir = get_git_dir(); + /* + * When setup_git_directory() was not yet asked to discover the +@@ -1652,12 +1655,15 @@ void read_early_config(config_fn_t cb, void *data) + * notably, the current working directory is still the same after the + * call). + */ +- else if (discover_git_directory(&buf)) +- opts.git_dir = buf.buf; ++ } else if (!discover_git_directory(&commondir, &gitdir)) { ++ opts.commondir = commondir.buf; ++ opts.git_dir = gitdir.buf; ++ } + + git_config_with_options(cb, data, NULL, &opts); + +- strbuf_release(&buf); ++ strbuf_release(&commondir); ++ strbuf_release(&gitdir); + } + + static void git_config_check_init(void); +diff --git a/environment.c b/environment.c +index 1f0bda5..aa478e7 100644 +--- a/environment.c ++++ b/environment.c +@@ -217,6 +217,8 @@ const char *get_git_dir(void) + + const char *get_git_common_dir(void) + { ++ if (!git_dir) ++ setup_git_env(); + return git_common_dir; + } + +diff --git a/setup.c b/setup.c +index 2435186..beb335c 100644 +--- a/setup.c ++++ b/setup.c +@@ -945,19 +945,21 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir, + } + } + +-const char *discover_git_directory(struct strbuf *gitdir) ++int discover_git_directory(struct strbuf *commondir, ++ struct strbuf *gitdir) + { + struct strbuf dir = STRBUF_INIT, err = STRBUF_INIT; + size_t gitdir_offset = gitdir->len, cwd_len; ++ size_t commondir_offset = commondir->len; + struct repository_format candidate; + + if (strbuf_getcwd(&dir)) +- return NULL; ++ return -1; + + cwd_len = dir.len; + if (setup_git_directory_gently_1(&dir, gitdir, 0) <= 0) { + strbuf_release(&dir); +- return NULL; ++ return -1; + } + + /* +@@ -973,8 +975,10 @@ const char *discover_git_directory(struct strbuf *gitdir) + strbuf_insert(gitdir, gitdir_offset, dir.buf, dir.len); + } + ++ get_common_dir(commondir, gitdir->buf + gitdir_offset); ++ + strbuf_reset(&dir); +- strbuf_addf(&dir, "%s/config", gitdir->buf + gitdir_offset); ++ strbuf_addf(&dir, "%s/config", commondir->buf + commondir_offset); + read_repository_format(&candidate, dir.buf); + strbuf_release(&dir); + +@@ -982,11 +986,12 @@ const char *discover_git_directory(struct strbuf *gitdir) + warning("ignoring git dir '%s': %s", + gitdir->buf + gitdir_offset, err.buf); + strbuf_release(&err); ++ strbuf_setlen(commondir, commondir_offset); + strbuf_setlen(gitdir, gitdir_offset); +- return NULL; ++ return -1; + } + +- return gitdir->buf + gitdir_offset; ++ return 0; + } + + const char *setup_git_directory_gently(int *nongit_ok)