When we generate relative names (e.g., "master~20^2"), we
format the name into a static buffer, then xstrdup the
result to attach it to the commit. Since the first thing we
add into the static buffer is the already-computed name of
the child commit, the names may get longer and longer as
the traversal gets deeper, and we may eventually overflow
the fixed-size buffer.

Fix this by converting the fixed-size buffer into a dynamic
strbuf.  The performance implications should be minimal, as
we end up allocating a heap copy of the name anyway (and now
we can just detach the heap copy from the strbuf).

Reported-by: Eric Roman <ero...@chromium.org>
Signed-off-by: Jeff King <p...@peff.net>
This is a fix for a bug report that came to me off-list.  A real-world
example can be seen by running "git show-branch --all" on a fresh clone


(but that repo is 1.7G, so I don't recommend cloning it unless you're
really interested). Its master branch consists of a strange sequence of
merges that results in naming commits like master^2^2^2^2... and so on
(it's unclear to me why, but it looks like maybe syncing up separate svn
and git repositories?).  Which is odd, but looking at graph, I think the
names show-branch is generating are correct; they're just really long.
And of course odd history is no excuse to overflow a buffer.

Though this is a stack overflow, I don't know that it's exploitable for
anything interesting; an attacker does not get to write arbitrary data,
but rather only a sequence of "^%d" and "~%d" relative history markers.
Perhaps in theory one could devise a history such that the sequence
markers spelled out some malicious code, but it would be quite a
challenge (and given that you have only ascii [^~0-9] to work with,
probably impossible).

I prepared this on "master", but it should be suitable for "maint"; the
code dates all the way back to git v0.99.

 builtin/show-branch.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index d208fd6..90fc6b1 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -162,29 +162,28 @@ static void name_commits(struct commit_list *list,
                        nth = 0;
                        while (parents) {
                                struct commit *p = parents->item;
-                               char newname[1000], *en;
+                               struct strbuf newname = STRBUF_INIT;
                                parents = parents->next;
                                if (p->util)
-                               en = newname;
                                switch (n->generation) {
                                case 0:
-                                       en += sprintf(en, "%s", n->head_name);
+                                       strbuf_addstr(&newname, n->head_name);
                                case 1:
-                                       en += sprintf(en, "%s^", n->head_name);
+                                       strbuf_addf(&newname, "%s^", 
-                                       en += sprintf(en, "%s~%d",
-                                               n->head_name, n->generation);
+                                       strbuf_addf(&newname, "%s~%d",
+                                                   n->head_name, 
                                if (nth == 1)
-                                       en += sprintf(en, "^");
+                                       strbuf_addch(&newname, '^');
-                                       en += sprintf(en, "^%d", nth);
-                               name_commit(p, xstrdup(newname), 0);
+                                       strbuf_addf(&newname, "^%d", nth);
+                               name_commit(p, strbuf_detach(&newname, NULL), 
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to