git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH] show-branch: fix crash with long ref name
@ 2017-02-14 15:48 Christian Couder
  2017-02-14 17:25 ` Jeff King
  0 siblings, 1 reply; 15+ messages in thread
From: Christian Couder @ 2017-02-14 15:48 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Maxim Kuvyrkov, Christian Couder

This is a minimum fix for a crash with a long ref name.

Note that if the refname is too long (for example if you
use 100 instead of 50 in the test script) you could get
an error like:

fatal: cannot lock ref 'refs/heads/1_2_3_4_ ... _98_99_100_':
Unable to create '... /.git/refs/heads/1_2_3_4_ ... _98_99_100_.lock':
File name too long

when creating the ref instead of a crash when using
show-branch and that would be ok.

So a simpler fix could have been just something like:

-       char head[128];
+       char head[1024];

But if the filesystem ever allows filenames longer than 1024
characters then the crash could appear again.

Reported by: Maxim Kuvyrkov <maxim.kuvyrkov@linaro.org>
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
 builtin/show-branch.c          | 14 +++++++-------
 t/t3204-show-branch-refname.sh | 19 +++++++++++++++++++
 2 files changed, 26 insertions(+), 7 deletions(-)
 create mode 100755 t/t3204-show-branch-refname.sh

diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 974f3403ab..3c0fe55eec 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -620,7 +620,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 	int all_heads = 0, all_remotes = 0;
 	int all_mask, all_revs;
 	enum rev_sort_order sort_order = REV_SORT_IN_GRAPH_ORDER;
-	char head[128];
+	char *head_cpy;
 	const char *head_p;
 	int head_len;
 	struct object_id head_oid;
@@ -791,11 +791,11 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 				    head_oid.hash, NULL);
 	if (head_p) {
 		head_len = strlen(head_p);
-		memcpy(head, head_p, head_len + 1);
+		head_cpy = xstrdup(head_p);
 	}
 	else {
 		head_len = 0;
-		head[0] = 0;
+		head_cpy = xstrdup("");
 	}
 
 	if (with_current_branch && head_p) {
@@ -804,15 +804,15 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 			/* We are only interested in adding the branch
 			 * HEAD points at.
 			 */
-			if (rev_is_head(head,
+			if (rev_is_head(head_cpy,
 					head_len,
 					ref_name[i],
 					head_oid.hash, NULL))
 				has_head++;
 		}
 		if (!has_head) {
-			int offset = starts_with(head, "refs/heads/") ? 11 : 0;
-			append_one_rev(head + offset);
+			int offset = starts_with(head_cpy, "refs/heads/") ? 11 : 0;
+			append_one_rev(head_cpy + offset);
 		}
 	}
 
@@ -865,7 +865,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 	if (1 < num_rev || extra < 0) {
 		for (i = 0; i < num_rev; i++) {
 			int j;
-			int is_head = rev_is_head(head,
+			int is_head = rev_is_head(head_cpy,
 						  head_len,
 						  ref_name[i],
 						  head_oid.hash,
diff --git a/t/t3204-show-branch-refname.sh b/t/t3204-show-branch-refname.sh
new file mode 100755
index 0000000000..83b64e3032
--- /dev/null
+++ b/t/t3204-show-branch-refname.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+test_description='test show-branch with long refname'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+
+	test_commit first &&
+	long_refname=$(printf "%s_" $(seq 1 50)) &&
+	git checkout -b "$long_refname"
+'
+
+test_expect_success 'show-branch with long refname' '
+
+	git show-branch first
+'
+
+test_done
-- 
2.12.0.rc0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH] show-branch: fix crash with long ref name
  2017-02-14 15:48 [PATCH] show-branch: fix crash with long ref name Christian Couder
@ 2017-02-14 17:25 ` Jeff King
  2017-02-14 17:26   ` [PATCH 1/3] show-branch: drop head_len variable Jeff King
                     ` (3 more replies)
  0 siblings, 4 replies; 15+ messages in thread
From: Jeff King @ 2017-02-14 17:25 UTC (permalink / raw)
  To: Christian Couder; +Cc: git, Junio C Hamano, Maxim Kuvyrkov, Christian Couder

On Tue, Feb 14, 2017 at 04:48:16PM +0100, Christian Couder wrote:

> @@ -791,11 +791,11 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
>  				    head_oid.hash, NULL);
>  	if (head_p) {
>  		head_len = strlen(head_p);
> -		memcpy(head, head_p, head_len + 1);
> +		head_cpy = xstrdup(head_p);
>  	}
>  	else {
>  		head_len = 0;
> -		head[0] = 0;
> +		head_cpy = xstrdup("");
>  	}

This fixes the problem, but I think we can simplify it quite a bit by
using resolve_refdup(). Here's the patch series I ended up with:

  [1/3]: show-branch: drop head_len variable
  [2/3]: show-branch: store resolved head in heap buffer
  [3/3]: show-branch: use skip_prefix to drop magic numbers

 builtin/show-branch.c | 39 ++++++++++++---------------------------
 1 file changed, 12 insertions(+), 27 deletions(-)

-Peff

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 1/3] show-branch: drop head_len variable
  2017-02-14 17:25 ` Jeff King
@ 2017-02-14 17:26   ` Jeff King
  2017-02-14 17:27   ` [PATCH 2/3] show-branch: store resolved head in heap buffer Jeff King
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 15+ messages in thread
From: Jeff King @ 2017-02-14 17:26 UTC (permalink / raw)
  To: Christian Couder; +Cc: git, Junio C Hamano, Maxim Kuvyrkov, Christian Couder

We copy the result of resolving HEAD into a buffer and keep
track of its length.  But we never actually use the length
for anything besides the copy. Let's stop passing it around.

Signed-off-by: Jeff King <peff@peff.net>
---
 builtin/show-branch.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 974f3403a..e4c488b8c 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -470,7 +470,7 @@ static void snarf_refs(int head, int remotes)
 	}
 }
 
-static int rev_is_head(char *head, int headlen, char *name,
+static int rev_is_head(char *head, char *name,
 		       unsigned char *head_sha1, unsigned char *sha1)
 {
 	if ((!head[0]) ||
@@ -622,7 +622,6 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 	enum rev_sort_order sort_order = REV_SORT_IN_GRAPH_ORDER;
 	char head[128];
 	const char *head_p;
-	int head_len;
 	struct object_id head_oid;
 	int merge_base = 0;
 	int independent = 0;
@@ -790,11 +789,10 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 	head_p = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
 				    head_oid.hash, NULL);
 	if (head_p) {
-		head_len = strlen(head_p);
+		size_t head_len = strlen(head_p);
 		memcpy(head, head_p, head_len + 1);
 	}
 	else {
-		head_len = 0;
 		head[0] = 0;
 	}
 
@@ -805,7 +803,6 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 			 * HEAD points at.
 			 */
 			if (rev_is_head(head,
-					head_len,
 					ref_name[i],
 					head_oid.hash, NULL))
 				has_head++;
@@ -866,7 +863,6 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 		for (i = 0; i < num_rev; i++) {
 			int j;
 			int is_head = rev_is_head(head,
-						  head_len,
 						  ref_name[i],
 						  head_oid.hash,
 						  rev[i]->object.oid.hash);
-- 
2.12.0.rc1.479.g59880b11e


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 2/3] show-branch: store resolved head in heap buffer
  2017-02-14 17:25 ` Jeff King
  2017-02-14 17:26   ` [PATCH 1/3] show-branch: drop head_len variable Jeff King
@ 2017-02-14 17:27   ` Jeff King
  2017-02-14 17:28   ` [PATCH 3/3] show-branch: use skip_prefix to drop magic numbers Jeff King
  2017-02-14 19:35   ` [PATCH] show-branch: fix crash with long ref name Junio C Hamano
  3 siblings, 0 replies; 15+ messages in thread
From: Jeff King @ 2017-02-14 17:27 UTC (permalink / raw)
  To: Christian Couder; +Cc: git, Junio C Hamano, Maxim Kuvyrkov, Christian Couder

We resolve HEAD and copy the result to a fixed-size buffer
with memcpy, never checking that it actually fits. This bug
dates back to 8098a178b (Add git-symbolic-ref, 2005-09-30).
Before that we used readlink(), which took a maximum buffer
size.

We can fix this by using resolve_refdup(), which duplicates
the buffer on the heap. That also lets us just check
for a NULL pointer to see if we have resolved HEAD, and
drop the extra head_p variable.

Signed-off-by: Jeff King <peff@peff.net>
---
 builtin/show-branch.c | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index e4c488b8c..404c4d09a 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -473,8 +473,7 @@ static void snarf_refs(int head, int remotes)
 static int rev_is_head(char *head, char *name,
 		       unsigned char *head_sha1, unsigned char *sha1)
 {
-	if ((!head[0]) ||
-	    (head_sha1 && sha1 && hashcmp(head_sha1, sha1)))
+	if (!head || (head_sha1 && sha1 && hashcmp(head_sha1, sha1)))
 		return 0;
 	if (starts_with(head, "refs/heads/"))
 		head += 11;
@@ -620,8 +619,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 	int all_heads = 0, all_remotes = 0;
 	int all_mask, all_revs;
 	enum rev_sort_order sort_order = REV_SORT_IN_GRAPH_ORDER;
-	char head[128];
-	const char *head_p;
+	char *head;
 	struct object_id head_oid;
 	int merge_base = 0;
 	int independent = 0;
@@ -786,17 +784,10 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 			snarf_refs(all_heads, all_remotes);
 	}
 
-	head_p = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
-				    head_oid.hash, NULL);
-	if (head_p) {
-		size_t head_len = strlen(head_p);
-		memcpy(head, head_p, head_len + 1);
-	}
-	else {
-		head[0] = 0;
-	}
+	head = resolve_refdup("HEAD", RESOLVE_REF_READING,
+			      head_oid.hash, NULL);
 
-	if (with_current_branch && head_p) {
+	if (with_current_branch && head) {
 		int has_head = 0;
 		for (i = 0; !has_head && i < ref_name_cnt; i++) {
 			/* We are only interested in adding the branch
-- 
2.12.0.rc1.479.g59880b11e


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 3/3] show-branch: use skip_prefix to drop magic numbers
  2017-02-14 17:25 ` Jeff King
  2017-02-14 17:26   ` [PATCH 1/3] show-branch: drop head_len variable Jeff King
  2017-02-14 17:27   ` [PATCH 2/3] show-branch: store resolved head in heap buffer Jeff King
@ 2017-02-14 17:28   ` Jeff King
  2017-02-14 18:53     ` Pranit Bauva
  2017-02-14 19:35   ` [PATCH] show-branch: fix crash with long ref name Junio C Hamano
  3 siblings, 1 reply; 15+ messages in thread
From: Jeff King @ 2017-02-14 17:28 UTC (permalink / raw)
  To: Christian Couder; +Cc: git, Junio C Hamano, Maxim Kuvyrkov, Christian Couder

We make several starts_with() calls, only to advance
pointers. This is exactly what skip_prefix() is for, which
lets us avoid manually-counted magic numbers.

Signed-off-by: Jeff King <peff@peff.net>
---
 builtin/show-branch.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 404c4d09a..c03d3ec7c 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -470,17 +470,14 @@ static void snarf_refs(int head, int remotes)
 	}
 }
 
-static int rev_is_head(char *head, char *name,
+static int rev_is_head(const char *head, const char *name,
 		       unsigned char *head_sha1, unsigned char *sha1)
 {
 	if (!head || (head_sha1 && sha1 && hashcmp(head_sha1, sha1)))
 		return 0;
-	if (starts_with(head, "refs/heads/"))
-		head += 11;
-	if (starts_with(name, "refs/heads/"))
-		name += 11;
-	else if (starts_with(name, "heads/"))
-		name += 6;
+	skip_prefix(head, "refs/heads/", &head);
+	if (!skip_prefix(name, "refs/heads/", &name))
+		skip_prefix(name, "heads/", &name);
 	return !strcmp(head, name);
 }
 
@@ -799,8 +796,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 				has_head++;
 		}
 		if (!has_head) {
-			int offset = starts_with(head, "refs/heads/") ? 11 : 0;
-			append_one_rev(head + offset);
+			const char *name = head;
+			skip_prefix(name, "refs/heads/", &name);
+			append_one_rev(name);
 		}
 	}
 
-- 
2.12.0.rc1.479.g59880b11e

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH 3/3] show-branch: use skip_prefix to drop magic numbers
  2017-02-14 17:28   ` [PATCH 3/3] show-branch: use skip_prefix to drop magic numbers Jeff King
@ 2017-02-14 18:53     ` Pranit Bauva
  2017-02-14 19:53       ` Jeff King
  0 siblings, 1 reply; 15+ messages in thread
From: Pranit Bauva @ 2017-02-14 18:53 UTC (permalink / raw)
  To: Jeff King
  Cc: Christian Couder, Git List, Junio C Hamano, Maxim Kuvyrkov,
	Christian Couder

[-- Attachment #1: Type: text/plain, Size: 2299 bytes --]

Hey Peff,

On Tue, Feb 14, 2017 at 10:58 PM, Jeff King <peff@peff.net> wrote:
> We make several starts_with() calls, only to advance
> pointers. This is exactly what skip_prefix() is for, which
> lets us avoid manually-counted magic numbers.
>
> Signed-off-by: Jeff King <peff@peff.net>
> ---
>  builtin/show-branch.c | 16 +++++++---------
>  1 file changed, 7 insertions(+), 9 deletions(-)
>
> diff --git a/builtin/show-branch.c b/builtin/show-branch.c
> index 404c4d09a..c03d3ec7c 100644
> --- a/builtin/show-branch.c
> +++ b/builtin/show-branch.c
> @@ -470,17 +470,14 @@ static void snarf_refs(int head, int remotes)
>         }
>  }
>
> -static int rev_is_head(char *head, char *name,
> +static int rev_is_head(const char *head, const char *name,
>                        unsigned char *head_sha1, unsigned char *sha1)
>  {
>         if (!head || (head_sha1 && sha1 && hashcmp(head_sha1, sha1)))
>                 return 0;
> -       if (starts_with(head, "refs/heads/"))
> -               head += 11;
> -       if (starts_with(name, "refs/heads/"))
> -               name += 11;
> -       else if (starts_with(name, "heads/"))
> -               name += 6;
> +       skip_prefix(head, "refs/heads/", &head);
> +       if (!skip_prefix(name, "refs/heads/", &name))
> +               skip_prefix(name, "heads/", &name);
>         return !strcmp(head, name);
>  }
>
> @@ -799,8 +796,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
>                                 has_head++;
>                 }
>                 if (!has_head) {
> -                       int offset = starts_with(head, "refs/heads/") ? 11 : 0;
> -                       append_one_rev(head + offset);
> +                       const char *name = head;
> +                       skip_prefix(name, "refs/heads/", &name);
> +                       append_one_rev(name);
>                 }
>         }
>


Did you purposely miss the one in line number 278 of
builtin/show-branch.c because I think you only touched up the parts
which were related to "refs/" but didn't explicitly mention it in the
commit message?

    if (starts_with(pretty_str, "[PATCH] "))
        pretty_str += 8;

If not, you can squash this patch attached. Sorry, couldn't send it in
mail because of proxy issues.

Regards,
Pranit Bauva

[-- Attachment #2: 0001-squash-show-branch-use-skip_prefix-to-drop-magic-num.patch --]
[-- Type: text/x-patch, Size: 868 bytes --]

From 2e80d4458df659765011450621ee34459dc749f9 Mon Sep 17 00:00:00 2001
From: Pranit Bauva <pranit.bauva@gmail.com>
Date: Tue, 14 Feb 2017 23:53:36 +0530
Subject: [PATCH] !squash: show-branch: use skip_prefix to drop magic numbers

Signed-off-by: Pranit Bauva <pranit.bauva@gmail.com>
---
 builtin/show-branch.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index c03d3ec7c..19756595d 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -275,8 +275,7 @@ static void show_one_commit(struct commit *commit, int no_name)
 		pp_commit_easy(CMIT_FMT_ONELINE, commit, &pretty);
 		pretty_str = pretty.buf;
 	}
-	if (starts_with(pretty_str, "[PATCH] "))
-		pretty_str += 8;
+	skip_prefix(pretty_str, "[PATCH] ", &pretty_str);
 
 	if (!no_name) {
 		if (name && name->head_name) {
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH] show-branch: fix crash with long ref name
  2017-02-14 17:25 ` Jeff King
                     ` (2 preceding siblings ...)
  2017-02-14 17:28   ` [PATCH 3/3] show-branch: use skip_prefix to drop magic numbers Jeff King
@ 2017-02-14 19:35   ` Junio C Hamano
  2017-02-14 19:55     ` Jeff King
  3 siblings, 1 reply; 15+ messages in thread
From: Junio C Hamano @ 2017-02-14 19:35 UTC (permalink / raw)
  To: Jeff King; +Cc: Christian Couder, git, Maxim Kuvyrkov, Christian Couder

Jeff King <peff@peff.net> writes:

> This fixes the problem, but I think we can simplify it quite a bit by
> using resolve_refdup(). Here's the patch series I ended up with:
>
>   [1/3]: show-branch: drop head_len variable
>   [2/3]: show-branch: store resolved head in heap buffer
>   [3/3]: show-branch: use skip_prefix to drop magic numbers
>
>  builtin/show-branch.c | 39 ++++++++++++---------------------------
>  1 file changed, 12 insertions(+), 27 deletions(-)

Yes, the whole thing is my fault ;-) and I agree with what these
patches do.

The second one lacks free(head) but I think that is OK; it is
something we allocate in cmd_*() and use pretty much thruout the
rest of the program.

Thanks.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 3/3] show-branch: use skip_prefix to drop magic numbers
  2017-02-14 18:53     ` Pranit Bauva
@ 2017-02-14 19:53       ` Jeff King
  0 siblings, 0 replies; 15+ messages in thread
From: Jeff King @ 2017-02-14 19:53 UTC (permalink / raw)
  To: Pranit Bauva
  Cc: Christian Couder, Git List, Junio C Hamano, Maxim Kuvyrkov,
	Christian Couder

On Wed, Feb 15, 2017 at 12:23:52AM +0530, Pranit Bauva wrote:

> Did you purposely miss the one in line number 278 of
> builtin/show-branch.c because I think you only touched up the parts
> which were related to "refs/" but didn't explicitly mention it in the
> commit message?
> 
>     if (starts_with(pretty_str, "[PATCH] "))
>         pretty_str += 8;

Not purposely. I was just fixing up the bits that I had noticed in the
earlier patches.

> diff --git a/builtin/show-branch.c b/builtin/show-branch.c
> index c03d3ec7c..19756595d 100644
> --- a/builtin/show-branch.c
> +++ b/builtin/show-branch.c
> @@ -275,8 +275,7 @@ static void show_one_commit(struct commit *commit, int no_name)
>  		pp_commit_easy(CMIT_FMT_ONELINE, commit, &pretty);
>  		pretty_str = pretty.buf;
>  	}
> -	if (starts_with(pretty_str, "[PATCH] "))
> -		pretty_str += 8;
> +	skip_prefix(pretty_str, "[PATCH] ", &pretty_str);

Yeah, I agree this the same type of fix and is worth including. Thanks!

-Peff

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] show-branch: fix crash with long ref name
  2017-02-14 19:35   ` [PATCH] show-branch: fix crash with long ref name Junio C Hamano
@ 2017-02-14 19:55     ` Jeff King
  2017-02-14 21:29       ` Christian Couder
  0 siblings, 1 reply; 15+ messages in thread
From: Jeff King @ 2017-02-14 19:55 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Christian Couder, git, Maxim Kuvyrkov, Christian Couder

On Tue, Feb 14, 2017 at 11:35:48AM -0800, Junio C Hamano wrote:

> Jeff King <peff@peff.net> writes:
> 
> > This fixes the problem, but I think we can simplify it quite a bit by
> > using resolve_refdup(). Here's the patch series I ended up with:
> >
> >   [1/3]: show-branch: drop head_len variable
> >   [2/3]: show-branch: store resolved head in heap buffer
> >   [3/3]: show-branch: use skip_prefix to drop magic numbers
> >
> >  builtin/show-branch.c | 39 ++++++++++++---------------------------
> >  1 file changed, 12 insertions(+), 27 deletions(-)
> 
> Yes, the whole thing is my fault ;-) and I agree with what these
> patches do.
> 
> The second one lacks free(head) but I think that is OK; it is
> something we allocate in cmd_*() and use pretty much thruout the
> rest of the program.

Yes, I actually tested the whole thing under ASAN (which was necessary
to notice the problem), which complained about the leak. I don't mind
adding a free(head), but there are a bunch of similar "leaks" in that
function, so I didn't bother.

I notice Christian's patch added a few tests. I don't know if we'd want
to squash them in (I didn't mean to override his patch at all; I was
about to send mine out when I noticed his, and I wondered if we wanted
to combine the two efforts).

-Peff

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] show-branch: fix crash with long ref name
  2017-02-14 19:55     ` Jeff King
@ 2017-02-14 21:29       ` Christian Couder
  2017-02-15 21:40         ` Jeff King
  0 siblings, 1 reply; 15+ messages in thread
From: Christian Couder @ 2017-02-14 21:29 UTC (permalink / raw)
  To: Jeff King, Junio C Hamano; +Cc: git, Maxim Kuvyrkov

On Tue, Feb 14, 2017 at 8:55 PM, Jeff King <peff@peff.net> wrote:
> On Tue, Feb 14, 2017 at 11:35:48AM -0800, Junio C Hamano wrote:
>
>> Jeff King <peff@peff.net> writes:
>>
>> > This fixes the problem, but I think we can simplify it quite a bit by
>> > using resolve_refdup(). Here's the patch series I ended up with:
>> >
>> >   [1/3]: show-branch: drop head_len variable
>> >   [2/3]: show-branch: store resolved head in heap buffer
>> >   [3/3]: show-branch: use skip_prefix to drop magic numbers

Yeah, I noticed there were a number of things that could be improved
in the area, but I didn't want to spend too much time on this, so
thanks for this series.

>> Yes, the whole thing is my fault ;-) and I agree with what these
>> patches do.
>>
>> The second one lacks free(head) but I think that is OK; it is
>> something we allocate in cmd_*() and use pretty much thruout the
>> rest of the program.
>
> Yes, I actually tested the whole thing under ASAN (which was necessary
> to notice the problem), which complained about the leak. I don't mind
> adding a free(head), but there are a bunch of similar "leaks" in that
> function, so I didn't bother.

Yeah, I didn't bother either.

> I notice Christian's patch added a few tests. I don't know if we'd want
> to squash them in (I didn't mean to override his patch at all; I was
> about to send mine out when I noticed his, and I wondered if we wanted
> to combine the two efforts).

I think it would be nice to have at least one test. Feel free to
squash mine if you want.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] show-branch: fix crash with long ref name
  2017-02-14 21:29       ` Christian Couder
@ 2017-02-15 21:40         ` Jeff King
  2017-02-15 21:50           ` Junio C Hamano
  2017-02-16 12:40           ` Christian Couder
  0 siblings, 2 replies; 15+ messages in thread
From: Jeff King @ 2017-02-15 21:40 UTC (permalink / raw)
  To: Christian Couder; +Cc: Junio C Hamano, git, Maxim Kuvyrkov, Pranit Bauva

On Tue, Feb 14, 2017 at 10:29:46PM +0100, Christian Couder wrote:

> > I notice Christian's patch added a few tests. I don't know if we'd want
> > to squash them in (I didn't mean to override his patch at all; I was
> > about to send mine out when I noticed his, and I wondered if we wanted
> > to combine the two efforts).
> 
> I think it would be nice to have at least one test. Feel free to
> squash mine if you want.

I started to add some tests, but I had second thoughts. It _is_ nice
to show off the fix, but as far as regressions go, this specific case is
unlikely to come up again. What would be more valuable, I think, is a
test script which set up a very long refname (not just 150 bytes or
whatever) and ran it through a series of git commands.

But then you run into all sorts of portability annoyances with pathname
restrictions (you can hack around creation by writing the refname
directly into packed-refs, but most manipulations will want to take the
.lock in the filesystem). So I dunno. It seems like being thorough is a
lot of hassle for not much gain. Being not-thorough is easy, but is
mostly a token that is unlikely to find any real bugs.

So I punted, at least for now.

I see the patches are marked for 'next' in the latest What's Cooking.
If it is not too late in today's integration cycle, here is a re-roll of
patch 3 that squashes in Pranit's suggestion (if it is too late, then
Pranit, you may want to re-send it as a squash on top).

-- >8 --
Subject: [PATCH] show-branch: use skip_prefix to drop magic numbers

We make several starts_with() calls, only to advance
pointers. This is exactly what skip_prefix() is for, which
lets us avoid manually-counted magic numbers.

Helped-by: Pranit Bauva <pranit.bauva@gmail.com>
Signed-off-by: Jeff King <peff@peff.net>
---
 builtin/show-branch.c | 19 ++++++++-----------
 1 file changed, 8 insertions(+), 11 deletions(-)

diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 404c4d09a..19756595d 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -275,8 +275,7 @@ static void show_one_commit(struct commit *commit, int no_name)
 		pp_commit_easy(CMIT_FMT_ONELINE, commit, &pretty);
 		pretty_str = pretty.buf;
 	}
-	if (starts_with(pretty_str, "[PATCH] "))
-		pretty_str += 8;
+	skip_prefix(pretty_str, "[PATCH] ", &pretty_str);
 
 	if (!no_name) {
 		if (name && name->head_name) {
@@ -470,17 +469,14 @@ static void snarf_refs(int head, int remotes)
 	}
 }
 
-static int rev_is_head(char *head, char *name,
+static int rev_is_head(const char *head, const char *name,
 		       unsigned char *head_sha1, unsigned char *sha1)
 {
 	if (!head || (head_sha1 && sha1 && hashcmp(head_sha1, sha1)))
 		return 0;
-	if (starts_with(head, "refs/heads/"))
-		head += 11;
-	if (starts_with(name, "refs/heads/"))
-		name += 11;
-	else if (starts_with(name, "heads/"))
-		name += 6;
+	skip_prefix(head, "refs/heads/", &head);
+	if (!skip_prefix(name, "refs/heads/", &name))
+		skip_prefix(name, "heads/", &name);
 	return !strcmp(head, name);
 }
 
@@ -799,8 +795,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 				has_head++;
 		}
 		if (!has_head) {
-			int offset = starts_with(head, "refs/heads/") ? 11 : 0;
-			append_one_rev(head + offset);
+			const char *name = head;
+			skip_prefix(name, "refs/heads/", &name);
+			append_one_rev(name);
 		}
 	}
 
-- 
2.12.0.rc1.541.g3e32dea89


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH] show-branch: fix crash with long ref name
  2017-02-15 21:40         ` Jeff King
@ 2017-02-15 21:50           ` Junio C Hamano
  2017-02-15 21:52             ` Jeff King
  2017-02-16 12:40           ` Christian Couder
  1 sibling, 1 reply; 15+ messages in thread
From: Junio C Hamano @ 2017-02-15 21:50 UTC (permalink / raw)
  To: Jeff King; +Cc: Christian Couder, git, Maxim Kuvyrkov, Pranit Bauva

Jeff King <peff@peff.net> writes:

> I see the patches are marked for 'next' in the latest What's Cooking.
> If it is not too late in today's integration cycle, here is a re-roll of
> patch 3 that squashes in Pranit's suggestion (if it is too late, then
> Pranit, you may want to re-send it as a squash on top).

Thanks.  

I think that matches what I queued last night, except for the
Helped-by: line.  Will replace.

> -- >8 --
> Subject: [PATCH] show-branch: use skip_prefix to drop magic numbers
>
> We make several starts_with() calls, only to advance
> pointers. This is exactly what skip_prefix() is for, which
> lets us avoid manually-counted magic numbers.
>
> Helped-by: Pranit Bauva <pranit.bauva@gmail.com>
> Signed-off-by: Jeff King <peff@peff.net>
> ---
>  builtin/show-branch.c | 19 ++++++++-----------
>  1 file changed, 8 insertions(+), 11 deletions(-)
>
> diff --git a/builtin/show-branch.c b/builtin/show-branch.c
> index 404c4d09a..19756595d 100644
> --- a/builtin/show-branch.c
> +++ b/builtin/show-branch.c
> @@ -275,8 +275,7 @@ static void show_one_commit(struct commit *commit, int no_name)
>  		pp_commit_easy(CMIT_FMT_ONELINE, commit, &pretty);
>  		pretty_str = pretty.buf;
>  	}
> -	if (starts_with(pretty_str, "[PATCH] "))
> -		pretty_str += 8;
> +	skip_prefix(pretty_str, "[PATCH] ", &pretty_str);
>  
>  	if (!no_name) {
>  		if (name && name->head_name) {
> @@ -470,17 +469,14 @@ static void snarf_refs(int head, int remotes)
>  	}
>  }
>  
> -static int rev_is_head(char *head, char *name,
> +static int rev_is_head(const char *head, const char *name,
>  		       unsigned char *head_sha1, unsigned char *sha1)
>  {
>  	if (!head || (head_sha1 && sha1 && hashcmp(head_sha1, sha1)))
>  		return 0;
> -	if (starts_with(head, "refs/heads/"))
> -		head += 11;
> -	if (starts_with(name, "refs/heads/"))
> -		name += 11;
> -	else if (starts_with(name, "heads/"))
> -		name += 6;
> +	skip_prefix(head, "refs/heads/", &head);
> +	if (!skip_prefix(name, "refs/heads/", &name))
> +		skip_prefix(name, "heads/", &name);
>  	return !strcmp(head, name);
>  }
>  
> @@ -799,8 +795,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
>  				has_head++;
>  		}
>  		if (!has_head) {
> -			int offset = starts_with(head, "refs/heads/") ? 11 : 0;
> -			append_one_rev(head + offset);
> +			const char *name = head;
> +			skip_prefix(name, "refs/heads/", &name);
> +			append_one_rev(name);
>  		}
>  	}

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] show-branch: fix crash with long ref name
  2017-02-15 21:50           ` Junio C Hamano
@ 2017-02-15 21:52             ` Jeff King
  0 siblings, 0 replies; 15+ messages in thread
From: Jeff King @ 2017-02-15 21:52 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Christian Couder, git, Maxim Kuvyrkov, Pranit Bauva

On Wed, Feb 15, 2017 at 01:50:07PM -0800, Junio C Hamano wrote:

> Jeff King <peff@peff.net> writes:
> 
> > I see the patches are marked for 'next' in the latest What's Cooking.
> > If it is not too late in today's integration cycle, here is a re-roll of
> > patch 3 that squashes in Pranit's suggestion (if it is too late, then
> > Pranit, you may want to re-send it as a squash on top).
> 
> Thanks.  
> 
> I think that matches what I queued last night, except for the
> Helped-by: line.  Will replace.

Oh, indeed. I should have actually checked what you queued. Thanks.

-Peff

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] show-branch: fix crash with long ref name
  2017-02-15 21:40         ` Jeff King
  2017-02-15 21:50           ` Junio C Hamano
@ 2017-02-16 12:40           ` Christian Couder
  2017-02-17  5:03             ` Jeff King
  1 sibling, 1 reply; 15+ messages in thread
From: Christian Couder @ 2017-02-16 12:40 UTC (permalink / raw)
  To: Jeff King; +Cc: Junio C Hamano, git, Maxim Kuvyrkov, Pranit Bauva

On Wed, Feb 15, 2017 at 10:40 PM, Jeff King <peff@peff.net> wrote:
> On Tue, Feb 14, 2017 at 10:29:46PM +0100, Christian Couder wrote:
>
>> > I notice Christian's patch added a few tests. I don't know if we'd want
>> > to squash them in (I didn't mean to override his patch at all; I was
>> > about to send mine out when I noticed his, and I wondered if we wanted
>> > to combine the two efforts).
>>
>> I think it would be nice to have at least one test. Feel free to
>> squash mine if you want.
>
> I started to add some tests, but I had second thoughts. It _is_ nice
> to show off the fix, but as far as regressions go, this specific case is
> unlikely to come up again. What would be more valuable, I think, is a
> test script which set up a very long refname (not just 150 bytes or
> whatever) and ran it through a series of git commands.

I agree that a test script running through a series of command with
long refnames would be great.

But I think the refname should not necesarily be too long. As I wrote
in the commit message of my patch, if the ref name had been much
longer the crash would not have happened because the ref could not
have been created in the first place.

So the best would be to run through a series of commands with a
refname ranging from let's say 80 chars to 300 chars.

That would have a chance to catch crashes due to legacy code using for
example things like `char stuff[128]` or `char stuff[256]`.

Implementing those tests could have started with something like the
test case I sent, but as it would in the end be about many different
commands, one can see it as part of a different topic.

> But then you run into all sorts of portability annoyances with pathname
> restrictions (you can hack around creation by writing the refname
> directly into packed-refs, but most manipulations will want to take the
> .lock in the filesystem).

Yeah, but if a crash doesn't happen because we die() as the ref is too
long for the file system, we could detect that and make the test
succeed.

> So I dunno. It seems like being thorough is a
> lot of hassle for not much gain. Being not-thorough is easy, but is
> mostly a token that is unlikely to find any real bugs.

Yeah, if we really care, it might be better to start using a fuzzer or
a property based testing tool instead of bothering with these kind of
tests by ourselves, which is also a different topic.

> So I punted, at least for now.

Ok, no problem.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] show-branch: fix crash with long ref name
  2017-02-16 12:40           ` Christian Couder
@ 2017-02-17  5:03             ` Jeff King
  0 siblings, 0 replies; 15+ messages in thread
From: Jeff King @ 2017-02-17  5:03 UTC (permalink / raw)
  To: Christian Couder; +Cc: Junio C Hamano, git, Maxim Kuvyrkov, Pranit Bauva

On Thu, Feb 16, 2017 at 01:40:00PM +0100, Christian Couder wrote:

> > I started to add some tests, but I had second thoughts. It _is_ nice
> > to show off the fix, but as far as regressions go, this specific case is
> > unlikely to come up again. What would be more valuable, I think, is a
> > test script which set up a very long refname (not just 150 bytes or
> > whatever) and ran it through a series of git commands.
> 
> I agree that a test script running through a series of command with
> long refnames would be great.
> 
> But I think the refname should not necesarily be too long. As I wrote
> in the commit message of my patch, if the ref name had been much
> longer the crash would not have happened because the ref could not
> have been created in the first place.

Right, I think there's a tension there. Too short and it is not
interesting, and too long and things start to fail for uninteresting
reasons (e.g., your filesystem can't handle the name).

> So the best would be to run through a series of commands with a
> refname ranging from let's say 80 chars to 300 chars.
> 
> That would have a chance to catch crashes due to legacy code using for
> example things like `char stuff[128]` or `char stuff[256]`.

But that doesn't catch `char stuff[512]`. I think you'd really want a
range of sizes, and to test all of them. Worse, though, is it's not
clear how you decide when a test has failed. Obviously smashing the
stack is a bad outcome, but part of the goal would presumably be to
flush out unnecessary length limitations elsewhere.

I got about that far in my thinking before saying "wow, this is getting
to be complicated for not much gain".

> > So I dunno. It seems like being thorough is a
> > lot of hassle for not much gain. Being not-thorough is easy, but is
> > mostly a token that is unlikely to find any real bugs.
> 
> Yeah, if we really care, it might be better to start using a fuzzer or
> a property based testing tool instead of bothering with these kind of
> tests by ourselves, which is also a different topic.

Yes, I'd agree that a fuzzer is probably a better choice. I played with
AFL a bit back when it came out, but I never got it to turn up anything
useful.

I am disappointed that this obvious memory problem survived for so long.
I did quite a bit of auditing for such problems a year or two ago, but I
focused on problematic functions like strcpy, sprintf, etc.

It's easy to use memcpy() wrong, too, but it's hard to audit. There are
a lot of calls, and you have to match up the copied length with a value
computed elsewhere. I traded a lot of them out back then for safer
variants (like the FLEX_ALLOC stuff), but many calls just fundamentally
need something unsafe like memcpy to get their job done.

-Peff

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2017-02-17  5:03 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-14 15:48 [PATCH] show-branch: fix crash with long ref name Christian Couder
2017-02-14 17:25 ` Jeff King
2017-02-14 17:26   ` [PATCH 1/3] show-branch: drop head_len variable Jeff King
2017-02-14 17:27   ` [PATCH 2/3] show-branch: store resolved head in heap buffer Jeff King
2017-02-14 17:28   ` [PATCH 3/3] show-branch: use skip_prefix to drop magic numbers Jeff King
2017-02-14 18:53     ` Pranit Bauva
2017-02-14 19:53       ` Jeff King
2017-02-14 19:35   ` [PATCH] show-branch: fix crash with long ref name Junio C Hamano
2017-02-14 19:55     ` Jeff King
2017-02-14 21:29       ` Christian Couder
2017-02-15 21:40         ` Jeff King
2017-02-15 21:50           ` Junio C Hamano
2017-02-15 21:52             ` Jeff King
2017-02-16 12:40           ` Christian Couder
2017-02-17  5:03             ` Jeff King

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).