git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH 19/24] refs.c: allow listing and deleting badly named refs

From
Junio C Hamano <gitster@pobox.com>
Date
Oct 2, 2014, 18:55 UTC
Message-ID
<xmqqa95envxa.fsf@gitster.dls.corp.google.com>
In-Reply-To
<20141002022819.GL1175@google.com>
Jonathan Nieder <jrnieder@gmail.com> writes:
Show 24 quoted lines
> From: Ronnie Sahlberg <sahlberg@google.com>
> ...
> In resolving functions, refuse to resolve refs that don't pass the
> check-ref-format(1) check unless the new RESOLVE_REF_ALLOW_BAD_NAME
> flag is passed.  Even with RESOLVE_REF_ALLOW_BAD_NAME, refuse to
> resolve refs that escape the refs/ directory and do not match the
> pattern [A-Z_]* (think "HEAD" and "MERGE_HEAD").
>
> In locking functions, refuse to act on badly named refs unless they
> are being deleted and either are in the refs/ directory or match [A-Z_]*.
>
> Just like other invalid refs, flag resolved, badly named refs with the
> REF_ISBROKEN flag, treat them as resolving to null_sha1, and skip them
> in all iteration functions except for for_each_rawref.
>
> Flag badly named refs with a REF_BAD_NAME flag to make it easier for
> future callers to notice and handle them specially.
>
> In the transaction API, refuse to create or update badly named refs,
> but allow deleting them (unless they escape refs/ and don't match
> [A-Z_]*).
>
> Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>

Thanks. We originally threw all the different kind of breakages into ISBROKEN, but a ref can have a malformed name or can contain a bad/non value and allowing us to tell them apart is a good direction to go.

Show 12 quoted lines
> diff --git a/cache.h b/cache.h
> index 5ca7f2b..0c0ac60 100644
> --- a/cache.h
> +++ b/cache.h
> @@ -978,16 +978,26 @@ extern int read_ref(const char *refname, unsigned char *sha1);
>   * If flags is non-NULL, set the value that it points to the
>   * combination of REF_ISPACKED (if the reference was found among the
>   * packed references), REF_ISSYMREF (if the initial reference was a
> - * symbolic reference) and REF_ISBROKEN (if the ref is malformed).
> + * symbolic reference), REF_BAD_NAME (if the reference name is ill
> + * formed --- see RESOLVE_REF_ALLOW_BAD_NAME below), and REF_ISBROKEN
> + * (if the ref is malformed).
You want to define "is malformed" here.
The original defines REF_ISBROKEN as "malformed" because
 (1) resolve_ref_unsafe() uses get_sha1_hex() and read_loose_refs()
     uses read_ref_full(), both to catch "malformed values" stored;
 (2) resolve_ref_unsafe() uses check_refname_format() and catches
     "malformed names" stored as a symref target.

I _think_ you are introducing ALLOW_BAD_NAME to allow add the third class ".git/refs/remotes/origin/mal..formed..name". I do not know if they should be the same class as a symref with a good name ".git/refs/remotes/origin/HEAD" that points at a bad name "mal..formed..name", which is (2) above). Perhaps not. (2) is still above what is stored in the ref, and the ref in question may or may not have a well-formed name, which is orthogonal.

So probably you left only the "value stored in the ref is malformed" (in other words, "we expected to find 40-hex object name but didn't find one") case for REF_ISBROKEN?

Do we want to separate "value is not 40-hex" and "a symref points at a malformed refname" as separate "malformed value" errors?

> + * RESOLVE_REF_ALLOW_BAD_NAME allows resolving refs even when their
> + * name is invalid according to git-check-ref-format(1).  If the name
> + * is bad then the value stored in sha1 will be null_sha1 and the
> + * REF_ISBROKEN and REF_BAD_NAME flags will be set.

Viewed with that light, I am not sure if a badly named ref should yield null_sha1[] (REF_ISBROKEN, which I am assuming is about a value that is badly formatted and cannot be read, should keep yielding it as before). Wouldn't it make it harder for the user if you give null_sha1[] back to somebody who is trying to recover by reading "refs/heads/mal..formed", creating "refs/heads/sensible" to point at the same value and then removing the former?

Note that I am not saying we should give back the parsed value at this step in the series. Perhaps there are some existing callers that do not check for ISBROKEN flag and instead says "null_sha1[] ref is to be rejected/ignored", in which case they may need to be corrected before that happens. Or there may be some reason I overlooked that makes it not so useful if we returned the object name stored in a ref whose name is malformed. Just wondering.

Show 15 quoted lines
> @@ -272,6 +272,37 @@ static struct ref_dir *get_ref_dir(struct ref_entry *entry)
>  	return dir;
>  }
>  
> +static int escapes_cwd(const char *path) {
> +	char *buf;
> +	int result;
> +
> +	if (is_absolute_path(path))
> +		return 1;
> +	buf = xmalloc(strlen(path) + 1);
> +	result = !!normalize_path_copy(buf, path);
> +	free(buf);
> +	return result;
> +}
I think this function is misnamed for two reasons.
 - It does not have anything to do with cwd; it does not make any
   difference to the outcome of this function given the same input,
   if 'pwd' says "/u/jc/git" or "/u/jc/git/Documentation", no?
 - Even if this had something to do with cwd, I would expect a
   function whose name is escapes_cwd("/u/jc/git/Documentation") to
   yield false when 'pwd' says "/u/jc/git", but the implementation
   unconditionally rejects absolute path.  In the context of the
   (sole) caller of this function, which deals with a refname "refs/...",
   it makes no sense to see an absolute path, but that does not have
   anything to do with "does this path escape cwd?", no?
Show 7 quoted lines
> +/*
> + * Check if a refname is safe.
> + * For refs that start with "refs/" we consider it safe as long as the rest
> + * of the path components does not allow it to escape from this directory.
> + * For all other refs we only consider them safe iff they only contain
> + * upper case characters and '_'.
> + */

I presume that the exception is to accomodate for "HEAD", "ORIG_HEAD", "MERGE_HEAD" and friends, but you probably do not want the readers to guess.

Show 11 quoted lines
> +static int refname_is_safe(const char *refname)
> +{
> +	if (starts_with(refname, "refs/"))
> +		return !escapes_cwd(refname + strlen("refs/"));
> +	while (*refname) {
> +		if (!isupper(*refname) && *refname != '_')
> +			return 0;
> +		refname++;
> +	}
> +	return 1;
> +}
Previous: Jonathan NiederNext: Ronnie Sahlberg
Message 121 of 129 in “Transaction patch series overview”
  1. Ronnie SahlbergJul 30, 2014
  2. Ronnie SahlbergJul 31, 2014
  3. Ronnie SahlbergAug 8, 2014
  4. Ronnie SahlbergAug 19, 2014
  5. Junio C HamanoAug 19, 2014
  6. Jonathan NiederAug 20, 2014
  7. Jonathan NiederAug 26, 2014
  8. Junio C HamanoAug 26, 2014
  9. Jonathan NiederAug 26, 2014
  10. 0/20 rs/ref-transaction-1 (Re: Transaction patch series overview)Jonathan Nieder, Aug 27, 2014
  11. 01/20 refs.c: change ref_transaction_create to do error checking and return statusJonathan Nieder, Aug 27, 2014
  12. 02/20 refs.c: update ref_transaction_delete to check for error and return statusJonathan Nieder, Aug 27, 2014
  13. 03/20 refs.c: make ref_transaction_begin take an err argumentJonathan Nieder, Aug 27, 2014
  14. 04/20 refs.c: add transaction.status and track OPEN/CLOSEDJonathan Nieder, Aug 27, 2014
  15. 05/20 tag.c: use ref transactions when doing updatesJonathan Nieder, Aug 27, 2014
  16. 06/20 replace.c: use the ref transaction functions for updatesJonathan Nieder, Aug 27, 2014
  17. 07/20 commit.c: use ref transactions for updatesJonathan Nieder, Aug 27, 2014
  18. 08/20 sequencer.c: use ref transactions for all ref updatesJonathan Nieder, Aug 27, 2014
  19. 09/20 fast-import.c: change update_branch to use ref transactionsJonathan Nieder, Aug 27, 2014
  20. 10/20 branch.c: use ref transaction for all ref updatesJonathan Nieder, Aug 27, 2014
  21. 11/20 refs.c: change update_ref to use a transactionJonathan Nieder, Aug 27, 2014
  22. 12/20 receive-pack.c: use a reference transaction for updating the refsJonathan Nieder, Aug 27, 2014
  23. 13/20 fast-import.c: use a ref transaction when dumping tagsJonathan Nieder, Aug 27, 2014
  24. 14/20 walker.c: use ref transaction for ref updatesJonathan Nieder, Aug 27, 2014
  25. 15/20 refs.c: make lock_ref_sha1 staticJonathan Nieder, Aug 27, 2014
  26. 16/20 refs.c: remove the update_ref_lock functionJonathan Nieder, Aug 27, 2014
  27. 17/20 refs.c: remove the update_ref_write functionJonathan Nieder, Aug 27, 2014
  28. 18/20 refs.c: remove lock_ref_sha1Jonathan Nieder, Aug 27, 2014
  29. 19/20 refs.c: make prune_ref use a transaction to delete the refJonathan Nieder, Aug 27, 2014
  30. 20/20 refs.c: make delete_ref use a transactionJonathan Nieder, Aug 27, 2014
  31. Junio C HamanoAug 27, 2014
  32. Junio C HamanoAug 27, 2014
  33. 0/22 rs/ref-transaction-1 (Re: Transaction patch series overview)Jonathan Nieder, Sep 2, 2014
  34. 01/22 refs.c: change ref_transaction_create to do error checking and return statusJonathan Nieder, Sep 2, 2014
  35. 02/22 refs.c: update ref_transaction_delete to check for error and return statusJonathan Nieder, Sep 2, 2014
  36. 03/22 refs.c: make ref_transaction_begin take an err argumentJonathan Nieder, Sep 2, 2014
  37. 04/22 refs.c: add transaction.status and track OPEN/CLOSEDJonathan Nieder, Sep 2, 2014
  38. 05/22 tag.c: use ref transactions when doing updatesJonathan Nieder, Sep 2, 2014
  39. 06/22 replace.c: use the ref transaction functions for updatesJonathan Nieder, Sep 2, 2014
  40. 07/22 commit.c: use ref transactions for updatesJonathan Nieder, Sep 2, 2014
  41. 08/22 sequencer.c: use ref transactions for all ref updatesJonathan Nieder, Sep 2, 2014
  42. 09/22 fast-import.c: change update_branch to use ref transactionsJonathan Nieder, Sep 2, 2014
  43. 10/22 branch.c: use ref transaction for all ref updatesJonathan Nieder, Sep 2, 2014
  44. 11/22 refs.c: change update_ref to use a transactionJonathan Nieder, Sep 2, 2014
  45. 12/22 receive-pack.c: use a reference transaction for updating the refsJonathan Nieder, Sep 2, 2014
  46. 13/22 fast-import.c: use a ref transaction when dumping tagsJonathan Nieder, Sep 2, 2014
  47. 14/22 walker.c: use ref transaction for ref updatesJonathan Nieder, Sep 2, 2014
  48. 15/22 refs.c: make lock_ref_sha1 staticJonathan Nieder, Sep 2, 2014
  49. 16/22 refs.c: remove the update_ref_lock functionJonathan Nieder, Sep 2, 2014
  50. 17/22 refs.c: remove the update_ref_write functionJonathan Nieder, Sep 2, 2014
  51. 18/22 refs.c: remove lock_ref_sha1Jonathan Nieder, Sep 2, 2014
  52. 19/22 refs.c: make prune_ref use a transaction to delete the refJonathan Nieder, Sep 2, 2014
  53. 20/22 refs.c: make delete_ref use a transactionJonathan Nieder, Sep 2, 2014
  54. 21/22 update-ref --stdin: narrow scope of err strbufJonathan Nieder, Sep 2, 2014
  55. 22/22 update-ref --stdin: pass transaction around explicitlyJonathan Nieder, Sep 2, 2014
  56. Using Gerrit to review Git patches (was: Re: Transaction patch series overview)Michael Haggerty, Aug 27, 2014
  57. Shawn PearceAug 28, 2014
  58. 0/19 rs/ref-transaction (Re: Transaction patch series overview)Jonathan Nieder, Sep 11, 2014
  59. 01/19 mv test: recreate mod/ directory instead of relying on stale copyJonathan Nieder, Sep 11, 2014
  60. 02/19 wrapper.c: remove/unlink_or_warn: simplify, treat ENOENT as successJonathan Nieder, Sep 11, 2014
  61. 03/19 wrapper.c: add a new function unlink_or_msgJonathan Nieder, Sep 11, 2014
  62. 04/19 refs.c: add an err argument to delete_ref_looseJonathan Nieder, Sep 11, 2014
  63. 05/19 refs.c: pass the ref log message to _create/delete/update instead of _commitJonathan Nieder, Sep 11, 2014
  64. 06/19 rename_ref: don't ask read_ref_full where the ref came fromJonathan Nieder, Sep 11, 2014
  65. 07/19 refs.c: move the check for valid refname to lock_ref_sha1_basicJonathan Nieder, Sep 11, 2014
  66. 08/19 refs.c: call lock_ref_sha1_basic directly from commitJonathan Nieder, Sep 11, 2014
  67. 09/19 refs.c: pass a skip list to name_conflict_fnJonathan Nieder, Sep 11, 2014
  68. 10/19 refs.c: ref_transaction_commit: distinguish name conflicts from other errorsJonathan Nieder, Sep 11, 2014
  69. 11/19 fetch.c: change s_update_ref to use a ref transactionJonathan Nieder, Sep 11, 2014
  70. 12/19 refs.c: make write_ref_sha1 staticJonathan Nieder, Sep 11, 2014
  71. 13/19 refs.c: change resolve_ref_unsafe reading argument to be a flags fieldJonathan Nieder, Sep 11, 2014
  72. 14/19 branch -d: avoid repeated symref resolutionJonathan Nieder, Sep 11, 2014
  73. 15/19 refs.c: fix handling of badly named refsJonathan Nieder, Sep 11, 2014
  74. 16/19 for-each-ref.c: improve message before aborting on broken refJonathan Nieder, Sep 11, 2014
  75. 17/19 refs.c: do not permit err == NULLJonathan Nieder, Sep 11, 2014
  76. 18/19 lockfile: remove unable_to_lock_errorJonathan Nieder, Sep 11, 2014
  77. 19/19 ref_transaction_commit: bail out on failure to remove a refJonathan Nieder, Sep 11, 2014
  78. Junio C HamanoSep 11, 2014
  79. Junio C HamanoSep 11, 2014
  80. Jonathan NiederSep 12, 2014
  81. Junio C HamanoSep 12, 2014
  82. Jonathan NiederSep 12, 2014
  83. Junio C HamanoSep 12, 2014
  84. Junio C HamanoSep 12, 2014
  85. Junio C HamanoSep 13, 2014
  86. Michael HaggertySep 12, 2014
  87. Jonathan NiederSep 12, 2014
  88. Michael HaggertySep 17, 2014
  89. Junio C HamanoSep 18, 2014
  90. Jonathan NiederSep 18, 2014
  91. Junio C HamanoSep 18, 2014
  92. Jonathan NiederSep 18, 2014
  93. Junio C HamanoSep 25, 2014
  94. Jonathan NiederSep 25, 2014
  95. Junio C HamanoSep 25, 2014
  96. 0/24 rs/ref-transactionJonathan Nieder, Oct 2, 2014
  97. 01/24 mv test: recreate mod/ directory instead of relying on stale copyJonathan Nieder, Oct 2, 2014
  98. 02/24 wrapper.c: remove/unlink_or_warn: simplify, treat ENOENT as successJonathan Nieder, Oct 2, 2014
  99. 03/24 wrapper.c: add a new function unlink_or_msgJonathan Nieder, Oct 2, 2014
  100. 04/24 refs.c: add an err argument to delete_ref_looseJonathan Nieder, Oct 2, 2014
  101. 05/24 refs.c: pass the ref log message to _create/delete/update instead of _commitJonathan Nieder, Oct 2, 2014
  102. 06/24 rename_ref: don't ask read_ref_full where the ref came fromJonathan Nieder, Oct 2, 2014
  103. 07/24 refs.c: refuse to lock badly named refs in lock_ref_sha1_basicJonathan Nieder, Oct 2, 2014
  104. 08/24 refs.c: call lock_ref_sha1_basic directly from commitJonathan Nieder, Oct 2, 2014
  105. 09/24 refs.c: pass a list of names to skip to is_refname_availableJonathan Nieder, Oct 2, 2014
  106. Junio C HamanoOct 2, 2014
  107. Jonathan NiederOct 3, 2014
  108. Junio C HamanoOct 3, 2014
  109. 09/24 refs.c: pass a list of names to skip to is_refname_availableJonathan Nieder, Oct 3, 2014
  110. Junio C HamanoOct 7, 2014
  111. 10/24 refs.c: ref_transaction_commit: distinguish name conflicts from other errorsJonathan Nieder, Oct 2, 2014
  112. 11/24 fetch.c: change s_update_ref to use a ref transactionJonathan Nieder, Oct 2, 2014
  113. 12/24 refs.c: make write_ref_sha1 staticJonathan Nieder, Oct 2, 2014
  114. 13/24 refs.c: change resolve_ref_unsafe reading argument to be a flags fieldJonathan Nieder, Oct 2, 2014
  115. 14/24 reflog test: test interaction with detached HEADJonathan Nieder, Oct 2, 2014
  116. 15/24 branch -d: avoid repeated symref resolutionJonathan Nieder, Oct 2, 2014
  117. 16/24 branch -d: simplify by using RESOLVE_REF_READING flagJonathan Nieder, Oct 2, 2014
  118. 17/24 packed-ref cache: forbid dot-components in refnamesJonathan Nieder, Oct 2, 2014
  119. 18/24 test: put tests for handling of bad ref names in one placeJonathan Nieder, Oct 2, 2014
  120. 19/24 refs.c: allow listing and deleting badly named refsJonathan Nieder, Oct 2, 2014
  121. Junio C HamanoOct 2, 2014
  122. Ronnie SahlbergOct 3, 2014
  123. Ronnie SahlbergOct 3, 2014
  124. Junio C HamanoOct 3, 2014
  125. 20/24 for-each-ref.c: improve message before aborting on broken refJonathan Nieder, Oct 2, 2014
  126. 21/24 remote rm/prune: print a message when writing packed-refs failsJonathan Nieder, Oct 2, 2014
  127. 22/24 refs.c: do not permit err == NULLJonathan Nieder, Oct 2, 2014
  128. 23/24 lockfile: remove unable_to_lock_errorJonathan Nieder, Oct 2, 2014
  129. 24/24 ref_transaction_commit: bail out on failure to remove a refJonathan Nieder, Oct 2, 2014

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.