All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] remote.c: reject 0-length branch names
@ 2022-05-31 23:12 Glen Choo via GitGitGadget
  2022-05-31 23:12 ` [PATCH 1/2] remote.c: don't BUG() on " Glen Choo via GitGitGadget
  2022-05-31 23:12 ` [PATCH 2/2] remote.c: reject " Glen Choo via GitGitGadget
  0 siblings, 2 replies; 8+ messages in thread
From: Glen Choo via GitGitGadget @ 2022-05-31 23:12 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Ing. Martin Prantl Ph.D., Glen Choo

This fixes the regression reported in [1], where Git may fail if it
encounters multiple "branch." keys with no subsection, e.g.

[branch ""] remote = foo merge = bar

Prior to 4a2dcb1a08 (remote: die if branch is not found in repository,
2021-11-17), we silently ignored such keys. But that commit had an
inconsistency in how we read and write to the branches hash map, causing us
to BUG() (see Patch 1/2 for more details).

This small series does two things

 * Fix the inconsistency in 4a2dcb1a08 that caused the bug.
 * Make Git fail if we find such keys (because we'll never use them anyway).

[1] https://lore.kernel.org/git/24f547-6285e280-59-40303580@48243747

Glen Choo (2):
  remote.c: don't BUG() on 0-length branch names
  remote.c: reject 0-length branch names

 remote.c              | 10 ++++++----
 t/t5516-fetch-push.sh | 20 ++++++++++++++++++++
 2 files changed, 26 insertions(+), 4 deletions(-)


base-commit: f9b95943b68b6b8ca5a6072f50a08411c6449b55
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1273%2Fchooglen%2Fremote%2Fhandle-0-length-branch-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1273/chooglen/remote/handle-0-length-branch-v1
Pull-Request: https://github.com/git/git/pull/1273
-- 
gitgitgadget

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

* [PATCH 1/2] remote.c: don't BUG() on 0-length branch names
  2022-05-31 23:12 [PATCH 0/2] remote.c: reject 0-length branch names Glen Choo via GitGitGadget
@ 2022-05-31 23:12 ` Glen Choo via GitGitGadget
  2022-06-08 23:27   ` Jeff King
  2022-05-31 23:12 ` [PATCH 2/2] remote.c: reject " Glen Choo via GitGitGadget
  1 sibling, 1 reply; 8+ messages in thread
From: Glen Choo via GitGitGadget @ 2022-05-31 23:12 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Ing. Martin Prantl Ph.D., Glen Choo, Glen Choo

From: Glen Choo <chooglen@google.com>

4a2dcb1a08 (remote: die if branch is not found in repository,
2021-11-17) introduced a regression where multiple config entries with
an empty branch name, e.g.

[branch ""]
  remote = foo
  merge = bar

could cause Git to fail when it tries to look up branch tracking
information.

We parse the config key to get (branch name, branch name length), but
when the branch name subsection is empty, we get a bogus branch name,
e.g. "branch..remote" gives (".remote", 0). We continue to use the bogus
branch name as if it were valid, and prior to 4a2dcb1a08, this wasn't an
issue because length = 0 caused the branch name to effectively be ""
everywhere.

However, that commit handles length = 0 inconsistently when we create
the branch:

- When find_branch() is called to check if the branch exists in the
  branch hash map, it interprets a length of 0 to mean that it should
  call strlen on the char pointer.
- But the code path that inserts into the branch hash map interprets a
  length of 0 to mean that the string is 0-length.

This results in the bug described above:

- "branch..remote" looks for ".remote" in the branch hash map. Since we
  do not find it, we insert the "" entry into the hash map.
- "branch..merge" looks for ".merge" in the branch hash map. Since we
  do not find it, we again try to insert the "" entry into the hash map.
  However, the entries in the branch hash map are supposed to be
  appended to, not overwritten.
- Since overwriting an entry is a BUG(), Git fails instead of silently
  ignoring the empty branch name.

Fix the bug by removing the convenience strlen functionality, so that
0 means that the string is 0-length. We still insert a bogus branch name
into the hash map, but this will be fixed in a later commit.

Reported-by: "Ing. Martin Prantl Ph.D." <perry@ntis.zcu.cz>
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Glen Choo <chooglen@google.com>
---
 remote.c              |  6 ++----
 t/t5516-fetch-push.sh | 10 ++++++++++
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/remote.c b/remote.c
index 42a4e7106e1..cf7015ae8ab 100644
--- a/remote.c
+++ b/remote.c
@@ -195,9 +195,6 @@ static struct branch *find_branch(struct remote_state *remote_state,
 	struct branches_hash_key lookup;
 	struct hashmap_entry lookup_entry, *e;
 
-	if (!len)
-		len = strlen(name);
-
 	lookup.str = name;
 	lookup.len = len;
 	hashmap_entry_init(&lookup_entry, memhash(name, len));
@@ -214,7 +211,8 @@ static void die_on_missing_branch(struct repository *repo,
 {
 	/* branch == NULL is always valid because it represents detached HEAD. */
 	if (branch &&
-	    branch != find_branch(repo->remote_state, branch->name, 0))
+	    branch != find_branch(repo->remote_state, branch->name,
+				  strlen(branch->name)))
 		die("branch %s was not found in the repository", branch->name);
 }
 
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 4dfb080433e..a05268952e9 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -598,6 +598,16 @@ test_expect_success 'branch.*.pushremote config order is irrelevant' '
 	check_push_result two_repo $the_commit heads/main
 '
 
+test_expect_success 'push ignores empty branch name entries' '
+	mk_test one_repo heads/main &&
+	test_config remote.one.url one_repo &&
+	test_config branch..remote one &&
+	test_config branch..merge refs/heads/ &&
+	test_config branch.main.remote one &&
+	test_config branch.main.merge refs/heads/main &&
+	git push
+'
+
 test_expect_success 'push with dry-run' '
 
 	mk_test testrepo heads/main &&
-- 
gitgitgadget


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

* [PATCH 2/2] remote.c: reject 0-length branch names
  2022-05-31 23:12 [PATCH 0/2] remote.c: reject 0-length branch names Glen Choo via GitGitGadget
  2022-05-31 23:12 ` [PATCH 1/2] remote.c: don't BUG() on " Glen Choo via GitGitGadget
@ 2022-05-31 23:12 ` Glen Choo via GitGitGadget
  2022-06-01  7:30   ` Ævar Arnfjörð Bjarmason
  1 sibling, 1 reply; 8+ messages in thread
From: Glen Choo via GitGitGadget @ 2022-05-31 23:12 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Ing. Martin Prantl Ph.D., Glen Choo, Glen Choo

From: Glen Choo <chooglen@google.com>

Branch names can't be empty, so config keys with an empty branch name,
e.g. "branch..remote", are silently ignored.

Since these config keys will never be useful, make it a fatal error when
remote.c finds a key that starts with "branch." and has an empty
subsection.

Signed-off-by: Glen Choo <chooglen@google.com>
---
 remote.c              |  4 ++++
 t/t5516-fetch-push.sh | 12 +++++++++++-
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/remote.c b/remote.c
index cf7015ae8ab..a3888dd789c 100644
--- a/remote.c
+++ b/remote.c
@@ -352,8 +352,12 @@ static int handle_config(const char *key, const char *value, void *cb)
 	struct remote_state *remote_state = cb;
 
 	if (parse_config_key(key, "branch", &name, &namelen, &subkey) >= 0) {
+		/* There is no subsection. */
 		if (!name)
 			return 0;
+		/* There is a subsection, but it is empty. */
+		if (!namelen)
+			return -1;
 		branch = make_branch(remote_state, name, namelen);
 		if (!strcmp(subkey, "remote")) {
 			return git_config_string(&branch->remote_name, key, value);
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index a05268952e9..e99c31f8c35 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -598,13 +598,23 @@ test_expect_success 'branch.*.pushremote config order is irrelevant' '
 	check_push_result two_repo $the_commit heads/main
 '
 
-test_expect_success 'push ignores empty branch name entries' '
+test_expect_success 'push rejects empty branch name entries' '
 	mk_test one_repo heads/main &&
 	test_config remote.one.url one_repo &&
 	test_config branch..remote one &&
 	test_config branch..merge refs/heads/ &&
 	test_config branch.main.remote one &&
 	test_config branch.main.merge refs/heads/main &&
+	test_must_fail git push 2>err &&
+	grep "bad config variable .branch\.\." err
+'
+
+test_expect_success 'push ignores "branch." config without subsection' '
+	mk_test one_repo heads/main &&
+	test_config remote.one.url one_repo &&
+	test_config branch.autoSetupMerge true &&
+	test_config branch.main.remote one &&
+	test_config branch.main.merge refs/heads/main &&
 	git push
 '
 
-- 
gitgitgadget

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

* Re: [PATCH 2/2] remote.c: reject 0-length branch names
  2022-05-31 23:12 ` [PATCH 2/2] remote.c: reject " Glen Choo via GitGitGadget
@ 2022-06-01  7:30   ` Ævar Arnfjörð Bjarmason
  2022-06-01 16:55     ` Glen Choo
  0 siblings, 1 reply; 8+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-06-01  7:30 UTC (permalink / raw)
  To: Glen Choo via GitGitGadget
  Cc: git, Jeff King, Ing. Martin Prantl Ph.D., Glen Choo


On Tue, May 31 2022, Glen Choo via GitGitGadget wrote:

> From: Glen Choo <chooglen@google.com>
>
> Branch names can't be empty, so config keys with an empty branch name,
> e.g. "branch..remote", are silently ignored.
>
> Since these config keys will never be useful, make it a fatal error when
> remote.c finds a key that starts with "branch." and has an empty
> subsection.

Perhaps this is fine, but I think this commit message (and I checked the
CL too) really needs to work a bit harder to convince us that this is
safe to do.

Are we confident that this is just bizarro config that nobody would have
had in practice? In that case I think it's fine to start dying on it.

But as I understand we previously just ignored this, then if there's any
doubt about that perhaps we should start with a warning?

Or are we really confident that this is an edge case not worth worrying
about in that way, and that we can go straight to die()?

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

* Re: [PATCH 2/2] remote.c: reject 0-length branch names
  2022-06-01  7:30   ` Ævar Arnfjörð Bjarmason
@ 2022-06-01 16:55     ` Glen Choo
  2022-06-01 21:21       ` Junio C Hamano
  2022-06-08 23:24       ` Jeff King
  0 siblings, 2 replies; 8+ messages in thread
From: Glen Choo @ 2022-06-01 16:55 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason, Glen Choo via GitGitGadget
  Cc: git, Jeff King, Ing. Martin Prantl Ph.D.

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> On Tue, May 31 2022, Glen Choo via GitGitGadget wrote:
>
>> From: Glen Choo <chooglen@google.com>
>>
>> Branch names can't be empty, so config keys with an empty branch name,
>> e.g. "branch..remote", are silently ignored.
>>
>> Since these config keys will never be useful, make it a fatal error when
>> remote.c finds a key that starts with "branch." and has an empty
>> subsection.
>
> Perhaps this is fine, but I think this commit message (and I checked the
> CL too) really needs to work a bit harder to convince us that this is
> safe to do.

Fair.

> Are we confident that this is just bizarro config that nobody would have
> had in practice? In that case I think it's fine to start dying on it.
>
> But as I understand we previously just ignored this, then if there's any
> doubt about that perhaps we should start with a warning?
>
> Or are we really confident that this is an edge case not worth worrying
> about in that way, and that we can go straight to die()?

The case I want to make is even stronger than that - this is an edge
case that _we_ shouldn't worry about, and we should tell the _user_ that
their config is bogus.

It truly makes no sense because `branch..remote` fits the schema of
`branch.<name>.remote` where <name> is "", but "" isn't a valid branch
name (and it never has been AFAIK). So such a key would never be useful
to Git, and it would be extremely hacky for a non-Git tool to use such
a key.

I'm not sure how a user would generate such a key in the wild (e.g.
[1]). Maybe it was a typo, but more worryingly (I don't have evidence
for this, but it could happen), it might be misbehavior from `git
[branch|config]` that we never noticed because the bogus keys have flown
under the radar. If there really is a bug elsewhere, erroring out when
we see such keys might also alert us to the bug.

Perhaps I need to capture all of this in the commit message?

[1] https://lore.kernel.org/git/24f547-6285e280-59-40303580@48243747/

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

* Re: [PATCH 2/2] remote.c: reject 0-length branch names
  2022-06-01 16:55     ` Glen Choo
@ 2022-06-01 21:21       ` Junio C Hamano
  2022-06-08 23:24       ` Jeff King
  1 sibling, 0 replies; 8+ messages in thread
From: Junio C Hamano @ 2022-06-01 21:21 UTC (permalink / raw)
  To: Glen Choo
  Cc: Ævar Arnfjörð Bjarmason,
	Glen Choo via GitGitGadget, git, Jeff King,
	Ing. Martin Prantl Ph.D.

Glen Choo <chooglen@google.com> writes:

> It truly makes no sense because `branch..remote` fits the schema of
> `branch.<name>.remote` where <name> is "", but "" isn't a valid branch
> name (and it never has been AFAIK). So such a key would never be useful
> to Git, and it would be extremely hacky for a non-Git tool to use such
> a key.

Yup, we might want to reserve a bogus key or two that can never be a
branch name to allow us express "this configuration is in effect for
all branches" (e.g. "branch.*.rebase = never"), but the natural such
name would be "*" and does not have to be an empty string.


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

* Re: [PATCH 2/2] remote.c: reject 0-length branch names
  2022-06-01 16:55     ` Glen Choo
  2022-06-01 21:21       ` Junio C Hamano
@ 2022-06-08 23:24       ` Jeff King
  1 sibling, 0 replies; 8+ messages in thread
From: Jeff King @ 2022-06-08 23:24 UTC (permalink / raw)
  To: Glen Choo
  Cc: Ævar Arnfjörð Bjarmason,
	Glen Choo via GitGitGadget, git, Ing. Martin Prantl Ph.D.

On Wed, Jun 01, 2022 at 09:55:57AM -0700, Glen Choo wrote:

> > Are we confident that this is just bizarro config that nobody would have
> > had in practice? In that case I think it's fine to start dying on it.
> >
> > But as I understand we previously just ignored this, then if there's any
> > doubt about that perhaps we should start with a warning?
> >
> > Or are we really confident that this is an edge case not worth worrying
> > about in that way, and that we can go straight to die()?
> 
> The case I want to make is even stronger than that - this is an edge
> case that _we_ shouldn't worry about, and we should tell the _user_ that
> their config is bogus.

It's a tradeoff, isn't it? We don't know how the user ended up with this
config, what they were trying to do, nor how common it is. Clearly the
config makes no sense and is broken, but by alerting the user, we are:

  - maybe doing some good, because now they know that whatever they were
    trying to do didn't work, and can clean up the broken config

  - maybe doing some bad, because it was not (and is not) hurting
    anything to have config that nobody bothers to do anything with. But
    if we die, now the user is presented with a situation that they know
    nothing about, and must resolve it before continuing with their
    unrelated work.

-Peff

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

* Re: [PATCH 1/2] remote.c: don't BUG() on 0-length branch names
  2022-05-31 23:12 ` [PATCH 1/2] remote.c: don't BUG() on " Glen Choo via GitGitGadget
@ 2022-06-08 23:27   ` Jeff King
  0 siblings, 0 replies; 8+ messages in thread
From: Jeff King @ 2022-06-08 23:27 UTC (permalink / raw)
  To: Glen Choo via GitGitGadget; +Cc: git, Ing. Martin Prantl Ph.D., Glen Choo

On Tue, May 31, 2022 at 11:12:33PM +0000, Glen Choo via GitGitGadget wrote:

> Fix the bug by removing the convenience strlen functionality, so that
> 0 means that the string is 0-length. We still insert a bogus branch name
> into the hash map, but this will be fixed in a later commit.

I think this is a good change, regardless of whether we take the second
commit or not. These kind of "automagically run strlen() sometimes"
interfaces are subtle, and I think have bitten us before.

> diff --git a/remote.c b/remote.c
> index 42a4e7106e1..cf7015ae8ab 100644
> --- a/remote.c
> +++ b/remote.c
> @@ -195,9 +195,6 @@ static struct branch *find_branch(struct remote_state *remote_state,
>  	struct branches_hash_key lookup;
>  	struct hashmap_entry lookup_entry, *e;
>  
> -	if (!len)
> -		len = strlen(name);
> -
>  	lookup.str = name;
>  	lookup.len = len;
>  	hashmap_entry_init(&lookup_entry, memhash(name, len));

This changes the behavior of find_branch() without changing its
signature. So any topics in flight that use it might be subtly broken. I
think that's probably OK in this instance, since it's a file-local
static, and was added relatively recently (i.e., the blast radius is
pretty small and unlikely).

-Peff

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

end of thread, other threads:[~2022-06-08 23:27 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-31 23:12 [PATCH 0/2] remote.c: reject 0-length branch names Glen Choo via GitGitGadget
2022-05-31 23:12 ` [PATCH 1/2] remote.c: don't BUG() on " Glen Choo via GitGitGadget
2022-06-08 23:27   ` Jeff King
2022-05-31 23:12 ` [PATCH 2/2] remote.c: reject " Glen Choo via GitGitGadget
2022-06-01  7:30   ` Ævar Arnfjörð Bjarmason
2022-06-01 16:55     ` Glen Choo
2022-06-01 21:21       ` Junio C Hamano
2022-06-08 23:24       ` Jeff King

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.