git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] repack.c: chmod +w before rename()
@ 2014-01-24 21:05 Torsten Bögershausen
  2014-01-24 21:40 ` brian m. carlson
  2014-01-24 23:31 ` Junio C Hamano
  0 siblings, 2 replies; 7+ messages in thread
From: Torsten Bögershausen @ 2014-01-24 21:05 UTC (permalink / raw)
  To: git
  Cc: tboegi, zwanzig12, stefanbeller, kusmabite, Johannes.Schindelin,
	msysgit

commit a1bbc6c0 "repack: rewrite the shell script in C" introduced
a possible regression, when a Git repo is located on a Windows network share.

When git gc is called on an already packed repository, it could fail like this:
"fatal: renaming '.git/objects/pack/.tmp-xyz.pack' failed: Permission denied"

Temporary *.pack and *.idx files remain in .git/objects/pack/

In a1bbc6c0 the rename() function replaced the "mv -f" shell command.

Obviously the -f option can also override a read-only file but
rename() can not on a network share.

Make the C-code to work similar to the shell script, by making the
files writable before calling rename().

Another solution could be to do the "chmod +x" in mingw_rename().
This may be done in another commit, because
a) It improves git gc only when Git for Windows is used
   on the client machine
b) Windows refuses to delete a file when the file is read-only.
   So setting a file to read-only under Windows is a way for a user
   to protect it from being deleted.
   Changing the behaviour of rename() globally may not be what we want.

Reported-by: Jochen Haag <zwanzig12@googlemail.com>
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
---
 builtin/repack.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/builtin/repack.c b/builtin/repack.c
index ba66c6e..033b4c2 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -324,6 +324,10 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 				statbuffer.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
 				chmod(fname_old, statbuffer.st_mode);
 			}
+			if (!stat(fname, &statbuffer)) {
+				statbuffer.st_mode |= (S_IWUSR | S_IWGRP | S_IWOTH);
+				chmod(fname, statbuffer.st_mode);
+			}
 			if (rename(fname_old, fname))
 				die_errno(_("renaming '%s' failed"), fname_old);
 			free(fname);
-- 
1.9.rc0.143.g6fd479e

-- 
-- 
*** Please reply-to-all at all times ***
*** (do not pretend to know who is subscribed and who is not) ***
*** Please avoid top-posting. ***
The msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.

You received this message because you are subscribed to the Google
Groups "msysGit" group.
To post to this group, send email to msysgit@googlegroups.com
To unsubscribe from this group, send email to
msysgit+unsubscribe@googlegroups.com
For more options, and view previous threads, visit this group at
http://groups.google.com/group/msysgit?hl=en_US?hl=en

--- 
You received this message because you are subscribed to the Google Groups "msysGit" group.
To unsubscribe from this group and stop receiving emails from it, send an email to msysgit+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

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

* Re: [PATCH] repack.c: chmod +w before rename()
  2014-01-24 21:05 [PATCH] repack.c: chmod +w before rename() Torsten Bögershausen
@ 2014-01-24 21:40 ` brian m. carlson
  2014-01-24 22:24   ` Johannes Schindelin
  2014-01-24 23:31 ` Junio C Hamano
  1 sibling, 1 reply; 7+ messages in thread
From: brian m. carlson @ 2014-01-24 21:40 UTC (permalink / raw)
  To: Torsten Bögershausen
  Cc: git, zwanzig12, stefanbeller, kusmabite, Johannes.Schindelin,
	msysgit

[-- Attachment #1: Type: text/plain, Size: 2462 bytes --]

On Fri, Jan 24, 2014 at 10:05:14PM +0100, Torsten Bögershausen wrote:
> commit a1bbc6c0 "repack: rewrite the shell script in C" introduced
> a possible regression, when a Git repo is located on a Windows network share.
> 
> When git gc is called on an already packed repository, it could fail like this:
> "fatal: renaming '.git/objects/pack/.tmp-xyz.pack' failed: Permission denied"
> 
> Temporary *.pack and *.idx files remain in .git/objects/pack/
> 
> In a1bbc6c0 the rename() function replaced the "mv -f" shell command.
> 
> Obviously the -f option can also override a read-only file but
> rename() can not on a network share.
> 
> Make the C-code to work similar to the shell script, by making the
> files writable before calling rename().
> 
> Another solution could be to do the "chmod +x" in mingw_rename().
> This may be done in another commit, because
> a) It improves git gc only when Git for Windows is used
>    on the client machine
> b) Windows refuses to delete a file when the file is read-only.
>    So setting a file to read-only under Windows is a way for a user
>    to protect it from being deleted.
>    Changing the behaviour of rename() globally may not be what we want.
> 
> Reported-by: Jochen Haag <zwanzig12@googlemail.com>
> Signed-off-by: Torsten Bögershausen <tboegi@web.de>
> ---
>  builtin/repack.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/builtin/repack.c b/builtin/repack.c
> index ba66c6e..033b4c2 100644
> --- a/builtin/repack.c
> +++ b/builtin/repack.c
> @@ -324,6 +324,10 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
>  				statbuffer.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
>  				chmod(fname_old, statbuffer.st_mode);
>  			}
> +			if (!stat(fname, &statbuffer)) {
> +				statbuffer.st_mode |= (S_IWUSR | S_IWGRP | S_IWOTH);
> +				chmod(fname, statbuffer.st_mode);
> +			}

Are we sure that the file in question can never be a symlink?  Because
if it is, we'll end up changing the permissions on the wrong file.  In
general, I'm wary of changing permissions on a file to suit Windows's
rename because of the symlink issue and the security issues that can
result.  Hard links probably have the same issue.

-- 
brian m. carlson / brian with sandals: Houston, Texas, US
+1 832 623 2791 | http://www.crustytoothpaste.net/~bmc | My opinion only
OpenPGP: RSA v4 4096b: 88AC E9B2 9196 305B A994 7552 F1BA 225C 0223 B187

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH] repack.c: chmod +w before rename()
  2014-01-24 21:40 ` brian m. carlson
@ 2014-01-24 22:24   ` Johannes Schindelin
  2014-01-24 22:49     ` brian m. carlson
  2014-01-24 23:32     ` Junio C Hamano
  0 siblings, 2 replies; 7+ messages in thread
From: Johannes Schindelin @ 2014-01-24 22:24 UTC (permalink / raw)
  To: brian m. carlson
  Cc: Torsten Bögershausen, git, zwanzig12, stefanbeller,
	kusmabite, msysgit

Hi Brian,

On Fri, 24 Jan 2014, brian m. carlson wrote:

> On Fri, Jan 24, 2014 at 10:05:14PM +0100, Torsten Bögershausen wrote:
> > diff --git a/builtin/repack.c b/builtin/repack.c
> > index ba66c6e..033b4c2 100644
> > --- a/builtin/repack.c
> > +++ b/builtin/repack.c
> > @@ -324,6 +324,10 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
> >  				statbuffer.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
> >  				chmod(fname_old, statbuffer.st_mode);
> >  			}
> > +			if (!stat(fname, &statbuffer)) {
> > +				statbuffer.st_mode |= (S_IWUSR | S_IWGRP | S_IWOTH);
> > +				chmod(fname, statbuffer.st_mode);
> > +			}
> 
> Are we sure that the file in question can never be a symlink?

On Windows: yes. Otherwise, no.

Having said that, the files in question are files generated by Git, so you
really would have to tamper with things in order to get into trouble.

> Because if it is, we'll end up changing the permissions on the wrong
> file.

In any case, I'd rather change the permissions only when the rename
failed. *And* I feel uncomfortable ignoring the return value...

> In general, I'm wary of changing permissions on a file to suit Windows's
> rename because of the symlink issue and the security issues that can
> result.

I agree on the Windows issue.

> Hard links probably have the same issue.

No, hard links have their own permissions. If you change the permissions
on a hardlink, any other hardlinks to the same content are unaffected.

Ciao,
Johannes

-- 
-- 
*** Please reply-to-all at all times ***
*** (do not pretend to know who is subscribed and who is not) ***
*** Please avoid top-posting. ***
The msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.

You received this message because you are subscribed to the Google
Groups "msysGit" group.
To post to this group, send email to msysgit@googlegroups.com
To unsubscribe from this group, send email to
msysgit+unsubscribe@googlegroups.com
For more options, and view previous threads, visit this group at
http://groups.google.com/group/msysgit?hl=en_US?hl=en

--- 
You received this message because you are subscribed to the Google Groups "msysGit" group.
To unsubscribe from this group and stop receiving emails from it, send an email to msysgit+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

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

* Re: [PATCH] repack.c: chmod +w before rename()
  2014-01-24 22:24   ` Johannes Schindelin
@ 2014-01-24 22:49     ` brian m. carlson
  2014-01-24 23:50       ` Mike Hommey
  2014-01-24 23:32     ` Junio C Hamano
  1 sibling, 1 reply; 7+ messages in thread
From: brian m. carlson @ 2014-01-24 22:49 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: Torsten Bögershausen, git, zwanzig12, stefanbeller,
	kusmabite, msysgit

[-- Attachment #1: Type: text/plain, Size: 1747 bytes --]

On Fri, Jan 24, 2014 at 11:24:36PM +0100, Johannes Schindelin wrote:
> > In general, I'm wary of changing permissions on a file to suit Windows's
> > rename because of the symlink issue and the security issues that can
> > result.
> 
> I agree on the Windows issue.

I personally feel that if Windows needs help to change permissions for a
rename, that code should only ever be used on Windows.  Doesn't
mingw_rename automatically do this anyway, and if it doesn't, shouldn't
we put the code there instead?  Furthermore, it makes me very nervous to
make the file 666.  Isn't 644 enough?

> > Hard links probably have the same issue.
> 
> No, hard links have their own permissions. If you change the permissions
> on a hardlink, any other hardlinks to the same content are unaffected.

Not according to link(2):

  This new name may be used exactly as the old one for any operation;
  both names refer to the same file (and so have the same permissions
  and ownership) and it is impossible to tell which name was the
  "original".

My testing confirms this.

More importantly, while one might not want to symlink a pack frequently,
git clone -l does use hard links.  This means that if a local clone is
made somewhere, and then the original repository is repacked and hits
this case, the clone is now vulnerable to tampering by a malicious user
(assuming that user can read the appropriate directory).  So unless I'm
reading this wrong, this patch would cause security problems on all Unix
systems.

-- 
brian m. carlson / brian with sandals: Houston, Texas, US
+1 832 623 2791 | http://www.crustytoothpaste.net/~bmc | My opinion only
OpenPGP: RSA v4 4096b: 88AC E9B2 9196 305B A994 7552 F1BA 225C 0223 B187

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH] repack.c: chmod +w before rename()
  2014-01-24 21:05 [PATCH] repack.c: chmod +w before rename() Torsten Bögershausen
  2014-01-24 21:40 ` brian m. carlson
@ 2014-01-24 23:31 ` Junio C Hamano
  1 sibling, 0 replies; 7+ messages in thread
From: Junio C Hamano @ 2014-01-24 23:31 UTC (permalink / raw)
  To: Torsten Bögershausen
  Cc: git, zwanzig12, stefanbeller, kusmabite, Johannes.Schindelin,
	msysgit

Torsten Bögershausen <tboegi@web.de> writes:

> Another solution could be to do the "chmod +x" in mingw_rename().
> This may be done in another commit, because
> a) It improves git gc only when Git for Windows is used
>    on the client machine
> b) Windows refuses to delete a file when the file is read-only.
>    So setting a file to read-only under Windows is a way for a user
>    to protect it from being deleted.
>    Changing the behaviour of rename() globally may not be what we want.

But doesn't this affect non Windows platforms in negative ways?  We
unconditionally run stat(2) and chmod(2) unnecessarily, and we leave
the resulting file writable when it originally may have been marked
read-only on purpose.

Also, it feels to me that doing this in mingw_rename() the right
approach in the first place.  If the user wants "git mv a b" to
rename "a" in the working tree and if that path is read-only, what
happens, and what should happen?  Does "chmod -w" on a file in the
working tree mean "I want to make sure nobody accidentally writes to
it, and also I want to protect it from being renamed or deleted"?

So perhaps mingw_rename() can be taught to

 - First try to just do rename(), and if it succeeds, happily return
   without doing anything extra.

 - If it fails, then

   - check if the failure is due to read-only-ness (optional: if you
     cannot reliably tell this from the error code, do not bother),
     and if not, return failure.

   - otherwise, stat() to grab the current permission bits, do the
     chmod(), retry the rename, then restore the permission bits
     with another chmod().  Return failure if any of these steps
     fail.

That way, it can cover any call to rename(), be it for packfiles or
a path in the working tree, and you would need to pay the overhead
of stat/chmod only when it matters, no?

> Reported-by: Jochen Haag <zwanzig12@googlemail.com>
> Signed-off-by: Torsten Bögershausen <tboegi@web.de>
> ---
>  builtin/repack.c | 4 ++++
>  1 file changed, 4 insertions(+)
>
> diff --git a/builtin/repack.c b/builtin/repack.c
> index ba66c6e..033b4c2 100644
> --- a/builtin/repack.c
> +++ b/builtin/repack.c
> @@ -324,6 +324,10 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
>  				statbuffer.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
>  				chmod(fname_old, statbuffer.st_mode);
>  			}
> +			if (!stat(fname, &statbuffer)) {
> +				statbuffer.st_mode |= (S_IWUSR | S_IWGRP | S_IWOTH);
> +				chmod(fname, statbuffer.st_mode);
> +			}
>  			if (rename(fname_old, fname))
>  				die_errno(_("renaming '%s' failed"), fname_old);
>  			free(fname);
> -- 
> 1.9.rc0.143.g6fd479e
>
> -- 

-- 
-- 
*** Please reply-to-all at all times ***
*** (do not pretend to know who is subscribed and who is not) ***
*** Please avoid top-posting. ***
The msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.

You received this message because you are subscribed to the Google
Groups "msysGit" group.
To post to this group, send email to msysgit@googlegroups.com
To unsubscribe from this group, send email to
msysgit+unsubscribe@googlegroups.com
For more options, and view previous threads, visit this group at
http://groups.google.com/group/msysgit?hl=en_US?hl=en

--- 
You received this message because you are subscribed to the Google Groups "msysGit" group.
To unsubscribe from this group and stop receiving emails from it, send an email to msysgit+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

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

* Re: [PATCH] repack.c: chmod +w before rename()
  2014-01-24 22:24   ` Johannes Schindelin
  2014-01-24 22:49     ` brian m. carlson
@ 2014-01-24 23:32     ` Junio C Hamano
  1 sibling, 0 replies; 7+ messages in thread
From: Junio C Hamano @ 2014-01-24 23:32 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: brian m. carlson, Torsten Bögershausen, git, zwanzig12,
	stefanbeller, kusmabite, msysgit

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

> In any case, I'd rather change the permissions only when the rename
> failed. *And* I feel uncomfortable ignoring the return value...

Good judgement I'd agree with 100%.

Thanks.

-- 
-- 
*** Please reply-to-all at all times ***
*** (do not pretend to know who is subscribed and who is not) ***
*** Please avoid top-posting. ***
The msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.

You received this message because you are subscribed to the Google
Groups "msysGit" group.
To post to this group, send email to msysgit@googlegroups.com
To unsubscribe from this group, send email to
msysgit+unsubscribe@googlegroups.com
For more options, and view previous threads, visit this group at
http://groups.google.com/group/msysgit?hl=en_US?hl=en

--- 
You received this message because you are subscribed to the Google Groups "msysGit" group.
To unsubscribe from this group and stop receiving emails from it, send an email to msysgit+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

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

* Re: [PATCH] repack.c: chmod +w before rename()
  2014-01-24 22:49     ` brian m. carlson
@ 2014-01-24 23:50       ` Mike Hommey
  0 siblings, 0 replies; 7+ messages in thread
From: Mike Hommey @ 2014-01-24 23:50 UTC (permalink / raw)
  To: Johannes Schindelin, Torsten Bögershausen, git, zwanzig12,
	stefanbeller, kusmabite, msysgit

On Fri, Jan 24, 2014 at 10:49:13PM +0000, brian m. carlson wrote:
> On Fri, Jan 24, 2014 at 11:24:36PM +0100, Johannes Schindelin wrote:
> > > In general, I'm wary of changing permissions on a file to suit Windows's
> > > rename because of the symlink issue and the security issues that can
> > > result.
> > 
> > I agree on the Windows issue.
> 
> I personally feel that if Windows needs help to change permissions for a
> rename, that code should only ever be used on Windows.  Doesn't
> mingw_rename automatically do this anyway, and if it doesn't, shouldn't
> we put the code there instead?  Furthermore, it makes me very nervous to
> make the file 666.  Isn't 644 enough?

Arguably, umask is supposed to take care of making things right. OTOH,
since it's the destination file that's the problem not the renamed file,
the equivalent to mv -f would be to unlink() that file first, not to change
its permissions. That would work properly on unix too.

Mike

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

end of thread, other threads:[~2014-01-24 23:51 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-01-24 21:05 [PATCH] repack.c: chmod +w before rename() Torsten Bögershausen
2014-01-24 21:40 ` brian m. carlson
2014-01-24 22:24   ` Johannes Schindelin
2014-01-24 22:49     ` brian m. carlson
2014-01-24 23:50       ` Mike Hommey
2014-01-24 23:32     ` Junio C Hamano
2014-01-24 23:31 ` Junio C Hamano

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