git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH] upload-pack: fix broken if/else chain in config callback
@ 2018-10-24  7:27 Jeff King
  2018-10-24  8:50 ` Johannes Schindelin
  0 siblings, 1 reply; 3+ messages in thread
From: Jeff King @ 2018-10-24  7:27 UTC (permalink / raw)
  To: git; +Cc: Jeff Hostetler

The upload_pack_config() callback uses an if/else chain
like:

  if (!strcmp(var, "a"))
     ...
  else if (!strcmp(var, "b"))
     ...
  etc

This works as long as the conditions are mutually exclusive,
but one of them is not. 20b20a22f8 (upload-pack: provide a
hook for running pack-objects, 2016-05-18) added:

  else if (current_config_scope() != CONFIG_SCOPE_REPO) {
     ... check some more options ...
  }

That was fine in that commit, because it came at the end of
the chain.  But later, 10ac85c785 (upload-pack: add object
filtering for partial clone, 2017-12-08) did this:

  else if (current_config_scope() != CONFIG_SCOPE_REPO) {
     ... check some more options ...
  } else if (!strcmp("uploadpack.allowfilter", var))
     ...

We'd always check the scope condition first, meaning we'd
_only_ respect allowfilter when it's in the repo config. You
can see this with:

  git -c uploadpack.allowfilter=true upload-pack . | head -1

which will not advertise the filter capability (but will
after this patch). We never noticed because:

  - our tests always set it in the repo config

  - in protocol v2, we use a different code path that
    actually calls repo_config_get_bool() separately, so
    that _does_ work. Real-world people experimenting with
    this may be using v2.

The more recent uploadpack.allowrefinwant option is in the
same boat.

There are a few possible fixes:

  1. Bump the scope conditional back to the bottom of the
     chain. But that just means somebody else is likely to
     make the same mistake later.

  2. Make the conditional more like the others. I.e.:

       else if (!current_config_scope() != CONFIG_SCOPE_REPO &&
                !strcmp(var, "uploadpack.notallowedinrepo"))

     This works, but the idea of the original structure was
     that we may grow multiple sensitive options like this.

  3. Pull it out of the chain entirely. The chain mostly
     serves to avoid extra strcmp() calls after we've found
     a match. But it's not worth caring about those. In the
     worst case, when there isn't a match, we're already
     hitting every strcmp (and this happens regularly for
     stuff like "core.bare", etc).

This patch does (3).

Signed-off-by: Jeff King <peff@peff.net>
---
Phew. That was a lot of explanation for a small patch, but
this was sufficiently subtle I thought it worth it. And
also, I was really surprised the bug managed to exist for
this long without anybody noticing.

 upload-pack.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/upload-pack.c b/upload-pack.c
index 540778d1dd..489c18e222 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -1028,14 +1028,17 @@ static int upload_pack_config(const char *var, const char *value, void *unused)
 		keepalive = git_config_int(var, value);
 		if (!keepalive)
 			keepalive = -1;
-	} else if (current_config_scope() != CONFIG_SCOPE_REPO) {
-		if (!strcmp("uploadpack.packobjectshook", var))
-			return git_config_string(&pack_objects_hook, var, value);
 	} else if (!strcmp("uploadpack.allowfilter", var)) {
 		allow_filter = git_config_bool(var, value);
 	} else if (!strcmp("uploadpack.allowrefinwant", var)) {
 		allow_ref_in_want = git_config_bool(var, value);
 	}
+
+	if (current_config_scope() != CONFIG_SCOPE_REPO) {
+		if (!strcmp("uploadpack.packobjectshook", var))
+			return git_config_string(&pack_objects_hook, var, value);
+	}
+
 	return parse_hide_refs_config(var, value, "uploadpack");
 }
 
-- 
2.19.1.1094.gd480080bf6

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

* Re: [PATCH] upload-pack: fix broken if/else chain in config callback
  2018-10-24  7:27 [PATCH] upload-pack: fix broken if/else chain in config callback Jeff King
@ 2018-10-24  8:50 ` Johannes Schindelin
  2018-10-25 21:59   ` Josh Steadmon
  0 siblings, 1 reply; 3+ messages in thread
From: Johannes Schindelin @ 2018-10-24  8:50 UTC (permalink / raw)
  To: Jeff King; +Cc: git, Jeff Hostetler

Hi Peff,

On Wed, 24 Oct 2018, Jeff King wrote:

> The upload_pack_config() callback uses an if/else chain
> like:
> 
>   if (!strcmp(var, "a"))
>      ...
>   else if (!strcmp(var, "b"))
>      ...
>   etc
> 
> This works as long as the conditions are mutually exclusive,
> but one of them is not. 20b20a22f8 (upload-pack: provide a
> hook for running pack-objects, 2016-05-18) added:
> 
>   else if (current_config_scope() != CONFIG_SCOPE_REPO) {
>      ... check some more options ...
>   }
> 
> That was fine in that commit, because it came at the end of
> the chain.  But later, 10ac85c785 (upload-pack: add object
> filtering for partial clone, 2017-12-08) did this:
> 
>   else if (current_config_scope() != CONFIG_SCOPE_REPO) {
>      ... check some more options ...
>   } else if (!strcmp("uploadpack.allowfilter", var))
>      ...
> 
> We'd always check the scope condition first, meaning we'd
> _only_ respect allowfilter when it's in the repo config. You
> can see this with:
> 
>   git -c uploadpack.allowfilter=true upload-pack . | head -1
> 
> which will not advertise the filter capability (but will
> after this patch). We never noticed because:
> 
>   - our tests always set it in the repo config
> 
>   - in protocol v2, we use a different code path that
>     actually calls repo_config_get_bool() separately, so
>     that _does_ work. Real-world people experimenting with
>     this may be using v2.
> 
> The more recent uploadpack.allowrefinwant option is in the
> same boat.
> 
> There are a few possible fixes:
> 
>   1. Bump the scope conditional back to the bottom of the
>      chain. But that just means somebody else is likely to
>      make the same mistake later.
> 
>   2. Make the conditional more like the others. I.e.:
> 
>        else if (!current_config_scope() != CONFIG_SCOPE_REPO &&
>                 !strcmp(var, "uploadpack.notallowedinrepo"))
> 
>      This works, but the idea of the original structure was
>      that we may grow multiple sensitive options like this.
> 
>   3. Pull it out of the chain entirely. The chain mostly
>      serves to avoid extra strcmp() calls after we've found
>      a match. But it's not worth caring about those. In the
>      worst case, when there isn't a match, we're already
>      hitting every strcmp (and this happens regularly for
>      stuff like "core.bare", etc).
> 
> This patch does (3).
> 
> Signed-off-by: Jeff King <peff@peff.net>
> ---
> Phew. That was a lot of explanation for a small patch, but
> this was sufficiently subtle I thought it worth it. And
> also, I was really surprised the bug managed to exist for
> this long without anybody noticing.

Maybe a lot of explanation, but definitely a good one. The explanation and
the patch look good to me.

Thanks,
Dscho

> 
>  upload-pack.c | 9 ++++++---
>  1 file changed, 6 insertions(+), 3 deletions(-)
> 
> diff --git a/upload-pack.c b/upload-pack.c
> index 540778d1dd..489c18e222 100644
> --- a/upload-pack.c
> +++ b/upload-pack.c
> @@ -1028,14 +1028,17 @@ static int upload_pack_config(const char *var, const char *value, void *unused)
>  		keepalive = git_config_int(var, value);
>  		if (!keepalive)
>  			keepalive = -1;
> -	} else if (current_config_scope() != CONFIG_SCOPE_REPO) {
> -		if (!strcmp("uploadpack.packobjectshook", var))
> -			return git_config_string(&pack_objects_hook, var, value);
>  	} else if (!strcmp("uploadpack.allowfilter", var)) {
>  		allow_filter = git_config_bool(var, value);
>  	} else if (!strcmp("uploadpack.allowrefinwant", var)) {
>  		allow_ref_in_want = git_config_bool(var, value);
>  	}
> +
> +	if (current_config_scope() != CONFIG_SCOPE_REPO) {
> +		if (!strcmp("uploadpack.packobjectshook", var))
> +			return git_config_string(&pack_objects_hook, var, value);
> +	}
> +
>  	return parse_hide_refs_config(var, value, "uploadpack");
>  }
>  
> -- 
> 2.19.1.1094.gd480080bf6
> 

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

* Re: [PATCH] upload-pack: fix broken if/else chain in config callback
  2018-10-24  8:50 ` Johannes Schindelin
@ 2018-10-25 21:59   ` Josh Steadmon
  0 siblings, 0 replies; 3+ messages in thread
From: Josh Steadmon @ 2018-10-25 21:59 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Jeff King, git, Jeff Hostetler

On 2018.10.24 10:50, Johannes Schindelin wrote:
> Maybe a lot of explanation, but definitely a good one. The explanation and
> the patch look good to me.
> 
> Thanks,
> Dscho

Agreed, as a newbie I definitely appreciate detailed explanations. Looks
good to me as well.

Reviewed-by: Josh Steadmon <steadmon@google.com>

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

end of thread, other threads:[~2018-10-25 21:59 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-24  7:27 [PATCH] upload-pack: fix broken if/else chain in config callback Jeff King
2018-10-24  8:50 ` Johannes Schindelin
2018-10-25 21:59   ` Josh Steadmon

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).