git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH] fetch: allow running as different users in shared repositories
@ 2020-03-19  1:03 Vadim Zeitlin
  2020-03-25 19:04 ` Johannes Schindelin
  0 siblings, 1 reply; 6+ messages in thread
From: Vadim Zeitlin @ 2020-03-19  1:03 UTC (permalink / raw)
  To: git; +Cc: Vadim Zeitlin, Johannes Schindelin

The function fopen_for_writing(), which was added in 79d7582e32 (commit:
allow editing the commit message even in shared repos, 2016-01-06) and
used for overwriting FETCH_HEAD since ea56518dfe (Handle more file
writes correctly in shared repos, 2016-01-11), didn't do it correctly in
shared repositories under Linux.

This happened because in this situation the file FETCH_HEAD has mode 644
and attempting to overwrite it when running git-fetch under an account
different from the one that was had originally created it, failed with
EACCES, and not EPERM. However fopen_for_writing() only checked for the
latter, and not the former, so it didn't even try removing the existing
file and recreating it, as it was supposed to do.

Fix this by checking for either EACCES or EPERM. The latter doesn't seem
to be ever returned in a typical situation by open(2) under Linux, but
keep checking for it as it is presumably returned under some other
platform, although it's not really clear where does this happen.

Signed-off-by: Vadim Zeitlin <vz-git@zeitlins.org>
---
I couldn't find any system that would return EPERM for a "normal"
permissions denied error, so maybe it's not worth checking for it, but I
wanted to minimize the number of changes to the existing behaviour. At the
very least, testing for EACCES is definitely necessary under Linux, where
openat(2) returns it, and not EPERM, in the situation described above, i.e.
non-writable file (even if it's in a writable directory, allowing to unlink
it without problems).
---
 wrapper.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/wrapper.c b/wrapper.c
index e1eaef2e16..f5607241da 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -373,11 +373,12 @@ FILE *fopen_for_writing(const char *path)
 {
 	FILE *ret = fopen(path, "w");
 
-	if (!ret && errno == EPERM) {
+	if (!ret && (errno == EACCES || errno == EPERM)) {
+		int open_error = errno;
 		if (!unlink(path))
 			ret = fopen(path, "w");
 		else
-			errno = EPERM;
+			errno = open_error;
 	}
 	return ret;
 }
-- 
2.26.0.rc2

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

* Re: [PATCH] fetch: allow running as different users in shared repositories
  2020-03-19  1:03 [PATCH] fetch: allow running as different users in shared repositories Vadim Zeitlin
@ 2020-03-25 19:04 ` Johannes Schindelin
  0 siblings, 0 replies; 6+ messages in thread
From: Johannes Schindelin @ 2020-03-25 19:04 UTC (permalink / raw)
  To: Vadim Zeitlin; +Cc: git

Hi Vadim,

On Thu, 19 Mar 2020, Vadim Zeitlin wrote:

> The function fopen_for_writing(), which was added in 79d7582e32 (commit:
> allow editing the commit message even in shared repos, 2016-01-06) and
> used for overwriting FETCH_HEAD since ea56518dfe (Handle more file
> writes correctly in shared repos, 2016-01-11), didn't do it correctly in
> shared repositories under Linux.
>
> This happened because in this situation the file FETCH_HEAD has mode 644

I wonder why that is. In a shared repository, it should have mode 664, I
thought.

> and attempting to overwrite it when running git-fetch under an account
> different from the one that was had originally created it, failed with
> EACCES, and not EPERM. However fopen_for_writing() only checked for the
> latter, and not the former, so it didn't even try removing the existing
> file and recreating it, as it was supposed to do.
>
> Fix this by checking for either EACCES or EPERM. The latter doesn't seem
> to be ever returned in a typical situation by open(2) under Linux, but
> keep checking for it as it is presumably returned under some other
> platform, although it's not really clear where does this happen.
>
> Signed-off-by: Vadim Zeitlin <vz-git@zeitlins.org>
> ---
> I couldn't find any system that would return EPERM for a "normal"
> permissions denied error, so maybe it's not worth checking for it, but I
> wanted to minimize the number of changes to the existing behaviour. At the
> very least, testing for EACCES is definitely necessary under Linux, where
> openat(2) returns it, and not EPERM, in the situation described above, i.e.
> non-writable file (even if it's in a writable directory, allowing to unlink
> it without problems).

That rationale makes sense to me, as does the patch.

Thanks,
Johannes

> ---
>  wrapper.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/wrapper.c b/wrapper.c
> index e1eaef2e16..f5607241da 100644
> --- a/wrapper.c
> +++ b/wrapper.c
> @@ -373,11 +373,12 @@ FILE *fopen_for_writing(const char *path)
>  {
>  	FILE *ret = fopen(path, "w");
>
> -	if (!ret && errno == EPERM) {
> +	if (!ret && (errno == EACCES || errno == EPERM)) {
> +		int open_error = errno;
>  		if (!unlink(path))
>  			ret = fopen(path, "w");
>  		else
> -			errno = EPERM;
> +			errno = open_error;
>  	}
>  	return ret;
>  }
> --
> 2.26.0.rc2
>

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

* Re: [PATCH] fetch: allow running as different users in shared repositories
@ 2020-03-26  0:44 Vadim Zeitlin
  2020-03-26 14:40 ` Johannes Schindelin
  0 siblings, 1 reply; 6+ messages in thread
From: Vadim Zeitlin @ 2020-03-26  0:44 UTC (permalink / raw)
  To: johannes.schindelin; +Cc: git

On Wed, 25 Mar 2020 20:04:09 +0100 Johannes Schindelin wrote:

JS> Hi Vadim,

 Hello Johannes and thanks for your reply!

JS> On Thu, 19 Mar 2020, Vadim Zeitlin wrote:
JS> 
JS> > The function fopen_for_writing(), which was added in 79d7582e32 (commit:
JS> > allow editing the commit message even in shared repos, 2016-01-06) and
JS> > used for overwriting FETCH_HEAD since ea56518dfe (Handle more file
JS> > writes correctly in shared repos, 2016-01-11), didn't do it correctly in
JS> > shared repositories under Linux.
JS> >
JS> > This happened because in this situation the file FETCH_HEAD has mode 644
JS> 
JS> I wonder why that is. In a shared repository, it should have mode 664, I
JS> thought.

 This file is created using a simple fopen("w") and so is subject to umask.
With the usual default umask value (022) its mode would be 644, regardless
of the repository settings.

[...snip my original description...]
JS> That rationale makes sense to me, as does the patch.

 Sorry for a possibly stupid question, but what is the next thing to do
now? The instructions in Documentation/SubmittingPatches indicate that I
should wait until the "list forms consensus that [...] your patch is good",
but it's not quite clear what indicates that a consensus has been reached.
Is your comment above enough or should I wait for something else? And
if/when it has been reached, do I really I need to resend the patch to
the maintainer and cc the list as written in that document? I'm a bit
surprised by this because I don't see (most) patches being resent to this
list.

 This is obviously very non-urgent, but I'd just like to understand what,
if anything, is expected from me.

 Thanks in advance for your guidance!
VZ

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

* Re: [PATCH] fetch: allow running as different users in shared repositories
  2020-03-26  0:44 Vadim Zeitlin
@ 2020-03-26 14:40 ` Johannes Schindelin
  2020-05-01 23:11   ` Re[2]: " Vadim Zeitlin
  0 siblings, 1 reply; 6+ messages in thread
From: Johannes Schindelin @ 2020-03-26 14:40 UTC (permalink / raw)
  To: Vadim Zeitlin; +Cc: git

Hi Vadim,

On Thu, 26 Mar 2020, Vadim Zeitlin wrote:

> On Wed, 25 Mar 2020 20:04:09 +0100 Johannes Schindelin wrote:
>
> JS> Hi Vadim,
>
>  Hello Johannes and thanks for your reply!
>
> JS> On Thu, 19 Mar 2020, Vadim Zeitlin wrote:
> JS>
> JS> > The function fopen_for_writing(), which was added in 79d7582e32 (commit:
> JS> > allow editing the commit message even in shared repos, 2016-01-06) and
> JS> > used for overwriting FETCH_HEAD since ea56518dfe (Handle more file
> JS> > writes correctly in shared repos, 2016-01-11), didn't do it correctly in
> JS> > shared repositories under Linux.
> JS> >
> JS> > This happened because in this situation the file FETCH_HEAD has mode 644
> JS>
> JS> I wonder why that is. In a shared repository, it should have mode 664, I
> JS> thought.
>
>  This file is created using a simple fopen("w") and so is subject to umask.
> With the usual default umask value (022) its mode would be 644, regardless
> of the repository settings.

Maybe we should change that to an `open()` call with the explicit `0666`
mode?

> [...snip my original description...]
> JS> That rationale makes sense to me, as does the patch.
>
>  Sorry for a possibly stupid question, but what is the next thing to do
> now? The instructions in Documentation/SubmittingPatches indicate that I
> should wait until the "list forms consensus that [...] your patch is good",
> but it's not quite clear what indicates that a consensus has been reached.
> Is your comment above enough or should I wait for something else? And
> if/when it has been reached, do I really I need to resend the patch to
> the maintainer and cc the list as written in that document? I'm a bit
> surprised by this because I don't see (most) patches being resent to this
> list.

My take is that this was waiting for a review, and I provided it (*not*
asking for any changes), and if there are no further reviews, the patch
should make it into the `pu` branch, then `next` and eventually `master`,
at which point it will be slated for the next official `.0` version.

It might make sense to ask for it to be trickled down into the `maint`
branch, too, in case a `v2.26.1` is released. I would be in favor of that,
but would not do the asking myself ;-)

Ciao,
Johannes

>
>  This is obviously very non-urgent, but I'd just like to understand what,
> if anything, is expected from me.
>
>  Thanks in advance for your guidance!
> VZ
>

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

* Re: [PATCH] fetch: allow running as different users in shared repositories
  2020-05-01 23:11   ` Re[2]: " Vadim Zeitlin
@ 2020-05-04 16:32     ` Junio C Hamano
  2020-05-04 17:04       ` Re[2]: " Vadim Zeitlin
  0 siblings, 1 reply; 6+ messages in thread
From: Junio C Hamano @ 2020-05-04 16:32 UTC (permalink / raw)
  To: Vadim Zeitlin; +Cc: git, Johannes Schindelin

Vadim Zeitlin <vz-git@zeitlins.org> writes:

>  So I'd just like to ask directly, hoping that it's not inappropriate:
> Junio, do I need to do anything to get this patch accepted or am I just
> being too impatient?

I do not even recall seeing the discussion, so you are right to
suspect that it fell thru the cracks, and it is quite appropriate to
ping the thread directly like you did.  Mind resending the patch to
the list, just to make sure nobody else sees any problems with it?

Thanks.

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

* Re: [PATCH] fetch: allow running as different users in shared repositories
  2020-05-04 17:04       ` Re[2]: " Vadim Zeitlin
@ 2020-05-04 20:39         ` Junio C Hamano
  0 siblings, 0 replies; 6+ messages in thread
From: Junio C Hamano @ 2020-05-04 20:39 UTC (permalink / raw)
  To: Vadim Zeitlin; +Cc: git, Johannes Schindelin

Vadim Zeitlin <vz-git@zeitlins.org> writes:

> From: Vadim Zeitlin <vz-git@zeitlins.org>
> Subject: [PATCH] fetch: allow running as different users in shared repositories

This pretends the change to affect ONLY "git fetch", but ...

> The function fopen_for_writing(), which was added in 79d7582e32 (commit:
> allow editing the commit message even in shared repos, 2016-01-06) and
> used for overwriting FETCH_HEAD since ea56518dfe (Handle more file
> writes correctly in shared repos, 2016-01-11), didn't do it correctly in
> shared repositories under Linux.

... fopen_for_writing() is not only about FETCH_HEAD.  In fact, the
author of this patch knows "git fetch" was not the primary target.

So, we need to make sure that (1) this change is beneficial to those
other codepaths that use the helper function, and (2) describe the
(good) effect of the patch on these other users in the log message.
We also need to retitle the commit.

Hits from "git grep fopen_for_writing" are

builtin/commit.c:812:	s->fp = fopen_for_writing(git_path_commit_editmsg());

That's .git/COMMIT_EDITMSG file.

builtin/fast-export.c:1049:	f = fopen_for_writing(file);

This is inside export_marks() to create the marks file.

builtin/fetch.c:1191:	FILE *fp = fopen_for_writing(filename);

This is the .git/FETCH_HEAD.

> This happened because in this situation the file FETCH_HEAD has mode 644
> and attempting to overwrite it when running git-fetch under an account
> different from the one that was had originally created it, failed with
> EACCES, and not EPERM.

Isn't that because FETCH_HEAD and others are not concluded with
adjust_shared_perm()?  The fopen_for_writing() that removes and
recreates the target file sounds like a band-aid to me.  The right
fix we should have done when we did 79d7582e (commit: allow editing
the commit message even in shared repos, 2016-01-06) would have been
to open(2) with 0666 (and let the umask(2) adjust it), and then use
adjust_shared_perm() to give it the desired protection bits.  With
the existing band-aid, we won't be able to fix incorrectly created
append-only files, for example, as the band-aid depends on the
contents in the existing file being expendable.

Having said all that, I agree that EACCES is the right errno to
detect for this band-aid, at least for FETCH_HEAD.

I think COMMIT_EDITMSG is also left after "git commit" finishes,
so it will share the same issue with FETCH_HEAD and the same fix
should apply (this is just a hint for you to write an updated
proposed log message for the patch).

I haven't looked at or analysed how fast-export will get affected.
I think it is used to create and leave a "marks" file, to be later
read by another instance of the fast-export process, which may (or
may not) further write new contents to the (same?) "marks" file, but
I do not know the ramifications of unlinking and recreating.  In any
case, even if that is broken, it is not a new breakage this patch is
introducing.  You may want to look at it further to make sure you
are not breaking things, though.

So, here are the things I would like to see in this area:

 - The same patch text, but with updated commit log message, to tell
   readers that we have looked at all the callers that are affected,
   and retitle it (e.g. "fopen_for_writing: detect the reason why fopen()
   failed correctly" or something like that, perhaps?).
   
 - Audit other codepaths that create .git/ALL_CAPS_FILE (e.g.  I see
   that "git branch --edit-description" creates a temporary file to
   edit without fopen_for_writing() band-aid and it does not use
   adjust_shared_perm(), but I think it should) and fix them.

 - The existing repositories have these files created and left whose
   permission bits were set according to the then-current umask
   without taking "core.sharedrepository" into account, so we have
   to keep the "if unable to open for writing, unlink and recreate"
   trick to salvage them.  But it does not mean we need to keep
   creating the files with wrong mode.  Update fopen_for_writing()
   and its users to leave the file created in the right mode by
   calling adjust_shared_perm().  I think fopen_for_writing() should
   switch from calling fopen(3) to calling open(2) and then fdopen(3)
   on the result as the first step.

The first one is better done by you to tie the loose ends for this
discussion.  

Other two items do not have to be done by you.  Anybody interested
can do them as a clean-up (only if people agree that it is a good
idea to do so---so I won't mark this as a left-over-bits yet).

Thanks.

> diff --git a/wrapper.c b/wrapper.c
> index e1eaef2e16..f5607241da 100644
> --- a/wrapper.c
> +++ b/wrapper.c
> @@ -373,11 +373,12 @@ FILE *fopen_for_writing(const char *path)
>  {
>  	FILE *ret = fopen(path, "w");
>  
> -	if (!ret && errno == EPERM) {
> +	if (!ret && (errno == EACCES || errno == EPERM)) {
> +		int open_error = errno;
>  		if (!unlink(path))
>  			ret = fopen(path, "w");
>  		else
> -			errno = EPERM;
> +			errno = open_error;
>  	}
>  	return ret;
>  }

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

end of thread, other threads:[~2020-05-04 20:40 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-19  1:03 [PATCH] fetch: allow running as different users in shared repositories Vadim Zeitlin
2020-03-25 19:04 ` Johannes Schindelin
  -- strict thread matches above, loose matches on Subject: below --
2020-03-26  0:44 Vadim Zeitlin
2020-03-26 14:40 ` Johannes Schindelin
2020-05-01 23:11   ` Re[2]: " Vadim Zeitlin
2020-05-04 16:32     ` Junio C Hamano
2020-05-04 17:04       ` Re[2]: " Vadim Zeitlin
2020-05-04 20:39         ` Junio C Hamano

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