From: Michael Haggerty <mhagger@alum.mit.edu>
To: Junio C Hamano <gitster@pobox.com>
Cc: Jens Lehmann <jens.lehmann@web.de>, git@vger.kernel.org
Subject: Re: [PATCH] resolve_gitlink_ref_recursive(): verify format of symbolic refs
Date: Sat, 28 Jun 2014 07:34:09 +0200 [thread overview]
Message-ID: <53AE53D1.9020905@alum.mit.edu> (raw)
In-Reply-To: <xmqq61jm2pz7.fsf@gitster.dls.corp.google.com>
On 06/27/2014 07:59 PM, Junio C Hamano wrote:
> Junio C Hamano <gitster@pobox.com> writes:
>
>> Michael Haggerty <mhagger@alum.mit.edu> writes:
>>
>>> When reading a symbolic ref via resolve_gitlink_ref_recursive(), check
>>> that the reference name that is pointed at is formatted correctly,
>>> using the same check as resolve_ref_unsafe() uses for non-gitlink
>>> references. This prevents bogosity like
>>>
>>> ref: ../../other/file
>>>
>>> from causing problems.
>>
>> I do agree that a textual symref "ref: ../../x/y" that is stored in
>> ".git/HEAD" or in ".git/refs/L" will step outside ".git/" and it is
>> problematic. But if ".git/refs/heads/a/b/LINK" has "ref: ../../x"
>> in it, shouldn't we interpret it as referring to the ref at
>> "refs/heads/x"?
I've never seen that usage, nor seen it advocated. Symrefs are not
propagated via the Git protocol, so even if somebody were doing this
privately, it could hardly be a project-wide practice. I can't think of
a practical use for this feature. And it would be mildly annoying to
implement. So my inclination is to forbid it.
> Actually, the textual symrefs have been invented to replace symbolic
> links used for .git/HEAD on symlink-incapable filesystems, and we do
> even not let the filesystem follow symlinks. The rule we have there
> are like so:
>
> /* Follow "normalized" - ie "refs/.." symlinks by hand */
> if (S_ISLNK(st.st_mode)) {
> len = readlink(path, buffer, sizeof(buffer)-1);
> if (len < 0) {
> if (errno == ENOENT || errno == EINVAL)
> /* inconsistent with lstat; retry */
> goto stat_ref;
> else
> return NULL;
> }
> buffer[len] = 0;
> if (starts_with(buffer, "refs/") &&
> !check_refname_format(buffer, 0)) {
> strcpy(refname_buffer, buffer);
> refname = refname_buffer;
> if (flag)
> *flag |= REF_ISSYMREF;
> continue;
> }
> }
>
> So we should do exactly the same check, I would think, no?
I think you overlooked that if the (starts_with() &&
!check_refname_format()) check fails, execution falls through, ending up
here:
/*
* Anything else, just open it and try to use it as
* a ref
*/
fd = open(path, O_RDONLY);
if (fd < 0) {
if (errno == ENOENT)
/* inconsistent with lstat; retry */
goto stat_ref;
else
return NULL;
}
len = read_in_full(fd, buffer, sizeof(buffer)-1);
close(fd);
[...etc...]
This has been the behavior since time immemorial [1].
In fact, another bug (which I probably introduced) is that in the case
of a symlink that points at a non-existent file, this code goes into an
infinite loop due to the "if (errno == ENOENT) goto stat_ref" in the
code that I quoted. My mistake was forgetting that lstat() is statting
the link whereas open() follows the link, so the success of the former
does not imply that the latter should not ENOENT.
I suggest we fix both problems by making the code behave the way you
*thought* it behaves: symlinks are never followed via the filesystem,
but if the symlink contents have the form of a legitimate refname that
starts with "refs/", then we follow it the same way as we would follow a
textual-style symref.
> In a typical clone, the ".git/refs/remotes/origin/HEAD" textual
> symref stores "ref: refs/remotes/origin/master" and it is neither
> "ref: master" nor "ref: ./master", so it should be sensible to
> insist on "must start with 'refs/' and its format valid."
Yes, we don't even have a notation for "relative refnames" because we
would have no way to distinguish them from "absolute refnames" except
maybe via some artifice like a "./" prefix.
Michael
[1] Where by "time immemorial" I mean "since before I ever touched refs.c".
--
Michael Haggerty
mhagger@alum.mit.edu
prev parent reply other threads:[~2014-06-28 5:34 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-06-27 11:01 [PATCH] resolve_gitlink_ref_recursive(): verify format of symbolic refs Michael Haggerty
2014-06-27 17:53 ` Junio C Hamano
2014-06-27 17:59 ` Junio C Hamano
2014-06-28 5:34 ` Michael Haggerty [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=53AE53D1.9020905@alum.mit.edu \
--to=mhagger@alum.mit.edu \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=jens.lehmann@web.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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 NNTP newsgroup(s).