diff mbox series

[v2] read-cache: write all indexes with the same permissions

Message ID 20181116173105.21784-1-chriscool@tuxfamily.org (mailing list archive)
State New, archived
Headers show
Series [v2] read-cache: write all indexes with the same permissions | expand

Commit Message

Christian Couder Nov. 16, 2018, 5:31 p.m. UTC
From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>

Change the code that writes out the shared index to use
mks_tempfile_sm() instead of mks_tempfile().

The create_tempfile() function is used to write out the main
".git/index" (via ".git/index.lock") using lock_file(). The
create_tempfile() function respects the umask, as it uses open() with
0666, whereas the mks_tempfile() function uses open() with 0600.

So mks_tempfile() which is used to create the shared index file is
likely to create such a file with restricted permissions compared to
the main ".git/index" file.

A bug related to this was spotted, fixed and tested for in df801f3f9f
("read-cache: use shared perms when writing shared index", 2017-06-25)
and 3ee83f48e5 ("t1700: make sure split-index respects
core.sharedrepository", 2017-06-25).

However, as noted in those commits we'd still create the file as 0600,
and would just re-chmod it depending on the setting of
core.sharedRepository. So without core.splitIndex a system with
e.g. the umask set to group writeability would work for the members of
the group, but not with core.splitIndex set, as members of the group
would not be able to access the shared index file.

Let's instead make the two consistent by using mks_tempfile_sm() and
passing 0666 in its `mode` argument.

Note that we cannot use the create_tempfile() function itself that is
used to write the main ".git/index" file because we want the XXXXXX
part of the "sharedindex_XXXXXX" argument to be replaced by a pseudo
random value and create_tempfile() doesn't do that.

Ideally we'd split up the adjust_shared_perm() function to one that
can give us the mode we want so we could just call open() instead of
open() followed by chmod(), but that's an unrelated cleanup. We
already have that minor issue with the "index" file #leftoverbits.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---

This is a simpler fix iterating from Ævar's RFC patch and the
following discussions:

https://public-inbox.org/git/20181113153235.25402-1-avarab@gmail.com/

 read-cache.c           |  3 ++-
 t/t1700-split-index.sh | 20 ++++++++++++++++++++
 2 files changed, 22 insertions(+), 1 deletion(-)

Comments

Duy Nguyen Nov. 16, 2018, 6:02 p.m. UTC | #1
On Fri, Nov 16, 2018 at 6:31 PM Christian Couder
<christian.couder@gmail.com> wrote:
> diff --git a/read-cache.c b/read-cache.c
> index 8c924506dd..ea80600bff 100644
> --- a/read-cache.c
> +++ b/read-cache.c
> @@ -3165,7 +3165,8 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
>                 struct tempfile *temp;
>                 int saved_errno;
>
> -               temp = mks_tempfile(git_path("sharedindex_XXXXXX"));
> +               /* Same permissions as the main .git/index file */

If the permission is already correct from the beginning (of this temp
file), should df801f3f9f be reverted since we don't need to adjust
permission anymore?

Or does $GIT_DIR/index go through the same adjust_shared_perm() anyway
in the end, which means df801f3f9f must stay? If so, perhaps clarify
that in the commit message.

> +               temp = mks_tempfile_sm(git_path("sharedindex_XXXXXX"), 0, 0666);
>                 if (!temp) {
>                         oidclr(&si->base_oid);
>                         ret = do_write_locked_index(istate, lock, flags);
SZEDER Gábor Nov. 16, 2018, 6:29 p.m. UTC | #2
On Fri, Nov 16, 2018 at 06:31:05PM +0100, Christian Couder wrote:
> diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh
> index 2ac47aa0e4..fa1d3d468b 100755
> --- a/t/t1700-split-index.sh
> +++ b/t/t1700-split-index.sh
> @@ -381,6 +381,26 @@ test_expect_success 'check splitIndex.sharedIndexExpire set to "never" and "now"
>  	test $(ls .git/sharedindex.* | wc -l) -le 2
>  '
>  
> +test_expect_success POSIXPERM 'same mode for index & split index' '
> +	git init same-mode &&
> +	(
> +		cd same-mode &&
> +		test_commit A &&
> +		test_modebits .git/index >index_mode &&
> +		test_must_fail git config core.sharedRepository &&
> +		git -c core.splitIndex=true status &&
> +		shared=$(ls .git/sharedindex.*) &&

I think the command substitution and 'ls' are unnecessary, and

  shared=.git/sharedindex.*

would work as well.

> +		case "$shared" in
> +		*" "*)
> +			# we have more than one???
> +			false ;;
> +		*)
> +			test_modebits "$shared" >split_index_mode &&
> +			test_cmp index_mode split_index_mode ;;
> +		esac
> +	)
> +'
> +
>  while read -r mode modebits
>  do
>  	test_expect_success POSIXPERM "split index respects core.sharedrepository $mode" '
> -- 
> 2.19.1.1053.g063ed687ac
>
Christian Couder Nov. 16, 2018, 7:10 p.m. UTC | #3
On Fri, Nov 16, 2018 at 7:03 PM Duy Nguyen <pclouds@gmail.com> wrote:
>
> On Fri, Nov 16, 2018 at 6:31 PM Christian Couder
> <christian.couder@gmail.com> wrote:
> > diff --git a/read-cache.c b/read-cache.c
> > index 8c924506dd..ea80600bff 100644
> > --- a/read-cache.c
> > +++ b/read-cache.c
> > @@ -3165,7 +3165,8 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
> >                 struct tempfile *temp;
> >                 int saved_errno;
> >
> > -               temp = mks_tempfile(git_path("sharedindex_XXXXXX"));
> > +               /* Same permissions as the main .git/index file */
>
> If the permission is already correct from the beginning (of this temp
> file), should df801f3f9f be reverted since we don't need to adjust
> permission anymore?

df801f3f9f (read-cache: use shared perms when writing shared index,
2017-06-25) was fixing the bug that permissions of the shared index
file did not take into account the shared permissions (which are about
core.sharedRepository; "shared" has a different meaning in "shared
index file" and in "shared permissions").

This fix only changes permissions before the shared permissions are
taken into account (so before adjust_shared_perm() is called).

> Or does $GIT_DIR/index go through the same adjust_shared_perm() anyway
> in the end, which means df801f3f9f must stay?

Yeah, $GIT_DIR/index goes through adjust_shared_perm() too because
create_tempfile() calls adjust_shared_perm(). So indeed df801f3f9f
must stay.

> If so, perhaps clarify
> that in the commit message.

There is already the following about df801f3f9f:

---
A bug related to this was spotted, fixed and tested for in df801f3f9f
("read-cache: use shared perms when writing shared index", 2017-06-25)
and 3ee83f48e5 ("t1700: make sure split-index respects
core.sharedrepository", 2017-06-25).

However, as noted in those commits we'd still create the file as 0600,
and would just re-chmod it depending on the setting of
core.sharedRepository.
---

So I would think that df801f3f9f should perhaps have explained that
create_tempfile() calls adjust_shared_perm(), but I don't think that
it is very relevant in this commit message. We are already talking
about df801f3f9f which should be enough to explain the issue
df801f3f9f fixed, and I think we should not need to explain in more
details why df801f3f9f did a good job. It's not as if we are reverting
it. We are just complementing it with another fix related to what
happens before adjust_shared_perm() is called.

I think rewording the comment a bit might help though, for example maybe:

/* Same initial permissions as the main .git/index file */

instead of:

/* Same permissions as the main .git/index file */

Thanks,
Christian.
Duy Nguyen Nov. 16, 2018, 7:16 p.m. UTC | #4
On Fri, Nov 16, 2018 at 8:10 PM Christian Couder
<christian.couder@gmail.com> wrote:
>
> On Fri, Nov 16, 2018 at 7:03 PM Duy Nguyen <pclouds@gmail.com> wrote:
> >
> > On Fri, Nov 16, 2018 at 6:31 PM Christian Couder
> > <christian.couder@gmail.com> wrote:
> > > diff --git a/read-cache.c b/read-cache.c
> > > index 8c924506dd..ea80600bff 100644
> > > --- a/read-cache.c
> > > +++ b/read-cache.c
> > > @@ -3165,7 +3165,8 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
> > >                 struct tempfile *temp;
> > >                 int saved_errno;
> > >
> > > -               temp = mks_tempfile(git_path("sharedindex_XXXXXX"));
> > > +               /* Same permissions as the main .git/index file */
> >
> > If the permission is already correct from the beginning (of this temp
> > file), should df801f3f9f be reverted since we don't need to adjust
> > permission anymore?
>
> df801f3f9f (read-cache: use shared perms when writing shared index,
> 2017-06-25) was fixing the bug that permissions of the shared index
> file did not take into account the shared permissions (which are about
> core.sharedRepository; "shared" has a different meaning in "shared
> index file" and in "shared permissions").
>
> This fix only changes permissions before the shared permissions are
> taken into account (so before adjust_shared_perm() is called).
>
> > Or does $GIT_DIR/index go through the same adjust_shared_perm() anyway
> > in the end, which means df801f3f9f must stay?
>
> Yeah, $GIT_DIR/index goes through adjust_shared_perm() too because
> create_tempfile() calls adjust_shared_perm(). So indeed df801f3f9f
> must stay.

Ah thanks. By the time I got to this part

> Let's instead make the two consistent by using mks_tempfile_sm() and
> passing 0666 in its `mode` argument.

went look at that function and back, I forgot about the paragraph above it.
Ævar Arnfjörð Bjarmason Nov. 16, 2018, 7:25 p.m. UTC | #5
On Fri, Nov 16 2018, SZEDER Gábor wrote:

> On Fri, Nov 16, 2018 at 06:31:05PM +0100, Christian Couder wrote:
>> diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh
>> index 2ac47aa0e4..fa1d3d468b 100755
>> --- a/t/t1700-split-index.sh
>> +++ b/t/t1700-split-index.sh
>> @@ -381,6 +381,26 @@ test_expect_success 'check splitIndex.sharedIndexExpire set to "never" and "now"
>>  	test $(ls .git/sharedindex.* | wc -l) -le 2
>>  '
>>
>> +test_expect_success POSIXPERM 'same mode for index & split index' '
>> +	git init same-mode &&
>> +	(
>> +		cd same-mode &&
>> +		test_commit A &&
>> +		test_modebits .git/index >index_mode &&
>> +		test_must_fail git config core.sharedRepository &&
>> +		git -c core.splitIndex=true status &&
>> +		shared=$(ls .git/sharedindex.*) &&
>
> I think the command substitution and 'ls' are unnecessary, and
>
>   shared=.git/sharedindex.*
>
> would work as well.

Looks like it. FWIW I just copy/pasted what an adjacent test was doing
for consistency, which was added in one of Christian's earlier changes
to this behavior.

But yeah, if the test can be made simpler in a portable way it would
make sense to make this a two-parter test cleanup & bug fix series.

>> +		case "$shared" in
>> +		*" "*)
>> +			# we have more than one???
>> +			false ;;
>> +		*)
>> +			test_modebits "$shared" >split_index_mode &&
>> +			test_cmp index_mode split_index_mode ;;
>> +		esac
>> +	)
>> +'
>> +
>>  while read -r mode modebits
>>  do
>>  	test_expect_success POSIXPERM "split index respects core.sharedrepository $mode" '
>> --
>> 2.19.1.1053.g063ed687ac
>>
Christian Couder Nov. 16, 2018, 7:25 p.m. UTC | #6
On Fri, Nov 16, 2018 at 7:29 PM SZEDER Gábor <szeder.dev@gmail.com> wrote:
>
> On Fri, Nov 16, 2018 at 06:31:05PM +0100, Christian Couder wrote:
> > diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh
> > index 2ac47aa0e4..fa1d3d468b 100755
> > --- a/t/t1700-split-index.sh
> > +++ b/t/t1700-split-index.sh
> > @@ -381,6 +381,26 @@ test_expect_success 'check splitIndex.sharedIndexExpire set to "never" and "now"
> >       test $(ls .git/sharedindex.* | wc -l) -le 2
> >  '
> >
> > +test_expect_success POSIXPERM 'same mode for index & split index' '
> > +     git init same-mode &&
> > +     (
> > +             cd same-mode &&
> > +             test_commit A &&
> > +             test_modebits .git/index >index_mode &&
> > +             test_must_fail git config core.sharedRepository &&
> > +             git -c core.splitIndex=true status &&
> > +             shared=$(ls .git/sharedindex.*) &&
>
> I think the command substitution and 'ls' are unnecessary, and
>
>   shared=.git/sharedindex.*
>
> would work as well.

If there is no shared index file with the above we would get:

shared=.git/sharedindex.*
$ echo $shared
.git/sharedindex.*

which seems bug prone to me.
Junio C Hamano Nov. 17, 2018, 8:57 a.m. UTC | #7
Christian Couder <christian.couder@gmail.com> writes:

>> > +test_expect_success POSIXPERM 'same mode for index & split index' '
>> > +     git init same-mode &&
>> > +     (
>> > +             cd same-mode &&
>> > +             test_commit A &&
>> > +             test_modebits .git/index >index_mode &&
>> > +             test_must_fail git config core.sharedRepository &&
>> > +             git -c core.splitIndex=true status &&
>> > +             shared=$(ls .git/sharedindex.*) &&
>>
>> I think the command substitution and 'ls' are unnecessary, and
>>
>>   shared=.git/sharedindex.*
>>
>> would work as well.
>
> If there is no shared index file with the above we would get:
>
> shared=.git/sharedindex.*
> $ echo $shared
> .git/sharedindex.*
>
> which seems bug prone to me.

It is not bug *PRONE*, but is already wrong, as the way this
variable is used is

        +		case "$shared" in
        +		*" "*)
        +			# we have more than one???
        +			false ;;
        +		*)
        +			test_modebits "$shared" >split_index_mode &&
        +			test_cmp index_mode split_index_mode ;;
        +		esac

i.e. we'd think there is a singleton ".git/shared/index.*" and we
can feed it to test_modebits.

So what you wrote originally is corrrect.
Junio C Hamano Nov. 17, 2018, 9:29 a.m. UTC | #8
Christian Couder <christian.couder@gmail.com> writes:

> However, as noted in those commits we'd still create the file as 0600,
> and would just re-chmod it depending on the setting of
> core.sharedRepository. So without core.splitIndex a system with
> e.g. the umask set to group writeability would work for the members of
> the group, but not with core.splitIndex set, as members of the group
> would not be able to access the shared index file.

I am not sure what the above wants to say.  If we are not making
necessary call to adjust-shared-perm, then it is irrelevant that the
lack of the call does not immediately cause an apparent problem for
users who happens to have non-restrictive group perm bit in their
umask.  Another group member whose umask is tighter will eventually
use the repository and end up creating a file unreadable to group
members.

Are you saying that we _lack_ necessary call when core.sharedRepository
is set?  If so, a commit that fixes such a bug would be the best
place to have a paragraph like the above.  If not, the above description
simply misleads the readers.

> Let's instead make the two consistent by using mks_tempfile_sm() and
> passing 0666 in its `mode` argument.

On the other hand, this is a relevant description; this patch kills
an inconsistency that is very short lived (I am assuming that there
is no bug in the current code before this patch and we make
necessary calls to adjust-shared-perm when core.sharedrepository is
set).

> Note that we cannot use the create_tempfile() function itself that is
> used to write the main ".git/index" file because we want the XXXXXX
> part of the "sharedindex_XXXXXX" argument to be replaced by a pseudo
> random value and create_tempfile() doesn't do that.

Sure.  Pseudo-random-ness is less important than the resulting
filename being unique.  "Because we are asking for a unique file to
be created, we cannot use create_tempfile() interface that is
designed to be used to create a file with known name."

But is that really worth saying, I wonder.

> Ideally we'd split up the adjust_shared_perm() function to one that
> can give us the mode we want so we could just call open() instead of
> open() followed by chmod(), but that's an unrelated cleanup.

I would drop this paragraph, as I think this is totally incorrect.
Imagine your umask is tighter than the target permission.  You ask
such a helper function and get "you want 0660".  Doing open(0660)
would not help you an iota---you'd need chmod() or fchmod() to
adjust the result anyway, which already is done by
adjust-shared-perm.

> We already have that minor issue with the "index" file
> #leftoverbits.

The above "Ideally", which I suspect is totally bogus, would show up
whey people look for that keyword in the list archive.  This is one
of the reasons why I try to write it after at least one person
sanity checks that an idea floated is worth remembering.

> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
> ---
>
> This is a simpler fix iterating from Ævar's RFC patch and the
> following discussions:
>
> https://public-inbox.org/git/20181113153235.25402-1-avarab@gmail.com/
>
>  read-cache.c           |  3 ++-
>  t/t1700-split-index.sh | 20 ++++++++++++++++++++
>  2 files changed, 22 insertions(+), 1 deletion(-)
>
> diff --git a/read-cache.c b/read-cache.c
> index 8c924506dd..ea80600bff 100644
> --- a/read-cache.c
> +++ b/read-cache.c
> @@ -3165,7 +3165,8 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
>  		struct tempfile *temp;
>  		int saved_errno;
>  
> -		temp = mks_tempfile(git_path("sharedindex_XXXXXX"));
> +		/* Same permissions as the main .git/index file */
> +		temp = mks_tempfile_sm(git_path("sharedindex_XXXXXX"), 0, 0666);
>  		if (!temp) {
>  			oidclr(&si->base_oid);
>  			ret = do_write_locked_index(istate, lock, flags);
> diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh
> index 2ac47aa0e4..fa1d3d468b 100755
> --- a/t/t1700-split-index.sh
> +++ b/t/t1700-split-index.sh
> @@ -381,6 +381,26 @@ test_expect_success 'check splitIndex.sharedIndexExpire set to "never" and "now"
>  	test $(ls .git/sharedindex.* | wc -l) -le 2
>  '
>  
> +test_expect_success POSIXPERM 'same mode for index & split index' '
> +	git init same-mode &&
> +	(
> +		cd same-mode &&
> +		test_commit A &&
> +		test_modebits .git/index >index_mode &&
> +		test_must_fail git config core.sharedRepository &&
> +		git -c core.splitIndex=true status &&
> +		shared=$(ls .git/sharedindex.*) &&
> +		case "$shared" in
> +		*" "*)
> +			# we have more than one???
> +			false ;;
> +		*)
> +			test_modebits "$shared" >split_index_mode &&
> +			test_cmp index_mode split_index_mode ;;
> +		esac
> +	)
> +'
> +
>  while read -r mode modebits
>  do
>  	test_expect_success POSIXPERM "split index respects core.sharedrepository $mode" '
Christian Couder Nov. 17, 2018, 11:19 a.m. UTC | #9
On Sat, Nov 17, 2018 at 10:29 AM Junio C Hamano <gitster@pobox.com> wrote:
>
> Christian Couder <christian.couder@gmail.com> writes:
>
> > However, as noted in those commits we'd still create the file as 0600,
> > and would just re-chmod it depending on the setting of
> > core.sharedRepository. So without core.splitIndex a system with
> > e.g. the umask set to group writeability would work for the members of
> > the group, but not with core.splitIndex set, as members of the group
> > would not be able to access the shared index file.
>
> I am not sure what the above wants to say.

I tried to improve from Ævar's previous commit message but I agree
that the above is not very clear.

> If we are not making
> necessary call to adjust-shared-perm,

The issue is that adjust_shared_perm() returns immediately when
core.sharedRepository is unset (or false). So when it is unset (or
false), and when the umask is 0022 or 0002 for example, then the index
and the shared index will not have the same permissions because one is
created using open() with mode 0666 and the other with mode 0600.

> then it is irrelevant that the
> lack of the call does not immediately cause an apparent problem for
> users who happens to have non-restrictive group perm bit in their
> umask.  Another group member whose umask is tighter will eventually
> use the repository and end up creating a file unreadable to group
> members.

The issue is that a group member with non-restrictive group perm bit
in their umask, like 0022 or 0002, will currently create an unreadable
shared index when using the repo.

I agree that it is much safer to just set core.sharedRepository to
"true" or "all", but maybe in some setups/systems it might be ok to
rely on everyone having non-restrictive group perm bit in their umask.

> Are you saying that we _lack_ necessary call when core.sharedRepository
> is set?

No, I am saying that, when it is unset, adjust_shared_perm() does nothing.

> If so, a commit that fixes such a bug would be the best
> place to have a paragraph like the above.  If not, the above description
> simply misleads the readers.

I agree that it is a bit misleading. Maybe something like:

"However, as noted in those commits we'd still create the file as
0600, and would just re-chmod it only if core.sharedRepository is set
to "true" or "all". If core.sharedRepository is unset or set to
"false", then the file mode will not be changed, so without
core.splitIndex a system with e.g. the umask set to group writeability
would work for a group member, but not with core.splitIndex set, as
group members would not be able to access the shared index file.

> > Let's instead make the two consistent by using mks_tempfile_sm() and
> > passing 0666 in its `mode` argument.
>
> On the other hand, this is a relevant description; this patch kills
> an inconsistency that is very short lived (I am assuming that there
> is no bug in the current code before this patch and we make
> necessary calls to adjust-shared-perm when core.sharedrepository is
> set).

It is unfortunately not short lived when core.sharedrepository is
unset for example as adjust_shared_perm() starts with:

int adjust_shared_perm(const char *path)
{
        int old_mode, new_mode;

        if (!get_shared_repository())
                return 0;

but get_shared_repository() will return PERM_UMASK which is 0 when
git_config_get_value("core.sharedrepository", ...) returns a non zero
value which happens when "core.sharedrepository" is unset.

Maybe there is a bug somewhere in adjust_shared_perm() or the
functions it calls, but I don't know this part of the code base much.

> > Note that we cannot use the create_tempfile() function itself that is
> > used to write the main ".git/index" file because we want the XXXXXX
> > part of the "sharedindex_XXXXXX" argument to be replaced by a pseudo
> > random value and create_tempfile() doesn't do that.
>
> Sure.  Pseudo-random-ness is less important than the resulting
> filename being unique.  "Because we are asking for a unique file to
> be created, we cannot use create_tempfile() interface that is
> designed to be used to create a file with known name."
>
> But is that really worth saying, I wonder.

I am ok with either your version or removing the above from the commit message.

> > Ideally we'd split up the adjust_shared_perm() function to one that
> > can give us the mode we want so we could just call open() instead of
> > open() followed by chmod(), but that's an unrelated cleanup.
>
> I would drop this paragraph, as I think this is totally incorrect.
> Imagine your umask is tighter than the target permission.  You ask
> such a helper function and get "you want 0660".  Doing open(0660)
> would not help you an iota---you'd need chmod() or fchmod() to
> adjust the result anyway, which already is done by
> adjust-shared-perm.

It seems to me that it is not done when "core.sharedrepository" is unset.

> > We already have that minor issue with the "index" file
> > #leftoverbits.
>
> The above "Ideally", which I suspect is totally bogus, would show up
> whey people look for that keyword in the list archive.  This is one
> of the reasons why I try to write it after at least one person
> sanity checks that an idea floated is worth remembering.

It was in Ævar's commit message and I thought it might be better to
keep it so that people looking for that keyword could find the above
as well as the previous RFC patch.
SZEDER Gábor Nov. 17, 2018, 12:24 p.m. UTC | #10
On Fri, Nov 16, 2018 at 08:25:43PM +0100, Christian Couder wrote:
> On Fri, Nov 16, 2018 at 7:29 PM SZEDER Gábor <szeder.dev@gmail.com> wrote:
> >
> > On Fri, Nov 16, 2018 at 06:31:05PM +0100, Christian Couder wrote:
> > > diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh
> > > index 2ac47aa0e4..fa1d3d468b 100755
> > > --- a/t/t1700-split-index.sh
> > > +++ b/t/t1700-split-index.sh
> > > @@ -381,6 +381,26 @@ test_expect_success 'check splitIndex.sharedIndexExpire set to "never" and "now"
> > >       test $(ls .git/sharedindex.* | wc -l) -le 2
> > >  '
> > >
> > > +test_expect_success POSIXPERM 'same mode for index & split index' '
> > > +     git init same-mode &&
> > > +     (
> > > +             cd same-mode &&
> > > +             test_commit A &&
> > > +             test_modebits .git/index >index_mode &&
> > > +             test_must_fail git config core.sharedRepository &&
> > > +             git -c core.splitIndex=true status &&
> > > +             shared=$(ls .git/sharedindex.*) &&
> >
> > I think the command substitution and 'ls' are unnecessary, and
> >
> >   shared=.git/sharedindex.*
> >
> > would work as well.
> 
> If there is no shared index file with the above we would get:
> 
> shared=.git/sharedindex.*
> $ echo $shared
> .git/sharedindex.*
> 
> which seems bug prone to me.

That's just a non-existing file, for which 'test_modebits' will print
nothing, which, in turn, will not match the modebits of '.git/index'.
And the "there are more than one shared index files" case is handled
by the case statement that was snipped from the email context.
Junio C Hamano Nov. 17, 2018, 1:05 p.m. UTC | #11
Christian Couder <christian.couder@gmail.com> writes:

> "However, as noted in those commits we'd still create the file as
> 0600, and would just re-chmod it only if core.sharedRepository is set
> to "true" or "all". If core.sharedRepository is unset or set to
> "false", then the file mode will not be changed, so without
> core.splitIndex a system with e.g. the umask set to group writeability
> would work for a group member, but not with core.splitIndex set, as
> group members would not be able to access the shared index file.

That is irrelevant.  The repository needs to be configured properly
if it wanted to be used by the members of the group, period.

> It is unfortunately not short lived when core.sharedrepository is
> unset for example as adjust_shared_perm() starts with:
>
> int adjust_shared_perm(const char *path)
> {
>         int old_mode, new_mode;
>
>         if (!get_shared_repository())
>                 return 0;
>
> but get_shared_repository() will return PERM_UMASK which is 0 when
> git_config_get_value("core.sharedrepository", ...) returns a non zero
> value which happens when "core.sharedrepository" is unset.

Which is to say, you get an unwanted result when your repository is
not configured properly.  It is not a news, and I have no sympathy.

Just configure your repository properly and you'll be fine.

>> > Ideally we'd split up the adjust_shared_perm() function to one that
>> > can give us the mode we want so we could just call open() instead of
>> > open() followed by chmod(), but that's an unrelated cleanup.
>>
>> I would drop this paragraph, as I think this is totally incorrect.
>> Imagine your umask is tighter than the target permission.  You ask
>> such a helper function and get "you want 0660".  Doing open(0660)
>> would not help you an iota---you'd need chmod() or fchmod() to
>> adjust the result anyway, which already is done by
>> adjust-shared-perm.
>
> It seems to me that it is not done when "core.sharedrepository" is unset.

So?  You are assuming that the repository is misconfigured and it is
not set to widen the perm bit in the first place, no?

>> > We already have that minor issue with the "index" file
>> > #leftoverbits.
>>
>> The above "Ideally", which I suspect is totally bogus, would show up
>> whey people look for that keyword in the list archive.  This is one
>> of the reasons why I try to write it after at least one person
>> sanity checks that an idea floated is worth remembering.
>
> It was in Ævar's commit message and I thought it might be better to
> keep it so that people looking for that keyword could find the above
> as well as the previous RFC patch.

So do you agree that open(0660) does not guarantee the result will
be group writable, the above "Ideally" is misguided nonsense, and
giving the #leftoverbits label to it will clutter the search result
and harm readers?  That's good.

Thanks.
Ævar Arnfjörð Bjarmason Nov. 17, 2018, 9:14 p.m. UTC | #12
On Sat, Nov 17 2018, Junio C Hamano wrote:

> Christian Couder <christian.couder@gmail.com> writes:
>
>> "However, as noted in those commits we'd still create the file as
>> 0600, and would just re-chmod it only if core.sharedRepository is set
>> to "true" or "all". If core.sharedRepository is unset or set to
>> "false", then the file mode will not be changed, so without
>> core.splitIndex a system with e.g. the umask set to group writeability
>> would work for a group member, but not with core.splitIndex set, as
>> group members would not be able to access the shared index file.
>
> That is irrelevant.  The repository needs to be configured properly
> if it wanted to be used by the members of the group, period.
>
>> It is unfortunately not short lived when core.sharedrepository is
>> unset for example as adjust_shared_perm() starts with:
>>
>> int adjust_shared_perm(const char *path)
>> {
>>         int old_mode, new_mode;
>>
>>         if (!get_shared_repository())
>>                 return 0;
>>
>> but get_shared_repository() will return PERM_UMASK which is 0 when
>> git_config_get_value("core.sharedrepository", ...) returns a non zero
>> value which happens when "core.sharedrepository" is unset.
>
> Which is to say, you get an unwanted result when your repository is
> not configured properly.  It is not a news, and I have no sympathy.
>
> Just configure your repository properly and you'll be fine.
>
>>> > Ideally we'd split up the adjust_shared_perm() function to one that
>>> > can give us the mode we want so we could just call open() instead of
>>> > open() followed by chmod(), but that's an unrelated cleanup.
>>>
>>> I would drop this paragraph, as I think this is totally incorrect.
>>> Imagine your umask is tighter than the target permission.  You ask
>>> such a helper function and get "you want 0660".  Doing open(0660)
>>> would not help you an iota---you'd need chmod() or fchmod() to
>>> adjust the result anyway, which already is done by
>>> adjust-shared-perm.
>>
>> It seems to me that it is not done when "core.sharedrepository" is unset.
>
> So?  You are assuming that the repository is misconfigured and it is
> not set to widen the perm bit in the first place, no?
>
>>> > We already have that minor issue with the "index" file
>>> > #leftoverbits.
>>>
>>> The above "Ideally", which I suspect is totally bogus, would show up
>>> whey people look for that keyword in the list archive.  This is one
>>> of the reasons why I try to write it after at least one person
>>> sanity checks that an idea floated is worth remembering.
>>
>> It was in Ævar's commit message and I thought it might be better to
>> keep it so that people looking for that keyword could find the above
>> as well as the previous RFC patch.
>
> So do you agree that open(0660) does not guarantee the result will
> be group writable, the above "Ideally" is misguided nonsense, and
> giving the #leftoverbits label to it will clutter the search result
> and harm readers?  That's good.

Aside from issues with the clarity of the commit message, which I'll fix
& thanks for pointing them out. I think we may have stumbled on
something more important here.

Do you mean that you don't agree that following should always create
both "foo" and e.g. ".git/refs/heads/master" with the same 644
(-rw-rw-r--) mode:

    (
        rm -rf /tmp/repo &&
        umask 022 &&
        git init /tmp/repo &&
        cd /tmp/repo &&
        echo hi >foo &&
        git add foo &&
        git commit -m"first"
    )

To me what we should do with the standard umask and what
core.sharedRepository are for are completely different things.

We should in git be creating files such that if I set my umask to
e.g. 022 all users on the system can read what I'm creating.

E.g. I tend to use this on something like a production server where
others (if I'm asleep) might want to look at my .bash_history as a last
resort, and also some one-off repo I've created without setting
core.sharedRepository.

I've yet to run into a case where this doesn't just work, aside from
core.splitIndex where before the patch here we're using a tempfile API
for something that isn't a tempfile.

This is distinct from the core.sharedRepository use-case, where you'd
like to on a per-repo basis override what you'd otherwise get with the
umask. E.g. if you have a shared server hosting a shared git repo, where
users with umask 077 will still be forced to create e.g. group rw files.
Junio C Hamano Nov. 18, 2018, 7:09 a.m. UTC | #13
Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> Do you mean that you don't agree that following should always create
> both "foo" and e.g. ".git/refs/heads/master" with the same 644
> (-rw-rw-r--) mode:
>
>     (
>         rm -rf /tmp/repo &&
>         umask 022 &&
>         git init /tmp/repo &&
>         cd /tmp/repo &&
>         echo hi >foo &&
>         git add foo &&
>         git commit -m"first"
>     )
>
> To me what we should do with the standard umask and what
> core.sharedRepository are for are completely different things.

Ahh, of course.  If you put it that way, I do agree that it gives us
a valid use case where core.sharedRepository is false and the umask
of repository owner is set to 022 (or anything that does not allow
write to group or others, and allows read to group) to let group
members only peek but not touch the contents of the repository.

I think I was distracted by the mention of ore.sharedRepository in
the proposed log message.
Ævar Arnfjörð Bjarmason Nov. 18, 2018, 12:03 p.m. UTC | #14
On Sun, Nov 18 2018, Junio C Hamano wrote:

> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>
>> Do you mean that you don't agree that following should always create
>> both "foo" and e.g. ".git/refs/heads/master" with the same 644
>> (-rw-rw-r--) mode:
>>
>>     (
>>         rm -rf /tmp/repo &&
>>         umask 022 &&
>>         git init /tmp/repo &&
>>         cd /tmp/repo &&
>>         echo hi >foo &&
>>         git add foo &&
>>         git commit -m"first"
>>     )
>>
>> To me what we should do with the standard umask and what
>> core.sharedRepository are for are completely different things.
>
> Ahh, of course.  If you put it that way, I do agree that it gives us
> a valid use case where core.sharedRepository is false and the umask
> of repository owner is set to 022 (or anything that does not allow
> write to group or others, and allows read to group) to let group
> members only peek but not touch the contents of the repository.
>
> I think I was distracted by the mention of ore.sharedRepository in
> the proposed log message.

Thanks. I'll submit a v3 with a less confusing commit message.
diff mbox series

Patch

diff --git a/read-cache.c b/read-cache.c
index 8c924506dd..ea80600bff 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -3165,7 +3165,8 @@  int write_locked_index(struct index_state *istate, struct lock_file *lock,
 		struct tempfile *temp;
 		int saved_errno;
 
-		temp = mks_tempfile(git_path("sharedindex_XXXXXX"));
+		/* Same permissions as the main .git/index file */
+		temp = mks_tempfile_sm(git_path("sharedindex_XXXXXX"), 0, 0666);
 		if (!temp) {
 			oidclr(&si->base_oid);
 			ret = do_write_locked_index(istate, lock, flags);
diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh
index 2ac47aa0e4..fa1d3d468b 100755
--- a/t/t1700-split-index.sh
+++ b/t/t1700-split-index.sh
@@ -381,6 +381,26 @@  test_expect_success 'check splitIndex.sharedIndexExpire set to "never" and "now"
 	test $(ls .git/sharedindex.* | wc -l) -le 2
 '
 
+test_expect_success POSIXPERM 'same mode for index & split index' '
+	git init same-mode &&
+	(
+		cd same-mode &&
+		test_commit A &&
+		test_modebits .git/index >index_mode &&
+		test_must_fail git config core.sharedRepository &&
+		git -c core.splitIndex=true status &&
+		shared=$(ls .git/sharedindex.*) &&
+		case "$shared" in
+		*" "*)
+			# we have more than one???
+			false ;;
+		*)
+			test_modebits "$shared" >split_index_mode &&
+			test_cmp index_mode split_index_mode ;;
+		esac
+	)
+'
+
 while read -r mode modebits
 do
 	test_expect_success POSIXPERM "split index respects core.sharedrepository $mode" '