git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] commit-graph: write non-split graphs as read-only
@ 2020-04-20 22:50 Taylor Blau
  2020-04-20 22:51 ` [PATCH 1/3] tempfile.c: introduce 'create_tempfile_mode' Taylor Blau
                   ` (5 more replies)
  0 siblings, 6 replies; 36+ messages in thread
From: Taylor Blau @ 2020-04-20 22:50 UTC (permalink / raw)
  To: git; +Cc: dstolee, mhagger, peff

Hi,

A colleague of mine pointed out they had occasionally observed that some
layers of a commit-graph chain appear to be have both read and write
permission bits for the user, while others are marked as read-only.

After some investigation, I realized that this only happens to the first
layer in a commit-graph-chain, and occurs when we move a non-split graph
into a chain as the new base. Since write_commit_graph() just renames in
this case, we carry over the 0644 permissions that we create non-split
graphs with, even though split graphs are created to be read-only.

Initially, I resolved this by 'chmod(graph, 0444)'-ing the graph after
renaming it into place, but it ends up being much cleaner if we
introduce an additional parameter in 'hold_lock_file_for_update' for a
mode.

The first two patches set this up, and the third patch uses it in
commit-graph.c, and corrects some test fallout. Eventually, we may want
to take another look at all of this and always create lockfiles with
permission 0444, but that change is much larger than this one and could
instead be done over time.

Thanks,
Taylor

Taylor Blau (3):
  tempfile.c: introduce 'create_tempfile_mode'
  lockfile.c: introduce 'hold_lock_file_for_update_mode'
  commit-graph.c: write non-split graphs as read-only

 commit-graph.c          |  3 ++-
 lockfile.c              | 18 ++++++++++--------
 lockfile.h              | 19 +++++++++++++++++--
 t/t5318-commit-graph.sh | 11 ++++++++++-
 t/t6600-test-reach.sh   |  2 ++
 tempfile.c              |  6 +++---
 tempfile.h              |  7 ++++++-
 7 files changed, 50 insertions(+), 16 deletions(-)

--
2.26.1.108.gadb95c98e4

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

* [PATCH 1/3] tempfile.c: introduce 'create_tempfile_mode'
  2020-04-20 22:50 [PATCH 0/3] commit-graph: write non-split graphs as read-only Taylor Blau
@ 2020-04-20 22:51 ` Taylor Blau
  2020-04-20 23:31   ` Junio C Hamano
  2020-04-20 22:51 ` [PATCH 2/3] lockfile.c: introduce 'hold_lock_file_for_update_mode' Taylor Blau
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 36+ messages in thread
From: Taylor Blau @ 2020-04-20 22:51 UTC (permalink / raw)
  To: git; +Cc: dstolee, mhagger, peff

In the next patch, 'hold_lock_file_for_update' will gain an additional
'mode' parameter to specify permissions for the associated temporary
file.

Since the lockfile.c machinery uses 'create_tempfile' which always
creates a temporary file with global read-write permissions, introduce a
variant here that allows specifying the mode.

Arguably, all temporary files should have permission 0444, since they
are likely to be renamed into place and then not written to again. This
is a much larger change than we may want to take on in this otherwise
small patch, so for the time being, make 'create_tempfile' behave as it
has always done by inlining it to 'create_tempfile_mode' with mode set
to '0666'.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 tempfile.c | 6 +++---
 tempfile.h | 7 ++++++-
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/tempfile.c b/tempfile.c
index d43ad8c191..94aa18f3f7 100644
--- a/tempfile.c
+++ b/tempfile.c
@@ -130,17 +130,17 @@ static void deactivate_tempfile(struct tempfile *tempfile)
 }
 
 /* Make sure errno contains a meaningful value on error */
-struct tempfile *create_tempfile(const char *path)
+struct tempfile *create_tempfile_mode(const char *path, int mode)
 {
 	struct tempfile *tempfile = new_tempfile();
 
 	strbuf_add_absolute_path(&tempfile->filename, path);
 	tempfile->fd = open(tempfile->filename.buf,
-			    O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0666);
+			    O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, mode);
 	if (O_CLOEXEC && tempfile->fd < 0 && errno == EINVAL)
 		/* Try again w/o O_CLOEXEC: the kernel might not support it */
 		tempfile->fd = open(tempfile->filename.buf,
-				    O_RDWR | O_CREAT | O_EXCL, 0666);
+				    O_RDWR | O_CREAT | O_EXCL, mode);
 	if (tempfile->fd < 0) {
 		deactivate_tempfile(tempfile);
 		return NULL;
diff --git a/tempfile.h b/tempfile.h
index cddda0a33c..b5760d4581 100644
--- a/tempfile.h
+++ b/tempfile.h
@@ -89,7 +89,12 @@ struct tempfile {
  * a tempfile (whose "fd" member can be used for writing to it), or
  * NULL on error. It is an error if a file already exists at that path.
  */
-struct tempfile *create_tempfile(const char *path);
+struct tempfile *create_tempfile_mode(const char *path, int mode);
+
+static inline struct tempfile *create_tempfile(const char *path)
+{
+	return create_tempfile_mode(path, 0666);
+}
 
 /*
  * Register an existing file as a tempfile, meaning that it will be
-- 
2.26.1.108.gadb95c98e4


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

* [PATCH 2/3] lockfile.c: introduce 'hold_lock_file_for_update_mode'
  2020-04-20 22:50 [PATCH 0/3] commit-graph: write non-split graphs as read-only Taylor Blau
  2020-04-20 22:51 ` [PATCH 1/3] tempfile.c: introduce 'create_tempfile_mode' Taylor Blau
@ 2020-04-20 22:51 ` Taylor Blau
  2020-04-20 22:51 ` [PATCH 3/3] commit-graph.c: write non-split graphs as read-only Taylor Blau
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 36+ messages in thread
From: Taylor Blau @ 2020-04-20 22:51 UTC (permalink / raw)
  To: git; +Cc: dstolee, mhagger, peff

We use 'hold_lock_file_for_update' (and the '_timeout') variant to
acquire a lock when updating references, the commit-graph file, and so
on.

In particular, the commit-graph machinery uses this to acquire a
temporary file that is used to write a non-split commit-graph. In a
subsequent commit, an issue in the commit-graph machinery produces
graph files that have a different permission based on whether or not
they are part of a multi-layer graph will be addressed.

To do so, the commit-graph machinery will need a version of
'hold_lock_file_for_update' that takes the permission bits from the
caller.

Introduce such a function in this patch for both the
'hold_lock_file_for_update' and 'hold_lock_file_for_update_timeout'
functions, and leave the existing functions alone by inlining their
definitions in terms of the new mode variants.

Note that even though the commit-graph machinery only calls
'hold_lock_file_for_update', that this is defined in terms of
'hold_lock_file_for_update_timeout', and so both need an additional mode
parameter here.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 lockfile.c | 18 ++++++++++--------
 lockfile.h | 19 +++++++++++++++++--
 2 files changed, 27 insertions(+), 10 deletions(-)

diff --git a/lockfile.c b/lockfile.c
index 8e8ab4f29f..cc9a4b8428 100644
--- a/lockfile.c
+++ b/lockfile.c
@@ -70,7 +70,8 @@ static void resolve_symlink(struct strbuf *path)
 }
 
 /* Make sure errno contains a meaningful value on error */
-static int lock_file(struct lock_file *lk, const char *path, int flags)
+static int lock_file(struct lock_file *lk, const char *path, int flags,
+		     int mode)
 {
 	struct strbuf filename = STRBUF_INIT;
 
@@ -79,7 +80,7 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)
 		resolve_symlink(&filename);
 
 	strbuf_addstr(&filename, LOCK_SUFFIX);
-	lk->tempfile = create_tempfile(filename.buf);
+	lk->tempfile = create_tempfile_mode(filename.buf, mode);
 	strbuf_release(&filename);
 	return lk->tempfile ? lk->tempfile->fd : -1;
 }
@@ -99,7 +100,7 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)
  * exactly once. If timeout_ms is -1, try indefinitely.
  */
 static int lock_file_timeout(struct lock_file *lk, const char *path,
-			     int flags, long timeout_ms)
+			     int flags, long timeout_ms, int mode)
 {
 	int n = 1;
 	int multiplier = 1;
@@ -107,7 +108,7 @@ static int lock_file_timeout(struct lock_file *lk, const char *path,
 	static int random_initialized = 0;
 
 	if (timeout_ms == 0)
-		return lock_file(lk, path, flags);
+		return lock_file(lk, path, flags, mode);
 
 	if (!random_initialized) {
 		srand((unsigned int)getpid());
@@ -121,7 +122,7 @@ static int lock_file_timeout(struct lock_file *lk, const char *path,
 		long backoff_ms, wait_ms;
 		int fd;
 
-		fd = lock_file(lk, path, flags);
+		fd = lock_file(lk, path, flags, mode);
 
 		if (fd >= 0)
 			return fd; /* success */
@@ -169,10 +170,11 @@ NORETURN void unable_to_lock_die(const char *path, int err)
 }
 
 /* This should return a meaningful errno on failure */
-int hold_lock_file_for_update_timeout(struct lock_file *lk, const char *path,
-				      int flags, long timeout_ms)
+int hold_lock_file_for_update_timeout_mode(struct lock_file *lk,
+					   const char *path, int flags,
+					   long timeout_ms, int mode)
 {
-	int fd = lock_file_timeout(lk, path, flags, timeout_ms);
+	int fd = lock_file_timeout(lk, path, flags, timeout_ms, mode);
 	if (fd < 0) {
 		if (flags & LOCK_DIE_ON_ERROR)
 			unable_to_lock_die(path, errno);
diff --git a/lockfile.h b/lockfile.h
index 9843053ce8..12f25279b5 100644
--- a/lockfile.h
+++ b/lockfile.h
@@ -159,9 +159,17 @@ struct lock_file {
  * timeout_ms is -1, retry indefinitely. The flags argument and error
  * handling are described above.
  */
-int hold_lock_file_for_update_timeout(
+int hold_lock_file_for_update_timeout_mode(
 		struct lock_file *lk, const char *path,
-		int flags, long timeout_ms);
+		int flags, long timeout_ms, int mode);
+
+static inline int hold_lock_file_for_update_timeout(
+		struct lock_file *lk, const char *path,
+		int flags, long timeout_ms)
+{
+	return hold_lock_file_for_update_timeout_mode(lk, path, flags,
+						      timeout_ms, 0666);
+}
 
 /*
  * Attempt to create a lockfile for the file at `path` and return a
@@ -175,6 +183,13 @@ static inline int hold_lock_file_for_update(
 	return hold_lock_file_for_update_timeout(lk, path, flags, 0);
 }
 
+static inline int hold_lock_file_for_update_mode(
+		struct lock_file *lk, const char *path,
+		int flags, int mode)
+{
+	return hold_lock_file_for_update_timeout_mode(lk, path, flags, 0, mode);
+}
+
 /*
  * Return a nonzero value iff `lk` is currently locked.
  */
-- 
2.26.1.108.gadb95c98e4


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

* [PATCH 3/3] commit-graph.c: write non-split graphs as read-only
  2020-04-20 22:50 [PATCH 0/3] commit-graph: write non-split graphs as read-only Taylor Blau
  2020-04-20 22:51 ` [PATCH 1/3] tempfile.c: introduce 'create_tempfile_mode' Taylor Blau
  2020-04-20 22:51 ` [PATCH 2/3] lockfile.c: introduce 'hold_lock_file_for_update_mode' Taylor Blau
@ 2020-04-20 22:51 ` Taylor Blau
  2020-04-20 23:23 ` [PATCH 0/3] commit-graph: " Junio C Hamano
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 36+ messages in thread
From: Taylor Blau @ 2020-04-20 22:51 UTC (permalink / raw)
  To: git; +Cc: dstolee, mhagger, peff

In the previous commit, Git learned 'hold_lock_file_for_update_mode' to
allow the caller to specify the permission bits used when acquiring a
temporary file.

Use this in the commit-graph machinery for writing a non-split graph to
acquire an opened temporary file with permissions read-only permissions
to match the split behavior. (In the split case, Git uses
'git_mkstemp_mode' for each of the commit-graph layers with permission
bits '0444').

One can notice this discrepancy when moving a non-split graph to be part
of a new chain. This causes a commit-graph chain where all layers have
read-only permission bits, except for the base layer, which is writable
for the current user.

Resolve this discrepancy by using the new
'hold_lock_file_for_update_mode' and passing the desired permission
bits.

Doing so causes some test fallout in t5318 and t6600. In t5318, this
occurs in tests that corrupt a commit-graph file by writing into it. For
these, 'chmod u+w'-ing the file beforehand resolves the issue. The
additional spot in 'corrupt_graph_verify' is necessary because of the
extra 'git commit-graph write' beforehand (which *does* rewrite the
commit-graph file). In t6600, this is caused by copying a read-only
commit-graph file into place and then trying to replace it. For these,
make these files writable.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 commit-graph.c          |  3 ++-
 t/t5318-commit-graph.sh | 11 ++++++++++-
 t/t6600-test-reach.sh   |  2 ++
 3 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/commit-graph.c b/commit-graph.c
index f013a84e29..5b5047a7dd 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -1388,7 +1388,8 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 
 		f = hashfd(fd, ctx->graph_name);
 	} else {
-		hold_lock_file_for_update(&lk, ctx->graph_name, LOCK_DIE_ON_ERROR);
+		hold_lock_file_for_update_mode(&lk, ctx->graph_name,
+					       LOCK_DIE_ON_ERROR, 0444);
 		fd = lk.tempfile->fd;
 		f = hashfd(lk.tempfile->fd, lk.tempfile->filename.buf);
 	}
diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index 9bf920ae17..fb0aae61c3 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -96,6 +96,13 @@ test_expect_success 'write graph' '
 	graph_read_expect "3"
 '
 
+test_expect_success POSIXPERM 'write graph has correct permissions' '
+	test_path_is_file $objdir/info/commit-graph &&
+	echo "-r--r--r--" >expect &&
+	test_modebits $objdir/info/commit-graph >actual &&
+	test_cmp expect actual
+'
+
 graph_git_behavior 'graph exists' full commits/3 commits/1
 
 test_expect_success 'Add more commits' '
@@ -421,7 +428,8 @@ GRAPH_BYTE_FOOTER=$(($GRAPH_OCTOPUS_DATA_OFFSET + 4 * $NUM_OCTOPUS_EDGES))
 corrupt_graph_setup() {
 	cd "$TRASH_DIRECTORY/full" &&
 	test_when_finished mv commit-graph-backup $objdir/info/commit-graph &&
-	cp $objdir/info/commit-graph commit-graph-backup
+	cp $objdir/info/commit-graph commit-graph-backup &&
+	chmod u+w $objdir/info/commit-graph
 }
 
 corrupt_graph_verify() {
@@ -435,6 +443,7 @@ corrupt_graph_verify() {
 	fi &&
 	git status --short &&
 	GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD=true git commit-graph write &&
+	chmod u+w $objdir/info/commit-graph &&
 	git commit-graph verify
 }
 
diff --git a/t/t6600-test-reach.sh b/t/t6600-test-reach.sh
index b24d850036..475564bee7 100755
--- a/t/t6600-test-reach.sh
+++ b/t/t6600-test-reach.sh
@@ -51,8 +51,10 @@ test_expect_success 'setup' '
 	done &&
 	git commit-graph write --reachable &&
 	mv .git/objects/info/commit-graph commit-graph-full &&
+	chmod u+w commit-graph-full &&
 	git show-ref -s commit-5-5 | git commit-graph write --stdin-commits &&
 	mv .git/objects/info/commit-graph commit-graph-half &&
+	chmod u+w commit-graph-half &&
 	git config core.commitGraph true
 '
 
-- 
2.26.1.108.gadb95c98e4

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

* Re: [PATCH 0/3] commit-graph: write non-split graphs as read-only
  2020-04-20 22:50 [PATCH 0/3] commit-graph: write non-split graphs as read-only Taylor Blau
                   ` (2 preceding siblings ...)
  2020-04-20 22:51 ` [PATCH 3/3] commit-graph.c: write non-split graphs as read-only Taylor Blau
@ 2020-04-20 23:23 ` Junio C Hamano
  2020-04-20 23:39   ` Taylor Blau
  2020-04-27 16:27 ` [PATCH v2 0/4] " Taylor Blau
  2020-04-29 17:36 ` [PATCH v3 0/5] commit-graph: write non-split graphs as read-only Taylor Blau
  5 siblings, 1 reply; 36+ messages in thread
From: Junio C Hamano @ 2020-04-20 23:23 UTC (permalink / raw)
  To: Taylor Blau; +Cc: git, dstolee, mhagger, peff

Taylor Blau <me@ttaylorr.com> writes:

> The first two patches set this up, and the third patch uses it in
> commit-graph.c, and corrects some test fallout. Eventually, we may want
> to take another look at all of this and always create lockfiles with
> permission 0444, but that change is much larger than this one and could
> instead be done over time.

So,... is the problem that this did not follow the common pattern of
creating (while honoring umask) and then call adjust_shared_perm(),
which I thought was the common pattern for files in $GIT_DIR/?

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

* Re: [PATCH 1/3] tempfile.c: introduce 'create_tempfile_mode'
  2020-04-20 22:51 ` [PATCH 1/3] tempfile.c: introduce 'create_tempfile_mode' Taylor Blau
@ 2020-04-20 23:31   ` Junio C Hamano
  0 siblings, 0 replies; 36+ messages in thread
From: Junio C Hamano @ 2020-04-20 23:31 UTC (permalink / raw)
  To: Taylor Blau; +Cc: git, dstolee, mhagger, peff

Taylor Blau <me@ttaylorr.com> writes:

> Arguably, all temporary files should have permission 0444, since they
> are likely to be renamed into place and then not written to again.

If the repository is not shared, it is more than likely that these
files ought to have permission narrower than that.  As you'd be
concluding any file that you created and written to in $GIT_DIR/
with adjust_shared_perm(), I do not think it is a good idea to allow
callers to pass an arbitrary mode and let them expect the mode would
stick.  Shoudln't we instead be passing "int read_only" and depending
on the boolean value, choosing between 0444 and 0666 in the function?

> Signed-off-by: Taylor Blau <me@ttaylorr.com>
> ---
>  tempfile.c | 6 +++---
>  tempfile.h | 7 ++++++-
>  2 files changed, 9 insertions(+), 4 deletions(-)
>
> diff --git a/tempfile.c b/tempfile.c
> index d43ad8c191..94aa18f3f7 100644
> --- a/tempfile.c
> +++ b/tempfile.c
> @@ -130,17 +130,17 @@ static void deactivate_tempfile(struct tempfile *tempfile)
>  }
>  
>  /* Make sure errno contains a meaningful value on error */
> -struct tempfile *create_tempfile(const char *path)
> +struct tempfile *create_tempfile_mode(const char *path, int mode)
>  {
>  	struct tempfile *tempfile = new_tempfile();
>  
>  	strbuf_add_absolute_path(&tempfile->filename, path);
>  	tempfile->fd = open(tempfile->filename.buf,
> -			    O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0666);
> +			    O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, mode);
>  	if (O_CLOEXEC && tempfile->fd < 0 && errno == EINVAL)
>  		/* Try again w/o O_CLOEXEC: the kernel might not support it */
>  		tempfile->fd = open(tempfile->filename.buf,
> -				    O_RDWR | O_CREAT | O_EXCL, 0666);
> +				    O_RDWR | O_CREAT | O_EXCL, mode);
>  	if (tempfile->fd < 0) {
>  		deactivate_tempfile(tempfile);
>  		return NULL;
> diff --git a/tempfile.h b/tempfile.h
> index cddda0a33c..b5760d4581 100644
> --- a/tempfile.h
> +++ b/tempfile.h
> @@ -89,7 +89,12 @@ struct tempfile {
>   * a tempfile (whose "fd" member can be used for writing to it), or
>   * NULL on error. It is an error if a file already exists at that path.
>   */
> -struct tempfile *create_tempfile(const char *path);
> +struct tempfile *create_tempfile_mode(const char *path, int mode);
> +
> +static inline struct tempfile *create_tempfile(const char *path)
> +{
> +	return create_tempfile_mode(path, 0666);
> +}
>  
>  /*
>   * Register an existing file as a tempfile, meaning that it will be

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

* Re: [PATCH 0/3] commit-graph: write non-split graphs as read-only
  2020-04-20 23:23 ` [PATCH 0/3] commit-graph: " Junio C Hamano
@ 2020-04-20 23:39   ` Taylor Blau
  2020-04-21  1:17     ` Junio C Hamano
  0 siblings, 1 reply; 36+ messages in thread
From: Taylor Blau @ 2020-04-20 23:39 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Taylor Blau, git, dstolee, mhagger, peff

On Mon, Apr 20, 2020 at 04:23:13PM -0700, Junio C Hamano wrote:
> Taylor Blau <me@ttaylorr.com> writes:
>
> > The first two patches set this up, and the third patch uses it in
> > commit-graph.c, and corrects some test fallout. Eventually, we may want
> > to take another look at all of this and always create lockfiles with
> > permission 0444, but that change is much larger than this one and could
> > instead be done over time.
>
> So,... is the problem that this did not follow the common pattern of
> creating (while honoring umask) and then call adjust_shared_perm(),
> which I thought was the common pattern for files in $GIT_DIR/?

We do call adjust_shared_perm() from (based on what's currently in
master) 'write_commit_graph_file' -> 'hold_lockfile_for_update' ->
'lock_file_timeout' -> 'lock_file' -> 'create_tempfile'.

But do we want commit-graphs to be respecting 'core.sharedRepository'
here? Either we:

  * do want to respect core.sharedRepository, in which case the
    current behavior of always setting split-graph permissions to '0444'
    is wrong, or

  * we do not want to respect core.sharedRepository, in which case these
    patches are doing what we want by setting all commit-graph files to
    have read-only permissions.

My hunch is that we do not want to abide by core.sharedRepository here
for the same reason that, say, loose objects are read-only. What do you
think?


Thanks,
Taylor

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

* Re: [PATCH 0/3] commit-graph: write non-split graphs as read-only
  2020-04-20 23:39   ` Taylor Blau
@ 2020-04-21  1:17     ` Junio C Hamano
  2020-04-21  7:01       ` Jeff King
  0 siblings, 1 reply; 36+ messages in thread
From: Junio C Hamano @ 2020-04-21  1:17 UTC (permalink / raw)
  To: Taylor Blau; +Cc: git, dstolee, mhagger, peff

Taylor Blau <me@ttaylorr.com> writes:

>   * do want to respect core.sharedRepository, in which case the
>     current behavior of always setting split-graph permissions to '0444'
>     is wrong, or

Yes, I would say "always 0444" is wrong.

>   * we do not want to respect core.sharedRepository, in which case these
>     patches are doing what we want by setting all commit-graph files to
>     have read-only permissions.
>
> My hunch is that we do not want to abide by core.sharedRepository here
> for the same reason that, say, loose objects are read-only. What do you
> think?

I thought that adjusting perm for sharedRepository is orthogonal to
the read-only vs read-write.  If a file ought to be writable by the
owner, we would make it group writable in a group shared repository.
If a file is readable by the owner, we make sure it is readable by
group in such a repository (and we do not want to flip write bit
on).  That happens by calling path.c::calc_shared_perm().


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

* Re: [PATCH 0/3] commit-graph: write non-split graphs as read-only
  2020-04-21  1:17     ` Junio C Hamano
@ 2020-04-21  7:01       ` Jeff King
  2020-04-21 18:59         ` Junio C Hamano
  0 siblings, 1 reply; 36+ messages in thread
From: Jeff King @ 2020-04-21  7:01 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Taylor Blau, git, dstolee, mhagger

On Mon, Apr 20, 2020 at 06:17:05PM -0700, Junio C Hamano wrote:

> Taylor Blau <me@ttaylorr.com> writes:
> 
> >   * do want to respect core.sharedRepository, in which case the
> >     current behavior of always setting split-graph permissions to '0444'
> >     is wrong, or
> 
> Yes, I would say "always 0444" is wrong.

I'm not sure. That's what we do for loose objects, packs, etc. The mode
we feed to git_mkstemp_mode(), etc, is not the true mode we expect to
end up with. We know that it will be modified by the umask, and then
perhaps by adjust_shared_perm().

If you are arguing that there are only two interesting modes: 0444 and
0666, and those could be represented by a read-only/read-write enum, I'd
agree with that. But the rest of the code already spells those as 0444
and 0666, and I don't see that as a big problem (in fact, there's a bit
of an advantage because the same constants work at both high and low
levels of the call stack, so you don't have to decide where to put the
translation).

> >   * we do not want to respect core.sharedRepository, in which case these
> >     patches are doing what we want by setting all commit-graph files to
> >     have read-only permissions.
> >
> > My hunch is that we do not want to abide by core.sharedRepository here
> > for the same reason that, say, loose objects are read-only. What do you
> > think?
> 
> I thought that adjusting perm for sharedRepository is orthogonal to
> the read-only vs read-write.  If a file ought to be writable by the
> owner, we would make it group writable in a group shared repository.
> If a file is readable by the owner, we make sure it is readable by
> group in such a repository (and we do not want to flip write bit
> on).  That happens by calling path.c::calc_shared_perm().

Right. I think adjust_shared_perm() should already be doing what we
want, and we should continue to call it. But it should not be
responsible for this "read-only versus read-write" decision. That
happens much earlier, and it adjusts as appropriate.

-Peff

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

* Re: [PATCH 0/3] commit-graph: write non-split graphs as read-only
  2020-04-21  7:01       ` Jeff King
@ 2020-04-21 18:59         ` Junio C Hamano
  0 siblings, 0 replies; 36+ messages in thread
From: Junio C Hamano @ 2020-04-21 18:59 UTC (permalink / raw)
  To: Jeff King; +Cc: Taylor Blau, git, dstolee, mhagger

Jeff King <peff@peff.net> writes:

>> Yes, I would say "always 0444" is wrong.
>
> I'm not sure. That's what we do for loose objects, packs, etc. The mode
> we feed to git_mkstemp_mode(), etc, is not the true mode we expect to
> end up with. We know that it will be modified by the umask, and then
> perhaps by adjust_shared_perm().
>
> If you are arguing that there are only two interesting modes: 0444 and
> 0666, and those could be represented by a read-only/read-write enum, I'd
> agree with that.

Yup, that is what I meant.  I am aware that these 0444/0666 are
limited with umask at open(O_CREAT) time, and then we later call
adjust_shared_perm().  I thought Taylor meant to always make it
readable by everybody, which was the only point I was objecting to.

> Right. I think adjust_shared_perm() should already be doing what we
> want, and we should continue to call it. But it should not be
> responsible for this "read-only versus read-write" decision. That
> happens much earlier, and it adjusts as appropriate.

Yes.

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

* [PATCH v2 0/4] commit-graph: write non-split graphs as read-only
  2020-04-20 22:50 [PATCH 0/3] commit-graph: write non-split graphs as read-only Taylor Blau
                   ` (3 preceding siblings ...)
  2020-04-20 23:23 ` [PATCH 0/3] commit-graph: " Junio C Hamano
@ 2020-04-27 16:27 ` Taylor Blau
  2020-04-27 16:27   ` [PATCH v2 1/4] tempfile.c: introduce 'create_tempfile_mode' Taylor Blau
                     ` (3 more replies)
  2020-04-29 17:36 ` [PATCH v3 0/5] commit-graph: write non-split graphs as read-only Taylor Blau
  5 siblings, 4 replies; 36+ messages in thread
From: Taylor Blau @ 2020-04-27 16:27 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster, mhagger

Hi,

Here's an updated version of my series to resolve a difference between
the permissions that split- and non-split commit-graphs are written
with.

Not much has changed since last time, since the main discussion revolved
around differences between what mode the user passes and how that
interacts with 'adjust_shared_perm' as well as why split-graphs are
always read-only for everybody.

Patches 1-3 remain mostly the same, with only some additional
documentation in the patches and headers about the interaction between
the 'mode' parameter and the umask and 'core.sharedRepository'. The
fourth patch is new, and makes sure that split-graphs are also
respecting 'core.sharedRepository' (and never have permissions above
0444).

The end-state of this is that both split- and non-split graphs have at
most permission 0444, and both respect core.sharedRepository.

Thanks in advance for another look.


Taylor Blau (4):
  tempfile.c: introduce 'create_tempfile_mode'
  lockfile.c: introduce 'hold_lock_file_for_update_mode'
  commit-graph.c: write non-split graphs as read-only
  commit-graph.c: ensure graph layers respect core.sharedRepository

 commit-graph.c                |  9 ++++++++-
 lockfile.c                    | 18 ++++++++++--------
 lockfile.h                    | 32 ++++++++++++++++++++++++++++----
 t/t5318-commit-graph.sh       | 11 ++++++++++-
 t/t5324-split-commit-graph.sh | 18 ++++++++++++++++++
 t/t6600-test-reach.sh         |  2 ++
 tempfile.c                    |  6 +++---
 tempfile.h                    | 10 +++++++++-
 8 files changed, 88 insertions(+), 18 deletions(-)

Range-diff against v1:
1:  aa86e8df40 ! 1:  03c975b0bd tempfile.c: introduce 'create_tempfile_mode'
    @@ Commit message
         creates a temporary file with global read-write permissions, introduce a
         variant here that allows specifying the mode.

    +    Note that the mode given to 'create_tempfile_mode' is not guaranteed to
    +    be written to disk, since it is subject to both the umask and
    +    'core.sharedRepository'.
    +
         Arguably, all temporary files should have permission 0444, since they
         are likely to be renamed into place and then not written to again. This
         is a much larger change than we may want to take on in this otherwise
    @@ tempfile.c: static void deactivate_tempfile(struct tempfile *tempfile)

      ## tempfile.h ##
     @@ tempfile.h: struct tempfile {
    +  * Attempt to create a temporary file at the specified `path`. Return
       * a tempfile (whose "fd" member can be used for writing to it), or
       * NULL on error. It is an error if a file already exists at that path.
    ++ * Note that `mode` will be further modified by the umask, and possibly
    ++ * `core.sharedRepository`, so it is not guaranteed to have the given
    ++ * mode.
       */
     -struct tempfile *create_tempfile(const char *path);
     +struct tempfile *create_tempfile_mode(const char *path, int mode);
2:  dad37d4233 ! 2:  c1c84552bc lockfile.c: introduce 'hold_lock_file_for_update_mode'
    @@ Commit message
         functions, and leave the existing functions alone by inlining their
         definitions in terms of the new mode variants.

    -    Note that even though the commit-graph machinery only calls
    +    Note that, like in the previous commit, 'hold_lock_file_for_update_mode'
    +    is not guarenteed to set the given mode, since it may be modified by
    +    both the umask and 'core.sharedRepository'.
    +
    +    Note also that even though the commit-graph machinery only calls
         'hold_lock_file_for_update', that this is defined in terms of
         'hold_lock_file_for_update_timeout', and so both need an additional mode
         parameter here.
    @@ lockfile.c: NORETURN void unable_to_lock_die(const char *path, int err)
      			unable_to_lock_die(path, errno);

      ## lockfile.h ##
    +@@
    +  * functions. In particular, the state diagram and the cleanup
    +  * machinery are all implemented in the tempfile module.
    +  *
    ++ * Permission bits
    ++ * ---------------
    ++ *
    ++ * If you call either `hold_lock_file_for_update_mode` or
    ++ * `hold_lock_file_for_update_timeout_mode`, you can specify a suggested
    ++ * mode for the underlying temporary file. Note that the file isn't
    ++ * guaranteed to have this exact mode, since it may be limited by either
    ++ * the umask, 'core.sharedRepository', or both. See `adjust_shared_perm`
    ++ * for more.
    +  *
    +  * Error handling
    +  * --------------
     @@ lockfile.h: struct lock_file {
    -  * timeout_ms is -1, retry indefinitely. The flags argument and error
    -  * handling are described above.
    +  * file descriptor for writing to it, or -1 on error. If the file is
    +  * currently locked, retry with quadratic backoff for at least
    +  * timeout_ms milliseconds. If timeout_ms is 0, try exactly once; if
    +- * timeout_ms is -1, retry indefinitely. The flags argument and error
    +- * handling are described above.
    ++ * timeout_ms is -1, retry indefinitely. The flags argument, error
    ++ * handling, and mode are described above.
       */
     -int hold_lock_file_for_update_timeout(
     +int hold_lock_file_for_update_timeout_mode(
3:  622fd92cee ! 3:  86cf29ce9c commit-graph.c: write non-split graphs as read-only
    @@ Commit message
         commit-graph.c: write non-split graphs as read-only

         In the previous commit, Git learned 'hold_lock_file_for_update_mode' to
    -    allow the caller to specify the permission bits used when acquiring a
    -    temporary file.
    +    allow the caller to specify the permission bits (prior to further
    +    adjustment by the umask and shared repository permissions) used when
    +    acquiring a temporary file.

         Use this in the commit-graph machinery for writing a non-split graph to
         acquire an opened temporary file with permissions read-only permissions
         to match the split behavior. (In the split case, Git uses
    -    'git_mkstemp_mode' for each of the commit-graph layers with permission
    +    git_mkstemp_mode' for each of the commit-graph layers with permission
         bits '0444').

         One can notice this discrepancy when moving a non-split graph to be part
-:  ---------- > 4:  f83437f130 commit-graph.c: ensure graph layers respect core.sharedRepository
--
2.26.0.113.ge9739cdccc

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

* [PATCH v2 1/4] tempfile.c: introduce 'create_tempfile_mode'
  2020-04-27 16:27 ` [PATCH v2 0/4] " Taylor Blau
@ 2020-04-27 16:27   ` Taylor Blau
  2020-04-27 16:27   ` [PATCH v2 2/4] lockfile.c: introduce 'hold_lock_file_for_update_mode' Taylor Blau
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 36+ messages in thread
From: Taylor Blau @ 2020-04-27 16:27 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster, mhagger

In the next patch, 'hold_lock_file_for_update' will gain an additional
'mode' parameter to specify permissions for the associated temporary
file.

Since the lockfile.c machinery uses 'create_tempfile' which always
creates a temporary file with global read-write permissions, introduce a
variant here that allows specifying the mode.

Note that the mode given to 'create_tempfile_mode' is not guaranteed to
be written to disk, since it is subject to both the umask and
'core.sharedRepository'.

Arguably, all temporary files should have permission 0444, since they
are likely to be renamed into place and then not written to again. This
is a much larger change than we may want to take on in this otherwise
small patch, so for the time being, make 'create_tempfile' behave as it
has always done by inlining it to 'create_tempfile_mode' with mode set
to '0666'.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 tempfile.c |  6 +++---
 tempfile.h | 10 +++++++++-
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/tempfile.c b/tempfile.c
index d43ad8c191..94aa18f3f7 100644
--- a/tempfile.c
+++ b/tempfile.c
@@ -130,17 +130,17 @@ static void deactivate_tempfile(struct tempfile *tempfile)
 }
 
 /* Make sure errno contains a meaningful value on error */
-struct tempfile *create_tempfile(const char *path)
+struct tempfile *create_tempfile_mode(const char *path, int mode)
 {
 	struct tempfile *tempfile = new_tempfile();
 
 	strbuf_add_absolute_path(&tempfile->filename, path);
 	tempfile->fd = open(tempfile->filename.buf,
-			    O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0666);
+			    O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, mode);
 	if (O_CLOEXEC && tempfile->fd < 0 && errno == EINVAL)
 		/* Try again w/o O_CLOEXEC: the kernel might not support it */
 		tempfile->fd = open(tempfile->filename.buf,
-				    O_RDWR | O_CREAT | O_EXCL, 0666);
+				    O_RDWR | O_CREAT | O_EXCL, mode);
 	if (tempfile->fd < 0) {
 		deactivate_tempfile(tempfile);
 		return NULL;
diff --git a/tempfile.h b/tempfile.h
index cddda0a33c..4de3bc77d2 100644
--- a/tempfile.h
+++ b/tempfile.h
@@ -88,8 +88,16 @@ struct tempfile {
  * Attempt to create a temporary file at the specified `path`. Return
  * a tempfile (whose "fd" member can be used for writing to it), or
  * NULL on error. It is an error if a file already exists at that path.
+ * Note that `mode` will be further modified by the umask, and possibly
+ * `core.sharedRepository`, so it is not guaranteed to have the given
+ * mode.
  */
-struct tempfile *create_tempfile(const char *path);
+struct tempfile *create_tempfile_mode(const char *path, int mode);
+
+static inline struct tempfile *create_tempfile(const char *path)
+{
+	return create_tempfile_mode(path, 0666);
+}
 
 /*
  * Register an existing file as a tempfile, meaning that it will be
-- 
2.26.0.113.ge9739cdccc


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

* [PATCH v2 2/4] lockfile.c: introduce 'hold_lock_file_for_update_mode'
  2020-04-27 16:27 ` [PATCH v2 0/4] " Taylor Blau
  2020-04-27 16:27   ` [PATCH v2 1/4] tempfile.c: introduce 'create_tempfile_mode' Taylor Blau
@ 2020-04-27 16:27   ` Taylor Blau
  2020-04-27 16:28   ` [PATCH v2 3/4] commit-graph.c: write non-split graphs as read-only Taylor Blau
  2020-04-27 16:28   ` [PATCH v2 4/4] commit-graph.c: ensure graph layers respect core.sharedRepository Taylor Blau
  3 siblings, 0 replies; 36+ messages in thread
From: Taylor Blau @ 2020-04-27 16:27 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster, mhagger

We use 'hold_lock_file_for_update' (and the '_timeout') variant to
acquire a lock when updating references, the commit-graph file, and so
on.

In particular, the commit-graph machinery uses this to acquire a
temporary file that is used to write a non-split commit-graph. In a
subsequent commit, an issue in the commit-graph machinery produces
graph files that have a different permission based on whether or not
they are part of a multi-layer graph will be addressed.

To do so, the commit-graph machinery will need a version of
'hold_lock_file_for_update' that takes the permission bits from the
caller.

Introduce such a function in this patch for both the
'hold_lock_file_for_update' and 'hold_lock_file_for_update_timeout'
functions, and leave the existing functions alone by inlining their
definitions in terms of the new mode variants.

Note that, like in the previous commit, 'hold_lock_file_for_update_mode'
is not guarenteed to set the given mode, since it may be modified by
both the umask and 'core.sharedRepository'.

Note also that even though the commit-graph machinery only calls
'hold_lock_file_for_update', that this is defined in terms of
'hold_lock_file_for_update_timeout', and so both need an additional mode
parameter here.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 lockfile.c | 18 ++++++++++--------
 lockfile.h | 32 ++++++++++++++++++++++++++++----
 2 files changed, 38 insertions(+), 12 deletions(-)

diff --git a/lockfile.c b/lockfile.c
index 8e8ab4f29f..cc9a4b8428 100644
--- a/lockfile.c
+++ b/lockfile.c
@@ -70,7 +70,8 @@ static void resolve_symlink(struct strbuf *path)
 }
 
 /* Make sure errno contains a meaningful value on error */
-static int lock_file(struct lock_file *lk, const char *path, int flags)
+static int lock_file(struct lock_file *lk, const char *path, int flags,
+		     int mode)
 {
 	struct strbuf filename = STRBUF_INIT;
 
@@ -79,7 +80,7 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)
 		resolve_symlink(&filename);
 
 	strbuf_addstr(&filename, LOCK_SUFFIX);
-	lk->tempfile = create_tempfile(filename.buf);
+	lk->tempfile = create_tempfile_mode(filename.buf, mode);
 	strbuf_release(&filename);
 	return lk->tempfile ? lk->tempfile->fd : -1;
 }
@@ -99,7 +100,7 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)
  * exactly once. If timeout_ms is -1, try indefinitely.
  */
 static int lock_file_timeout(struct lock_file *lk, const char *path,
-			     int flags, long timeout_ms)
+			     int flags, long timeout_ms, int mode)
 {
 	int n = 1;
 	int multiplier = 1;
@@ -107,7 +108,7 @@ static int lock_file_timeout(struct lock_file *lk, const char *path,
 	static int random_initialized = 0;
 
 	if (timeout_ms == 0)
-		return lock_file(lk, path, flags);
+		return lock_file(lk, path, flags, mode);
 
 	if (!random_initialized) {
 		srand((unsigned int)getpid());
@@ -121,7 +122,7 @@ static int lock_file_timeout(struct lock_file *lk, const char *path,
 		long backoff_ms, wait_ms;
 		int fd;
 
-		fd = lock_file(lk, path, flags);
+		fd = lock_file(lk, path, flags, mode);
 
 		if (fd >= 0)
 			return fd; /* success */
@@ -169,10 +170,11 @@ NORETURN void unable_to_lock_die(const char *path, int err)
 }
 
 /* This should return a meaningful errno on failure */
-int hold_lock_file_for_update_timeout(struct lock_file *lk, const char *path,
-				      int flags, long timeout_ms)
+int hold_lock_file_for_update_timeout_mode(struct lock_file *lk,
+					   const char *path, int flags,
+					   long timeout_ms, int mode)
 {
-	int fd = lock_file_timeout(lk, path, flags, timeout_ms);
+	int fd = lock_file_timeout(lk, path, flags, timeout_ms, mode);
 	if (fd < 0) {
 		if (flags & LOCK_DIE_ON_ERROR)
 			unable_to_lock_die(path, errno);
diff --git a/lockfile.h b/lockfile.h
index 9843053ce8..db93e6ba73 100644
--- a/lockfile.h
+++ b/lockfile.h
@@ -90,6 +90,15 @@
  * functions. In particular, the state diagram and the cleanup
  * machinery are all implemented in the tempfile module.
  *
+ * Permission bits
+ * ---------------
+ *
+ * If you call either `hold_lock_file_for_update_mode` or
+ * `hold_lock_file_for_update_timeout_mode`, you can specify a suggested
+ * mode for the underlying temporary file. Note that the file isn't
+ * guaranteed to have this exact mode, since it may be limited by either
+ * the umask, 'core.sharedRepository', or both. See `adjust_shared_perm`
+ * for more.
  *
  * Error handling
  * --------------
@@ -156,12 +165,20 @@ struct lock_file {
  * file descriptor for writing to it, or -1 on error. If the file is
  * currently locked, retry with quadratic backoff for at least
  * timeout_ms milliseconds. If timeout_ms is 0, try exactly once; if
- * timeout_ms is -1, retry indefinitely. The flags argument and error
- * handling are described above.
+ * timeout_ms is -1, retry indefinitely. The flags argument, error
+ * handling, and mode are described above.
  */
-int hold_lock_file_for_update_timeout(
+int hold_lock_file_for_update_timeout_mode(
 		struct lock_file *lk, const char *path,
-		int flags, long timeout_ms);
+		int flags, long timeout_ms, int mode);
+
+static inline int hold_lock_file_for_update_timeout(
+		struct lock_file *lk, const char *path,
+		int flags, long timeout_ms)
+{
+	return hold_lock_file_for_update_timeout_mode(lk, path, flags,
+						      timeout_ms, 0666);
+}
 
 /*
  * Attempt to create a lockfile for the file at `path` and return a
@@ -175,6 +192,13 @@ static inline int hold_lock_file_for_update(
 	return hold_lock_file_for_update_timeout(lk, path, flags, 0);
 }
 
+static inline int hold_lock_file_for_update_mode(
+		struct lock_file *lk, const char *path,
+		int flags, int mode)
+{
+	return hold_lock_file_for_update_timeout_mode(lk, path, flags, 0, mode);
+}
+
 /*
  * Return a nonzero value iff `lk` is currently locked.
  */
-- 
2.26.0.113.ge9739cdccc


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

* [PATCH v2 3/4] commit-graph.c: write non-split graphs as read-only
  2020-04-27 16:27 ` [PATCH v2 0/4] " Taylor Blau
  2020-04-27 16:27   ` [PATCH v2 1/4] tempfile.c: introduce 'create_tempfile_mode' Taylor Blau
  2020-04-27 16:27   ` [PATCH v2 2/4] lockfile.c: introduce 'hold_lock_file_for_update_mode' Taylor Blau
@ 2020-04-27 16:28   ` Taylor Blau
  2020-04-27 23:54     ` Junio C Hamano
  2020-04-27 16:28   ` [PATCH v2 4/4] commit-graph.c: ensure graph layers respect core.sharedRepository Taylor Blau
  3 siblings, 1 reply; 36+ messages in thread
From: Taylor Blau @ 2020-04-27 16:28 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster, mhagger

In the previous commit, Git learned 'hold_lock_file_for_update_mode' to
allow the caller to specify the permission bits (prior to further
adjustment by the umask and shared repository permissions) used when
acquiring a temporary file.

Use this in the commit-graph machinery for writing a non-split graph to
acquire an opened temporary file with permissions read-only permissions
to match the split behavior. (In the split case, Git uses
git_mkstemp_mode' for each of the commit-graph layers with permission
bits '0444').

One can notice this discrepancy when moving a non-split graph to be part
of a new chain. This causes a commit-graph chain where all layers have
read-only permission bits, except for the base layer, which is writable
for the current user.

Resolve this discrepancy by using the new
'hold_lock_file_for_update_mode' and passing the desired permission
bits.

Doing so causes some test fallout in t5318 and t6600. In t5318, this
occurs in tests that corrupt a commit-graph file by writing into it. For
these, 'chmod u+w'-ing the file beforehand resolves the issue. The
additional spot in 'corrupt_graph_verify' is necessary because of the
extra 'git commit-graph write' beforehand (which *does* rewrite the
commit-graph file). In t6600, this is caused by copying a read-only
commit-graph file into place and then trying to replace it. For these,
make these files writable.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 commit-graph.c          |  3 ++-
 t/t5318-commit-graph.sh | 11 ++++++++++-
 t/t6600-test-reach.sh   |  2 ++
 3 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/commit-graph.c b/commit-graph.c
index f013a84e29..5b5047a7dd 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -1388,7 +1388,8 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 
 		f = hashfd(fd, ctx->graph_name);
 	} else {
-		hold_lock_file_for_update(&lk, ctx->graph_name, LOCK_DIE_ON_ERROR);
+		hold_lock_file_for_update_mode(&lk, ctx->graph_name,
+					       LOCK_DIE_ON_ERROR, 0444);
 		fd = lk.tempfile->fd;
 		f = hashfd(lk.tempfile->fd, lk.tempfile->filename.buf);
 	}
diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index 9bf920ae17..fb0aae61c3 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -96,6 +96,13 @@ test_expect_success 'write graph' '
 	graph_read_expect "3"
 '
 
+test_expect_success POSIXPERM 'write graph has correct permissions' '
+	test_path_is_file $objdir/info/commit-graph &&
+	echo "-r--r--r--" >expect &&
+	test_modebits $objdir/info/commit-graph >actual &&
+	test_cmp expect actual
+'
+
 graph_git_behavior 'graph exists' full commits/3 commits/1
 
 test_expect_success 'Add more commits' '
@@ -421,7 +428,8 @@ GRAPH_BYTE_FOOTER=$(($GRAPH_OCTOPUS_DATA_OFFSET + 4 * $NUM_OCTOPUS_EDGES))
 corrupt_graph_setup() {
 	cd "$TRASH_DIRECTORY/full" &&
 	test_when_finished mv commit-graph-backup $objdir/info/commit-graph &&
-	cp $objdir/info/commit-graph commit-graph-backup
+	cp $objdir/info/commit-graph commit-graph-backup &&
+	chmod u+w $objdir/info/commit-graph
 }
 
 corrupt_graph_verify() {
@@ -435,6 +443,7 @@ corrupt_graph_verify() {
 	fi &&
 	git status --short &&
 	GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD=true git commit-graph write &&
+	chmod u+w $objdir/info/commit-graph &&
 	git commit-graph verify
 }
 
diff --git a/t/t6600-test-reach.sh b/t/t6600-test-reach.sh
index b24d850036..475564bee7 100755
--- a/t/t6600-test-reach.sh
+++ b/t/t6600-test-reach.sh
@@ -51,8 +51,10 @@ test_expect_success 'setup' '
 	done &&
 	git commit-graph write --reachable &&
 	mv .git/objects/info/commit-graph commit-graph-full &&
+	chmod u+w commit-graph-full &&
 	git show-ref -s commit-5-5 | git commit-graph write --stdin-commits &&
 	mv .git/objects/info/commit-graph commit-graph-half &&
+	chmod u+w commit-graph-half &&
 	git config core.commitGraph true
 '
 
-- 
2.26.0.113.ge9739cdccc


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

* [PATCH v2 4/4] commit-graph.c: ensure graph layers respect core.sharedRepository
  2020-04-27 16:27 ` [PATCH v2 0/4] " Taylor Blau
                     ` (2 preceding siblings ...)
  2020-04-27 16:28   ` [PATCH v2 3/4] commit-graph.c: write non-split graphs as read-only Taylor Blau
@ 2020-04-27 16:28   ` Taylor Blau
  2020-04-27 17:21     ` Taylor Blau
  3 siblings, 1 reply; 36+ messages in thread
From: Taylor Blau @ 2020-04-27 16:28 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster, mhagger

Non-layered commit-graphs use 'adjust_shared_perm' to make the
commit-graph file readable (or not) to a combination of the user, group,
and others.

Call 'adjust_shared_perm' for split-graph layers to make sure that these
also respect 'core.sharedRepository'. The 'commit-graph-chain' file
already respects this configuration since it uses
'hold_lock_file_for_update' (which calls 'adjust_shared_perm' eventually
in 'create_tempfile_mode').

Suggested-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 commit-graph.c                |  6 ++++++
 t/t5324-split-commit-graph.sh | 18 ++++++++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/commit-graph.c b/commit-graph.c
index 5b5047a7dd..d05a55901d 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -1386,6 +1386,12 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 			return -1;
 		}
 
+		if (adjust_shared_perm(ctx->graph_name)) {
+			error(_("unable to adjust shared permissions for '%s'"),
+			      ctx->graph_name);
+			return -1;
+		}
+
 		f = hashfd(fd, ctx->graph_name);
 	} else {
 		hold_lock_file_for_update_mode(&lk, ctx->graph_name,
diff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh
index 53b2e6b455..61136c737f 100755
--- a/t/t5324-split-commit-graph.sh
+++ b/t/t5324-split-commit-graph.sh
@@ -351,4 +351,22 @@ test_expect_success 'split across alternate where alternate is not split' '
 	test_cmp commit-graph .git/objects/info/commit-graph
 '
 
+while read mode modebits
+do
+	test_expect_success POSIXPERM "split commit-graph respects core.sharedrepository $mode" '
+		rm -rf $graphdir $infodir/commit-graph &&
+		git reset --hard commits/1 &&
+		test_config core.sharedrepository "$mode" &&
+		git commit-graph write --split --reachable &&
+		ls $graphdir/graph-*.graph >graph-files &&
+		test_line_count = 1 graph-files &&
+		echo "$modebits" >expect &&
+		test_modebits $graphdir/graph-*.graph >actual &&
+		test_cmp expect actual
+	'
+done <<\EOF
+0666 -r--r--r--
+0600 -r--------
+EOF
+
 test_done
-- 
2.26.0.113.ge9739cdccc

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

* Re: [PATCH v2 4/4] commit-graph.c: ensure graph layers respect core.sharedRepository
  2020-04-27 16:28   ` [PATCH v2 4/4] commit-graph.c: ensure graph layers respect core.sharedRepository Taylor Blau
@ 2020-04-27 17:21     ` Taylor Blau
  2020-04-27 20:58       ` Jeff King
  0 siblings, 1 reply; 36+ messages in thread
From: Taylor Blau @ 2020-04-27 17:21 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster, mhagger

On Mon, Apr 27, 2020 at 10:28:05AM -0600, Taylor Blau wrote:
> Non-layered commit-graphs use 'adjust_shared_perm' to make the
> commit-graph file readable (or not) to a combination of the user, group,
> and others.
>
> Call 'adjust_shared_perm' for split-graph layers to make sure that these
> also respect 'core.sharedRepository'. The 'commit-graph-chain' file
> already respects this configuration since it uses
> 'hold_lock_file_for_update' (which calls 'adjust_shared_perm' eventually
> in 'create_tempfile_mode').

It occurs to me that we might want to apply the same treatment to
'commit-graph-chain's, too.

Junio: I'm not sure if you want to apply the below in this series on
top, or if you'd prefer me send it as a separate series. Either way,
here's a patch to do just that:

-- >8 --

Subject: [PATCH] commit-graph.c: make 'commit-graph-chain's read-only

In a previous commit, we made incremental graph layers read-only by
using 'git_mkstemp_mode' with permissions '0444'.

There is no reason that 'commit-graph-chain's should be modifiable by
the user, since they are generated at a temporary location and then
atomically renamed into place.

To ensure that these files are read-only, too, use
'hold_lock_file_for_update_mode' with the same read-only permission
bits, and let the umask and 'adjust_shared_perm' take care of the rest.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 commit-graph.c                | 3 ++-
 t/t5324-split-commit-graph.sh | 2 ++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/commit-graph.c b/commit-graph.c
index d05a55901d..b2dfd7701f 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -1378,7 +1378,8 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 	if (ctx->split) {
 		char *lock_name = get_chain_filename(ctx->odb);

-		hold_lock_file_for_update(&lk, lock_name, LOCK_DIE_ON_ERROR);
+		hold_lock_file_for_update_mode(&lk, lock_name,
+					       LOCK_DIE_ON_ERROR, 0444);

 		fd = git_mkstemp_mode(ctx->graph_name, 0444);
 		if (fd < 0) {
diff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh
index 61136c737f..a8b12c8110 100755
--- a/t/t5324-split-commit-graph.sh
+++ b/t/t5324-split-commit-graph.sh
@@ -362,6 +362,8 @@ do
 		test_line_count = 1 graph-files &&
 		echo "$modebits" >expect &&
 		test_modebits $graphdir/graph-*.graph >actual &&
+		test_cmp expect actual &&
+		test_modebits $graphdir/commit-graph-chain >actual &&
 		test_cmp expect actual
 	'
 done <<\EOF
--
2.26.0.113.ge9739cdccc


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

* Re: [PATCH v2 4/4] commit-graph.c: ensure graph layers respect core.sharedRepository
  2020-04-27 17:21     ` Taylor Blau
@ 2020-04-27 20:58       ` Jeff King
  0 siblings, 0 replies; 36+ messages in thread
From: Jeff King @ 2020-04-27 20:58 UTC (permalink / raw)
  To: Taylor Blau; +Cc: git, dstolee, gitster, mhagger

On Mon, Apr 27, 2020 at 11:21:11AM -0600, Taylor Blau wrote:

> On Mon, Apr 27, 2020 at 10:28:05AM -0600, Taylor Blau wrote:
> > Non-layered commit-graphs use 'adjust_shared_perm' to make the
> > commit-graph file readable (or not) to a combination of the user, group,
> > and others.
> >
> > Call 'adjust_shared_perm' for split-graph layers to make sure that these
> > also respect 'core.sharedRepository'. The 'commit-graph-chain' file
> > already respects this configuration since it uses
> > 'hold_lock_file_for_update' (which calls 'adjust_shared_perm' eventually
> > in 'create_tempfile_mode').
> 
> It occurs to me that we might want to apply the same treatment to
> 'commit-graph-chain's, too.

Yeah, perhaps. I think we've been fairly inconsistent about modes here.

Really, just about _everything_ in .git is meant to be immutable,
because we generally use rename() to update files atomically. And
there's no reason anybody should ever be opening them for writing.

I think we started with dropping the write-bit on loose and packed
object files because those are extra-precious (even if everything else
were corrupted, your history, etc, is all still there). And certainly
you can't update them without invalidating their checksum trailers
anyway.

So I think there's really three levels that could make sense:

  1. Many files in .git should lose their write bits, because Git will
     never update them except through rename. This makes things safer
     against accidental changes, but more annoying when you do want to
     edit by hand. Probably .git/config should likely be exempted, as
     we'd encourage people to hand-edit even if it's not atomic. But
     having to chmod before hand-editing a packed-refs file while
     debugging is not a huge burden.

  2. Any file written via hashfd() should be marked immutable. It cannot
     be edited without rewriting the whole contents and updating the
     trailer anyway. That would imply that commit-graph and chain files
     should be immutable, but the commit-graph-chain file should not.

  3. Everything except actual object files should retain their write
     bit. It's a minor annoyance when touching the repo by hand (e.g.,
     "rm" is sometimes pickier even about deletion), and it's not like
     there's a rash of people accidentally overwriting their refs/
     files (they're just as likely to screw themselves by deleting
     them).

I admit I don't overly care much between the three. And your patches
look fine to me, as they're just making the commit-graph code consistent
with itself (and that inconsistency is wrong under any of the mental
models above ;) ).

The exception is the final patch, which is an actual bug-fix for people
using core.sharedRepository. I suspect the feature is used infrequently
enough that nobody noticed.

-Peff

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

* Re: [PATCH v2 3/4] commit-graph.c: write non-split graphs as read-only
  2020-04-27 16:28   ` [PATCH v2 3/4] commit-graph.c: write non-split graphs as read-only Taylor Blau
@ 2020-04-27 23:54     ` Junio C Hamano
  2020-04-27 23:59       ` Taylor Blau
  0 siblings, 1 reply; 36+ messages in thread
From: Junio C Hamano @ 2020-04-27 23:54 UTC (permalink / raw)
  To: Taylor Blau; +Cc: git, peff, dstolee, mhagger

Taylor Blau <me@ttaylorr.com> writes:

> In the previous commit, Git learned 'hold_lock_file_for_update_mode' to
> allow the caller to specify the permission bits (prior to further
> adjustment by the umask and shared repository permissions) used when
> acquiring a temporary file.
>
> Use this in the commit-graph machinery for writing a non-split graph to
> acquire an opened temporary file with permissions read-only permissions
> to match the split behavior. (In the split case, Git uses
> git_mkstemp_mode' for each of the commit-graph layers with permission
> bits '0444').
>
> One can notice this discrepancy when moving a non-split graph to be part
> of a new chain. This causes a commit-graph chain where all layers have
> read-only permission bits, except for the base layer, which is writable
> for the current user.
>
> Resolve this discrepancy by using the new
> 'hold_lock_file_for_update_mode' and passing the desired permission
> bits.
>
> Doing so causes some test fallout in t5318 and t6600. In t5318, this
> occurs in tests that corrupt a commit-graph file by writing into it. For
> these, 'chmod u+w'-ing the file beforehand resolves the issue. The
> additional spot in 'corrupt_graph_verify' is necessary because of the
> extra 'git commit-graph write' beforehand (which *does* rewrite the
> commit-graph file). In t6600, this is caused by copying a read-only
> commit-graph file into place and then trying to replace it. For these,
> make these files writable.
>
> Signed-off-by: Taylor Blau <me@ttaylorr.com>
> ---
>  commit-graph.c          |  3 ++-
>  t/t5318-commit-graph.sh | 11 ++++++++++-
>  t/t6600-test-reach.sh   |  2 ++
>  3 files changed, 14 insertions(+), 2 deletions(-)

This step, queued as 3a5c7d70 (commit-graph.c: write non-split
graphs as read-only, 2020-04-27), starts failing 5318#9 at least for
me.  Do we need to loosen umask while running this test to something
not more strict than 022 or something silly like that?

Here is what I'll use as a workaround for today's pushout.

commit f062d1c028bcc839f961e8904c38c476b9deeec3
Author: Junio C Hamano <gitster@pobox.com>
Date:   Mon Apr 27 16:50:30 2020 -0700

    SQUASH??? force known umask if you are going to check the resulting mode bits

diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index fb0aae61c3..901eb3ecfb 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -12,6 +12,10 @@ test_expect_success 'setup full repo' '
 	test_oid_init
 '
 
+test_expect_success POSIXPERM 'tweak umask for modebit tests' '
+	umask 022
+'
+
 test_expect_success 'verify graph with no graph file' '
 	cd "$TRASH_DIRECTORY/full" &&
 	git commit-graph verify

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

* Re: [PATCH v2 3/4] commit-graph.c: write non-split graphs as read-only
  2020-04-27 23:54     ` Junio C Hamano
@ 2020-04-27 23:59       ` Taylor Blau
  2020-04-28  0:25         ` Junio C Hamano
  2020-04-28  3:34         ` Jeff King
  0 siblings, 2 replies; 36+ messages in thread
From: Taylor Blau @ 2020-04-27 23:59 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Taylor Blau, git, peff, dstolee, mhagger

On Mon, Apr 27, 2020 at 04:54:09PM -0700, Junio C Hamano wrote:
> This step, queued as 3a5c7d70 (commit-graph.c: write non-split
> graphs as read-only, 2020-04-27), starts failing 5318#9 at least for
> me.  Do we need to loosen umask while running this test to something
> not more strict than 022 or something silly like that?
>
> Here is what I'll use as a workaround for today's pushout.
>
> commit f062d1c028bcc839f961e8904c38c476b9deeec3
> Author: Junio C Hamano <gitster@pobox.com>
> Date:   Mon Apr 27 16:50:30 2020 -0700
>
>     SQUASH??? force known umask if you are going to check the resulting mode bits
>
> diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
> index fb0aae61c3..901eb3ecfb 100755
> --- a/t/t5318-commit-graph.sh
> +++ b/t/t5318-commit-graph.sh
> @@ -12,6 +12,10 @@ test_expect_success 'setup full repo' '
>  	test_oid_init
>  '
>
> +test_expect_success POSIXPERM 'tweak umask for modebit tests' '
> +	umask 022
> +'
> +
>  test_expect_success 'verify graph with no graph file' '
>  	cd "$TRASH_DIRECTORY/full" &&
>  	git commit-graph verify

Looks good to me; this is definitely necessary. For what it's worth, it
passes for me, but my system may not have as restrictive a umask as
others.

I'd be happy to re-send this patch, but alternatively if you want to
just squash this in, I'd be just as happy.

Thanks,
Taylor

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

* Re: [PATCH v2 3/4] commit-graph.c: write non-split graphs as read-only
  2020-04-27 23:59       ` Taylor Blau
@ 2020-04-28  0:25         ` Junio C Hamano
  2020-04-28  3:34         ` Jeff King
  1 sibling, 0 replies; 36+ messages in thread
From: Junio C Hamano @ 2020-04-28  0:25 UTC (permalink / raw)
  To: Taylor Blau; +Cc: git, peff, dstolee, mhagger

Taylor Blau <me@ttaylorr.com> writes:

> Looks good to me; this is definitely necessary. For what it's worth, it
> passes for me, but my system may not have as restrictive a umask as
> others.

Note that umask is not a system thing, but personal.  When I was
with smaller company, I used to have 002 as my umask, but these days
I use 077.

> I'd be happy to re-send this patch, but alternatively if you want to
> just squash this in, I'd be just as happy.

I'll keep it queued, until we need to replace it with an undated
series.

Thanks.

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

* Re: [PATCH v2 3/4] commit-graph.c: write non-split graphs as read-only
  2020-04-27 23:59       ` Taylor Blau
  2020-04-28  0:25         ` Junio C Hamano
@ 2020-04-28  3:34         ` Jeff King
  2020-04-28 16:50           ` Junio C Hamano
  1 sibling, 1 reply; 36+ messages in thread
From: Jeff King @ 2020-04-28  3:34 UTC (permalink / raw)
  To: Taylor Blau; +Cc: Junio C Hamano, git, dstolee, mhagger

On Mon, Apr 27, 2020 at 05:59:35PM -0600, Taylor Blau wrote:

> > diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
> > index fb0aae61c3..901eb3ecfb 100755
> > --- a/t/t5318-commit-graph.sh
> > +++ b/t/t5318-commit-graph.sh
> > @@ -12,6 +12,10 @@ test_expect_success 'setup full repo' '
> >  	test_oid_init
> >  '
> >
> > +test_expect_success POSIXPERM 'tweak umask for modebit tests' '
> > +	umask 022
> > +'
> > +
> >  test_expect_success 'verify graph with no graph file' '
> >  	cd "$TRASH_DIRECTORY/full" &&
> >  	git commit-graph verify
> 
> Looks good to me; this is definitely necessary. For what it's worth, it
> passes for me, but my system may not have as restrictive a umask as
> others.

If we're just doing this for a single test, perhaps it would be better
to set the umask in that test (perhaps even in a subshell to avoid
touching other tests). I guess that's a little awkward here because the
write and the mode-check happen in separate snippets.

Or going in the opposite direction: if we think that covering the rest
of the test suite with a diversity of umasks isn't worthwhile, we could
just set "umask" in test-lib.sh. That would solve this problem and any
future ones.

I also wondered if it would be simpler to just limit the scope of the
test, like so:

diff --git b/t/t5318-commit-graph.sh a/t/t5318-commit-graph.sh
index fb0aae61c3..5f1c746ad1 100755
--- b/t/t5318-commit-graph.sh
+++ a/t/t5318-commit-graph.sh
@@ -98,9 +98,10 @@ test_expect_success 'write graph' '
 
 test_expect_success POSIXPERM 'write graph has correct permissions' '
 	test_path_is_file $objdir/info/commit-graph &&
-	echo "-r--r--r--" >expect &&
 	test_modebits $objdir/info/commit-graph >actual &&
-	test_cmp expect actual
+	# check only user mode bits, as we do not want to rely on
+	# test environment umask
+	grep ^-r-- actual
 '
 
 graph_git_behavior 'graph exists' full commits/3 commits/1

but maybe there's some value in checking the whole thing.

-Peff

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

* Re: [PATCH v2 3/4] commit-graph.c: write non-split graphs as read-only
  2020-04-28  3:34         ` Jeff King
@ 2020-04-28 16:50           ` Junio C Hamano
  2020-04-28 20:59             ` Jeff King
  0 siblings, 1 reply; 36+ messages in thread
From: Junio C Hamano @ 2020-04-28 16:50 UTC (permalink / raw)
  To: Jeff King; +Cc: Taylor Blau, git, dstolee, mhagger

Jeff King <peff@peff.net> writes:

> If we're just doing this for a single test, perhaps it would be better
> to set the umask in that test (perhaps even in a subshell to avoid
> touching other tests). I guess that's a little awkward here because the
> write and the mode-check happen in separate snippets.

Yes, and we cannot afford to place the writing side under POSIXPERM
prerequisite.

> Or going in the opposite direction: if we think that covering the rest
> of the test suite with a diversity of umasks isn't worthwhile, we could
> just set "umask" in test-lib.sh. That would solve this problem and any
> future ones.

Seen from the point of view of giving us a stable testing
environment, it certainly feels like an easy and simple thing to do.
I do not offhand see any downsides in that approach.

On the other hand, we use and rely on test-specified umask only in a
few tests (t0001, t1301 and t1304).  Perhaps we should discourage
tests outside these to rely too heavily on exact perm bits?

For example, I wonder if we should have used

	test -r commit-graph && ! test -w commit-graph 

to ensure the file is read-only to the user who is testing, instead
of relying on parsing "ls -l" output, which IIRC has bitten us with
xattr and forced us to revise test_modebits helper in 5610e3b0 (Fix
testcase failure when extended attributes are in use, 2008-10-19).
That would make the test require SANITY instead, though.

> I also wondered if it would be simpler to just limit the scope of the
> test, like so:
> ...
> +	# check only user mode bits, as we do not want to rely on
> +	# test environment umask
> +	grep ^-r-- actual
>  '
> ...
> but maybe there's some value in checking the whole thing.

Yeah, I guess we are wondering about the same thing.

Among various approaches on plate, my preference is to use "umask
022" around the place where we prepare the $TRASH_DIRECTORY and do
so only when POSIXPERM is there in the test-lib.sh.  I do not know
if we should do so before or after creating the $TRASH_DIRECTORY;
my gut feeling is that in the ideal world, we should be able to

 - create trash directory

 - use the directory to automatically figure out POSIXPERM

 - if POSIXPERM is set, use umask 022 and chmod og=rx the trash
   directory

Automatically figuring out POSIXPERM the above approach shoots for
is a much larger change, so I am not in a haste to implement it and
it may be OK to only do "umask 022" after we set POSIXPERM for
everybody but MINGW at least as the initial cut, but that would mean
we would run for quite a long time with the testing user's umask
during the setup process, which is unsatisfying.

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

* Re: [PATCH v2 3/4] commit-graph.c: write non-split graphs as read-only
  2020-04-28 16:50           ` Junio C Hamano
@ 2020-04-28 20:59             ` Jeff King
  2020-04-28 21:05               ` Junio C Hamano
  0 siblings, 1 reply; 36+ messages in thread
From: Jeff King @ 2020-04-28 20:59 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Taylor Blau, git, dstolee, mhagger

On Tue, Apr 28, 2020 at 09:50:02AM -0700, Junio C Hamano wrote:

> Jeff King <peff@peff.net> writes:
> 
> > If we're just doing this for a single test, perhaps it would be better
> > to set the umask in that test (perhaps even in a subshell to avoid
> > touching other tests). I guess that's a little awkward here because the
> > write and the mode-check happen in separate snippets.
> 
> Yes, and we cannot afford to place the writing side under POSIXPERM
> prerequisite.

Do we need POSIXPERM just to call umask?

We call it unconditionally in t1304, for example. I could certainly
believe it doesn't do anything useful or predictable on other systems,
but it would not surprise me if it is a silent noop. It might return
non-zero, though (the call in t1304 is not inside a test snippet).

> Among various approaches on plate, my preference is to use "umask
> 022" around the place where we prepare the $TRASH_DIRECTORY and do
> so only when POSIXPERM is there in the test-lib.sh.  I do not know
> if we should do so before or after creating the $TRASH_DIRECTORY;
> my gut feeling is that in the ideal world, we should be able to
> 
>  - create trash directory
> 
>  - use the directory to automatically figure out POSIXPERM
> 
>  - if POSIXPERM is set, use umask 022 and chmod og=rx the trash
>    directory

I don't think we do any actual filesystem tests for POSIXPERM. It's
purely based on "uname -s", and we could check it much earlier. So
unless actually probing the filesystem is worth doing, we could just
punt on that part easily.

That said, I think this does get complicated when interacting with
t1304, for example, which explicitly creates an 077 umask for the trash
directory.

This is looking like a much deeper rabbit hole than it's worth going
down. I think the pragmatic thing is to just stick a "umask 022" near
the new test (or possibly "test_might_fail umask 022" inside the
commit-graph writing test).

-Peff

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

* Re: [PATCH v2 3/4] commit-graph.c: write non-split graphs as read-only
  2020-04-28 20:59             ` Jeff King
@ 2020-04-28 21:05               ` Junio C Hamano
  2020-04-28 21:08                 ` Jeff King
  0 siblings, 1 reply; 36+ messages in thread
From: Junio C Hamano @ 2020-04-28 21:05 UTC (permalink / raw)
  To: Jeff King; +Cc: Taylor Blau, git, dstolee, mhagger

Jeff King <peff@peff.net> writes:

> On Tue, Apr 28, 2020 at 09:50:02AM -0700, Junio C Hamano wrote:
>
>> Jeff King <peff@peff.net> writes:
>> 
>> > If we're just doing this for a single test, perhaps it would be better
>> > to set the umask in that test (perhaps even in a subshell to avoid
>> > touching other tests). I guess that's a little awkward here because the
>> > write and the mode-check happen in separate snippets.
>> 
>> Yes, and we cannot afford to place the writing side under POSIXPERM
>> prerequisite.
>
> Do we need POSIXPERM just to call umask?

I checked "git grep umask t/" hits, and I thought everybody was
using it inside POSIXPERM.

> We call it unconditionally in t1304, for example. I could certainly
> believe it doesn't do anything useful or predictable on other systems,
> but it would not surprise me if it is a silent noop. It might return
> non-zero, though (the call in t1304 is not inside a test snippet).

That is sloppy, but it might be deliberate that it does not check
the result?

> I don't think we do any actual filesystem tests for POSIXPERM. It's
> purely based on "uname -s", and we could check it much earlier. So
> unless actually probing the filesystem is worth doing, we could just
> punt on that part easily.

Yup.

> That said, I think this does get complicated when interacting with
> t1304, for example, which explicitly creates an 077 umask for the trash
> directory.
>
> This is looking like a much deeper rabbit hole than it's worth going
> down. I think the pragmatic thing is to just stick a "umask 022" near
> the new test (or possibly "test_might_fail umask 022" inside the
> commit-graph writing test).

I think the most pragmatic would be to just squash in what is
already there ;-)


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

* Re: [PATCH v2 3/4] commit-graph.c: write non-split graphs as read-only
  2020-04-28 21:05               ` Junio C Hamano
@ 2020-04-28 21:08                 ` Jeff King
  2020-04-28 21:44                   ` Taylor Blau
  0 siblings, 1 reply; 36+ messages in thread
From: Jeff King @ 2020-04-28 21:08 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Taylor Blau, git, dstolee, mhagger

On Tue, Apr 28, 2020 at 02:05:21PM -0700, Junio C Hamano wrote:

> > This is looking like a much deeper rabbit hole than it's worth going
> > down. I think the pragmatic thing is to just stick a "umask 022" near
> > the new test (or possibly "test_might_fail umask 022" inside the
> > commit-graph writing test).
> 
> I think the most pragmatic would be to just squash in what is
> already there ;-)

That is OK with me. :)

-Peff

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

* Re: [PATCH v2 3/4] commit-graph.c: write non-split graphs as read-only
  2020-04-28 21:08                 ` Jeff King
@ 2020-04-28 21:44                   ` Taylor Blau
  2020-04-28 21:58                     ` Jeff King
  0 siblings, 1 reply; 36+ messages in thread
From: Taylor Blau @ 2020-04-28 21:44 UTC (permalink / raw)
  To: Jeff King; +Cc: Junio C Hamano, Taylor Blau, git, dstolee, mhagger

On Tue, Apr 28, 2020 at 05:08:21PM -0400, Jeff King wrote:
> On Tue, Apr 28, 2020 at 02:05:21PM -0700, Junio C Hamano wrote:
>
> > > This is looking like a much deeper rabbit hole than it's worth going
> > > down. I think the pragmatic thing is to just stick a "umask 022" near
> > > the new test (or possibly "test_might_fail umask 022" inside the
> > > commit-graph writing test).
> >
> > I think the most pragmatic would be to just squash in what is
> > already there ;-)
>
> That is OK with me. :)

Thanks for an interesting discussion. I squashed Junio's fix into the
third patch, but the fourth patch suffers from the same problem (so I
stuck another POSIXPERM test to tweak the umask there, too).

What do you want to do about the final patch that I stuck on the end of
this series in [1]? If I don't hear from anybody, I'll send it as 5/5 in
v3 and we can feel free to not apply it if it's controversial.

> -Peff

Thanks,
Taylor

[1]: https://lore.kernel.org/git/20200427172111.GA58509@syl.local/

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

* Re: [PATCH v2 3/4] commit-graph.c: write non-split graphs as read-only
  2020-04-28 21:44                   ` Taylor Blau
@ 2020-04-28 21:58                     ` Jeff King
  2020-04-28 23:22                       ` Junio C Hamano
  0 siblings, 1 reply; 36+ messages in thread
From: Jeff King @ 2020-04-28 21:58 UTC (permalink / raw)
  To: Taylor Blau; +Cc: Junio C Hamano, git, dstolee, mhagger

On Tue, Apr 28, 2020 at 03:44:13PM -0600, Taylor Blau wrote:

> What do you want to do about the final patch that I stuck on the end of
> this series in [1]? If I don't hear from anybody, I'll send it as 5/5 in
> v3 and we can feel free to not apply it if it's controversial.

I have to admit I don't care that much either way about it (see my
earlier response on three mental models). I'm happy for you or Junio to
decide. :)

-Peff

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

* Re: [PATCH v2 3/4] commit-graph.c: write non-split graphs as read-only
  2020-04-28 21:58                     ` Jeff King
@ 2020-04-28 23:22                       ` Junio C Hamano
  2020-04-29 11:52                         ` Derrick Stolee
  0 siblings, 1 reply; 36+ messages in thread
From: Junio C Hamano @ 2020-04-28 23:22 UTC (permalink / raw)
  To: Jeff King; +Cc: Taylor Blau, git, dstolee, mhagger

Jeff King <peff@peff.net> writes:

> On Tue, Apr 28, 2020 at 03:44:13PM -0600, Taylor Blau wrote:
>
>> What do you want to do about the final patch that I stuck on the end of
>> this series in [1]? If I don't hear from anybody, I'll send it as 5/5 in
>> v3 and we can feel free to not apply it if it's controversial.
>
> I have to admit I don't care that much either way about it (see my
> earlier response on three mental models). I'm happy for you or Junio to
> decide. :)

My gut feeling is that our longer term goal (if we had timeperiod
during which the codebase is quiescent enough and infinite energy to
dedicate on code clean-up) among one or your options should be to
consistently create files that are rewritten-and-renamed read-only,
to discourage casual tampering, so I am OK with that 5th patch.

Having said that, I suspect that Derrick and friends are larger
stakeholders in the "chain" file, so I'd prefer to see us basing
the choice on their input.

Thanks.


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

* Re: [PATCH v2 3/4] commit-graph.c: write non-split graphs as read-only
  2020-04-28 23:22                       ` Junio C Hamano
@ 2020-04-29 11:52                         ` Derrick Stolee
  0 siblings, 0 replies; 36+ messages in thread
From: Derrick Stolee @ 2020-04-29 11:52 UTC (permalink / raw)
  To: Junio C Hamano, Jeff King; +Cc: Taylor Blau, git, dstolee, mhagger

On 4/28/2020 7:22 PM, Junio C Hamano wrote:
> Jeff King <peff@peff.net> writes:
> 
>> On Tue, Apr 28, 2020 at 03:44:13PM -0600, Taylor Blau wrote:
>>
>>> What do you want to do about the final patch that I stuck on the end of
>>> this series in [1]? If I don't hear from anybody, I'll send it as 5/5 in
>>> v3 and we can feel free to not apply it if it's controversial.
>>
>> I have to admit I don't care that much either way about it (see my
>> earlier response on three mental models). I'm happy for you or Junio to
>> decide. :)
> 
> My gut feeling is that our longer term goal (if we had timeperiod
> during which the codebase is quiescent enough and infinite energy to
> dedicate on code clean-up) among one or your options should be to
> consistently create files that are rewritten-and-renamed read-only,
> to discourage casual tampering, so I am OK with that 5th patch.
> 
> Having said that, I suspect that Derrick and friends are larger
> stakeholders in the "chain" file, so I'd prefer to see us basing
> the choice on their input.

I'm happy with how this discussion has gone. I'm sure the only reason
for the permissions I wrote was because I found them somewhere else in
the codebase and I copied them from there. Memory is fuzzy, but I can
guarantee the deviation from the norm was not in purpose.

Thanks,
-Stolee

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

* [PATCH v3 0/5] commit-graph: write non-split graphs as read-only
  2020-04-20 22:50 [PATCH 0/3] commit-graph: write non-split graphs as read-only Taylor Blau
                   ` (4 preceding siblings ...)
  2020-04-27 16:27 ` [PATCH v2 0/4] " Taylor Blau
@ 2020-04-29 17:36 ` Taylor Blau
  2020-04-29 17:36   ` [PATCH v3 1/5] tempfile.c: introduce 'create_tempfile_mode' Taylor Blau
                     ` (5 more replies)
  5 siblings, 6 replies; 36+ messages in thread
From: Taylor Blau @ 2020-04-29 17:36 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster, mhagger

Hi,

Here's a brief reroll to incorporate suggestions from Junio and Peff in
the sub-thread beginning at [1]. Not much at all has changed since v2,
with the exception of:

  * fixing the aforementioned issue by sprinkling in some 'umask 022's
    in throughout the new tests

  * adding in a new final patch to apply the same treatment to
    the 'commit-graph-chain' file

[1]: https://lore.kernel.org/git/xmqqr1w85vtq.fsf@gitster.c.googlers.com/

Taylor Blau (5):
  tempfile.c: introduce 'create_tempfile_mode'
  lockfile.c: introduce 'hold_lock_file_for_update_mode'
  commit-graph.c: write non-split graphs as read-only
  commit-graph.c: ensure graph layers respect core.sharedRepository
  commit-graph.c: make 'commit-graph-chain's read-only

 commit-graph.c                | 12 ++++++++++--
 lockfile.c                    | 18 ++++++++++--------
 lockfile.h                    | 32 ++++++++++++++++++++++++++++----
 t/t5318-commit-graph.sh       | 15 ++++++++++++++-
 t/t5324-split-commit-graph.sh | 24 ++++++++++++++++++++++++
 t/t6600-test-reach.sh         |  2 ++
 tempfile.c                    |  6 +++---
 tempfile.h                    | 10 +++++++++-
 8 files changed, 100 insertions(+), 19 deletions(-)

Range-diff against v2:
1:  03c975b0bd = 1:  03c975b0bd tempfile.c: introduce 'create_tempfile_mode'
2:  c1c84552bc = 2:  c1c84552bc lockfile.c: introduce 'hold_lock_file_for_update_mode'
3:  86cf29ce9c ! 3:  8d5503d2e6 commit-graph.c: write non-split graphs as read-only
    @@ Commit message
         commit-graph file into place and then trying to replace it. For these,
         make these files writable.

    +    Helped-by: Junio C Hamano <gitster@pobox.com>
         Signed-off-by: Taylor Blau <me@ttaylorr.com>

      ## commit-graph.c ##
    @@ commit-graph.c: static int write_commit_graph_file(struct write_commit_graph_con
      	}

      ## t/t5318-commit-graph.sh ##
    +@@ t/t5318-commit-graph.sh: test_expect_success 'setup full repo' '
    + 	test_oid_init
    + '
    +
    ++test_expect_success POSIXPERM 'tweak umask for modebit tests' '
    ++	umask 022
    ++'
    ++
    + test_expect_success 'verify graph with no graph file' '
    + 	cd "$TRASH_DIRECTORY/full" &&
    + 	git commit-graph verify
     @@ t/t5318-commit-graph.sh: test_expect_success 'write graph' '
      	graph_read_expect "3"
      '
4:  f83437f130 ! 4:  4b74e23af2 commit-graph.c: ensure graph layers respect core.sharedRepository
    @@ commit-graph.c: static int write_commit_graph_file(struct write_commit_graph_con
      		hold_lock_file_for_update_mode(&lk, ctx->graph_name,

      ## t/t5324-split-commit-graph.sh ##
    +@@ t/t5324-split-commit-graph.sh: graph_read_expect() {
    + 	test_cmp expect output
    + }
    +
    ++test_expect_success POSIXPERM 'tweak umask for modebit tests' '
    ++	umask 022
    ++'
    ++
    + test_expect_success 'create commits and write commit-graph' '
    + 	for i in $(test_seq 3)
    + 	do
     @@ t/t5324-split-commit-graph.sh: test_expect_success 'split across alternate where alternate is not split' '
      	test_cmp commit-graph .git/objects/info/commit-graph
      '
-:  ---------- > 5:  864c916067 commit-graph.c: make 'commit-graph-chain's read-only
--
2.26.0.113.ge9739cdccc

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

* [PATCH v3 1/5] tempfile.c: introduce 'create_tempfile_mode'
  2020-04-29 17:36 ` [PATCH v3 0/5] commit-graph: write non-split graphs as read-only Taylor Blau
@ 2020-04-29 17:36   ` Taylor Blau
  2020-04-29 17:36   ` [PATCH v3 2/5] lockfile.c: introduce 'hold_lock_file_for_update_mode' Taylor Blau
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 36+ messages in thread
From: Taylor Blau @ 2020-04-29 17:36 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster, mhagger

In the next patch, 'hold_lock_file_for_update' will gain an additional
'mode' parameter to specify permissions for the associated temporary
file.

Since the lockfile.c machinery uses 'create_tempfile' which always
creates a temporary file with global read-write permissions, introduce a
variant here that allows specifying the mode.

Note that the mode given to 'create_tempfile_mode' is not guaranteed to
be written to disk, since it is subject to both the umask and
'core.sharedRepository'.

Arguably, all temporary files should have permission 0444, since they
are likely to be renamed into place and then not written to again. This
is a much larger change than we may want to take on in this otherwise
small patch, so for the time being, make 'create_tempfile' behave as it
has always done by inlining it to 'create_tempfile_mode' with mode set
to '0666'.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 tempfile.c |  6 +++---
 tempfile.h | 10 +++++++++-
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/tempfile.c b/tempfile.c
index d43ad8c191..94aa18f3f7 100644
--- a/tempfile.c
+++ b/tempfile.c
@@ -130,17 +130,17 @@ static void deactivate_tempfile(struct tempfile *tempfile)
 }
 
 /* Make sure errno contains a meaningful value on error */
-struct tempfile *create_tempfile(const char *path)
+struct tempfile *create_tempfile_mode(const char *path, int mode)
 {
 	struct tempfile *tempfile = new_tempfile();
 
 	strbuf_add_absolute_path(&tempfile->filename, path);
 	tempfile->fd = open(tempfile->filename.buf,
-			    O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0666);
+			    O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, mode);
 	if (O_CLOEXEC && tempfile->fd < 0 && errno == EINVAL)
 		/* Try again w/o O_CLOEXEC: the kernel might not support it */
 		tempfile->fd = open(tempfile->filename.buf,
-				    O_RDWR | O_CREAT | O_EXCL, 0666);
+				    O_RDWR | O_CREAT | O_EXCL, mode);
 	if (tempfile->fd < 0) {
 		deactivate_tempfile(tempfile);
 		return NULL;
diff --git a/tempfile.h b/tempfile.h
index cddda0a33c..4de3bc77d2 100644
--- a/tempfile.h
+++ b/tempfile.h
@@ -88,8 +88,16 @@ struct tempfile {
  * Attempt to create a temporary file at the specified `path`. Return
  * a tempfile (whose "fd" member can be used for writing to it), or
  * NULL on error. It is an error if a file already exists at that path.
+ * Note that `mode` will be further modified by the umask, and possibly
+ * `core.sharedRepository`, so it is not guaranteed to have the given
+ * mode.
  */
-struct tempfile *create_tempfile(const char *path);
+struct tempfile *create_tempfile_mode(const char *path, int mode);
+
+static inline struct tempfile *create_tempfile(const char *path)
+{
+	return create_tempfile_mode(path, 0666);
+}
 
 /*
  * Register an existing file as a tempfile, meaning that it will be
-- 
2.26.0.113.ge9739cdccc


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

* [PATCH v3 2/5] lockfile.c: introduce 'hold_lock_file_for_update_mode'
  2020-04-29 17:36 ` [PATCH v3 0/5] commit-graph: write non-split graphs as read-only Taylor Blau
  2020-04-29 17:36   ` [PATCH v3 1/5] tempfile.c: introduce 'create_tempfile_mode' Taylor Blau
@ 2020-04-29 17:36   ` Taylor Blau
  2020-04-29 17:36   ` [PATCH v3 3/5] commit-graph.c: write non-split graphs as read-only Taylor Blau
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 36+ messages in thread
From: Taylor Blau @ 2020-04-29 17:36 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster, mhagger

We use 'hold_lock_file_for_update' (and the '_timeout') variant to
acquire a lock when updating references, the commit-graph file, and so
on.

In particular, the commit-graph machinery uses this to acquire a
temporary file that is used to write a non-split commit-graph. In a
subsequent commit, an issue in the commit-graph machinery produces
graph files that have a different permission based on whether or not
they are part of a multi-layer graph will be addressed.

To do so, the commit-graph machinery will need a version of
'hold_lock_file_for_update' that takes the permission bits from the
caller.

Introduce such a function in this patch for both the
'hold_lock_file_for_update' and 'hold_lock_file_for_update_timeout'
functions, and leave the existing functions alone by inlining their
definitions in terms of the new mode variants.

Note that, like in the previous commit, 'hold_lock_file_for_update_mode'
is not guarenteed to set the given mode, since it may be modified by
both the umask and 'core.sharedRepository'.

Note also that even though the commit-graph machinery only calls
'hold_lock_file_for_update', that this is defined in terms of
'hold_lock_file_for_update_timeout', and so both need an additional mode
parameter here.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 lockfile.c | 18 ++++++++++--------
 lockfile.h | 32 ++++++++++++++++++++++++++++----
 2 files changed, 38 insertions(+), 12 deletions(-)

diff --git a/lockfile.c b/lockfile.c
index 8e8ab4f29f..cc9a4b8428 100644
--- a/lockfile.c
+++ b/lockfile.c
@@ -70,7 +70,8 @@ static void resolve_symlink(struct strbuf *path)
 }
 
 /* Make sure errno contains a meaningful value on error */
-static int lock_file(struct lock_file *lk, const char *path, int flags)
+static int lock_file(struct lock_file *lk, const char *path, int flags,
+		     int mode)
 {
 	struct strbuf filename = STRBUF_INIT;
 
@@ -79,7 +80,7 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)
 		resolve_symlink(&filename);
 
 	strbuf_addstr(&filename, LOCK_SUFFIX);
-	lk->tempfile = create_tempfile(filename.buf);
+	lk->tempfile = create_tempfile_mode(filename.buf, mode);
 	strbuf_release(&filename);
 	return lk->tempfile ? lk->tempfile->fd : -1;
 }
@@ -99,7 +100,7 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)
  * exactly once. If timeout_ms is -1, try indefinitely.
  */
 static int lock_file_timeout(struct lock_file *lk, const char *path,
-			     int flags, long timeout_ms)
+			     int flags, long timeout_ms, int mode)
 {
 	int n = 1;
 	int multiplier = 1;
@@ -107,7 +108,7 @@ static int lock_file_timeout(struct lock_file *lk, const char *path,
 	static int random_initialized = 0;
 
 	if (timeout_ms == 0)
-		return lock_file(lk, path, flags);
+		return lock_file(lk, path, flags, mode);
 
 	if (!random_initialized) {
 		srand((unsigned int)getpid());
@@ -121,7 +122,7 @@ static int lock_file_timeout(struct lock_file *lk, const char *path,
 		long backoff_ms, wait_ms;
 		int fd;
 
-		fd = lock_file(lk, path, flags);
+		fd = lock_file(lk, path, flags, mode);
 
 		if (fd >= 0)
 			return fd; /* success */
@@ -169,10 +170,11 @@ NORETURN void unable_to_lock_die(const char *path, int err)
 }
 
 /* This should return a meaningful errno on failure */
-int hold_lock_file_for_update_timeout(struct lock_file *lk, const char *path,
-				      int flags, long timeout_ms)
+int hold_lock_file_for_update_timeout_mode(struct lock_file *lk,
+					   const char *path, int flags,
+					   long timeout_ms, int mode)
 {
-	int fd = lock_file_timeout(lk, path, flags, timeout_ms);
+	int fd = lock_file_timeout(lk, path, flags, timeout_ms, mode);
 	if (fd < 0) {
 		if (flags & LOCK_DIE_ON_ERROR)
 			unable_to_lock_die(path, errno);
diff --git a/lockfile.h b/lockfile.h
index 9843053ce8..db93e6ba73 100644
--- a/lockfile.h
+++ b/lockfile.h
@@ -90,6 +90,15 @@
  * functions. In particular, the state diagram and the cleanup
  * machinery are all implemented in the tempfile module.
  *
+ * Permission bits
+ * ---------------
+ *
+ * If you call either `hold_lock_file_for_update_mode` or
+ * `hold_lock_file_for_update_timeout_mode`, you can specify a suggested
+ * mode for the underlying temporary file. Note that the file isn't
+ * guaranteed to have this exact mode, since it may be limited by either
+ * the umask, 'core.sharedRepository', or both. See `adjust_shared_perm`
+ * for more.
  *
  * Error handling
  * --------------
@@ -156,12 +165,20 @@ struct lock_file {
  * file descriptor for writing to it, or -1 on error. If the file is
  * currently locked, retry with quadratic backoff for at least
  * timeout_ms milliseconds. If timeout_ms is 0, try exactly once; if
- * timeout_ms is -1, retry indefinitely. The flags argument and error
- * handling are described above.
+ * timeout_ms is -1, retry indefinitely. The flags argument, error
+ * handling, and mode are described above.
  */
-int hold_lock_file_for_update_timeout(
+int hold_lock_file_for_update_timeout_mode(
 		struct lock_file *lk, const char *path,
-		int flags, long timeout_ms);
+		int flags, long timeout_ms, int mode);
+
+static inline int hold_lock_file_for_update_timeout(
+		struct lock_file *lk, const char *path,
+		int flags, long timeout_ms)
+{
+	return hold_lock_file_for_update_timeout_mode(lk, path, flags,
+						      timeout_ms, 0666);
+}
 
 /*
  * Attempt to create a lockfile for the file at `path` and return a
@@ -175,6 +192,13 @@ static inline int hold_lock_file_for_update(
 	return hold_lock_file_for_update_timeout(lk, path, flags, 0);
 }
 
+static inline int hold_lock_file_for_update_mode(
+		struct lock_file *lk, const char *path,
+		int flags, int mode)
+{
+	return hold_lock_file_for_update_timeout_mode(lk, path, flags, 0, mode);
+}
+
 /*
  * Return a nonzero value iff `lk` is currently locked.
  */
-- 
2.26.0.113.ge9739cdccc


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

* [PATCH v3 3/5] commit-graph.c: write non-split graphs as read-only
  2020-04-29 17:36 ` [PATCH v3 0/5] commit-graph: write non-split graphs as read-only Taylor Blau
  2020-04-29 17:36   ` [PATCH v3 1/5] tempfile.c: introduce 'create_tempfile_mode' Taylor Blau
  2020-04-29 17:36   ` [PATCH v3 2/5] lockfile.c: introduce 'hold_lock_file_for_update_mode' Taylor Blau
@ 2020-04-29 17:36   ` Taylor Blau
  2020-04-29 17:36   ` [PATCH v3 4/5] commit-graph.c: ensure graph layers respect core.sharedRepository Taylor Blau
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 36+ messages in thread
From: Taylor Blau @ 2020-04-29 17:36 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster, mhagger

In the previous commit, Git learned 'hold_lock_file_for_update_mode' to
allow the caller to specify the permission bits (prior to further
adjustment by the umask and shared repository permissions) used when
acquiring a temporary file.

Use this in the commit-graph machinery for writing a non-split graph to
acquire an opened temporary file with permissions read-only permissions
to match the split behavior. (In the split case, Git uses
git_mkstemp_mode' for each of the commit-graph layers with permission
bits '0444').

One can notice this discrepancy when moving a non-split graph to be part
of a new chain. This causes a commit-graph chain where all layers have
read-only permission bits, except for the base layer, which is writable
for the current user.

Resolve this discrepancy by using the new
'hold_lock_file_for_update_mode' and passing the desired permission
bits.

Doing so causes some test fallout in t5318 and t6600. In t5318, this
occurs in tests that corrupt a commit-graph file by writing into it. For
these, 'chmod u+w'-ing the file beforehand resolves the issue. The
additional spot in 'corrupt_graph_verify' is necessary because of the
extra 'git commit-graph write' beforehand (which *does* rewrite the
commit-graph file). In t6600, this is caused by copying a read-only
commit-graph file into place and then trying to replace it. For these,
make these files writable.

Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 commit-graph.c          |  3 ++-
 t/t5318-commit-graph.sh | 15 ++++++++++++++-
 t/t6600-test-reach.sh   |  2 ++
 3 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/commit-graph.c b/commit-graph.c
index f013a84e29..5b5047a7dd 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -1388,7 +1388,8 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 
 		f = hashfd(fd, ctx->graph_name);
 	} else {
-		hold_lock_file_for_update(&lk, ctx->graph_name, LOCK_DIE_ON_ERROR);
+		hold_lock_file_for_update_mode(&lk, ctx->graph_name,
+					       LOCK_DIE_ON_ERROR, 0444);
 		fd = lk.tempfile->fd;
 		f = hashfd(lk.tempfile->fd, lk.tempfile->filename.buf);
 	}
diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index 9bf920ae17..901eb3ecfb 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -12,6 +12,10 @@ test_expect_success 'setup full repo' '
 	test_oid_init
 '
 
+test_expect_success POSIXPERM 'tweak umask for modebit tests' '
+	umask 022
+'
+
 test_expect_success 'verify graph with no graph file' '
 	cd "$TRASH_DIRECTORY/full" &&
 	git commit-graph verify
@@ -96,6 +100,13 @@ test_expect_success 'write graph' '
 	graph_read_expect "3"
 '
 
+test_expect_success POSIXPERM 'write graph has correct permissions' '
+	test_path_is_file $objdir/info/commit-graph &&
+	echo "-r--r--r--" >expect &&
+	test_modebits $objdir/info/commit-graph >actual &&
+	test_cmp expect actual
+'
+
 graph_git_behavior 'graph exists' full commits/3 commits/1
 
 test_expect_success 'Add more commits' '
@@ -421,7 +432,8 @@ GRAPH_BYTE_FOOTER=$(($GRAPH_OCTOPUS_DATA_OFFSET + 4 * $NUM_OCTOPUS_EDGES))
 corrupt_graph_setup() {
 	cd "$TRASH_DIRECTORY/full" &&
 	test_when_finished mv commit-graph-backup $objdir/info/commit-graph &&
-	cp $objdir/info/commit-graph commit-graph-backup
+	cp $objdir/info/commit-graph commit-graph-backup &&
+	chmod u+w $objdir/info/commit-graph
 }
 
 corrupt_graph_verify() {
@@ -435,6 +447,7 @@ corrupt_graph_verify() {
 	fi &&
 	git status --short &&
 	GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD=true git commit-graph write &&
+	chmod u+w $objdir/info/commit-graph &&
 	git commit-graph verify
 }
 
diff --git a/t/t6600-test-reach.sh b/t/t6600-test-reach.sh
index b24d850036..475564bee7 100755
--- a/t/t6600-test-reach.sh
+++ b/t/t6600-test-reach.sh
@@ -51,8 +51,10 @@ test_expect_success 'setup' '
 	done &&
 	git commit-graph write --reachable &&
 	mv .git/objects/info/commit-graph commit-graph-full &&
+	chmod u+w commit-graph-full &&
 	git show-ref -s commit-5-5 | git commit-graph write --stdin-commits &&
 	mv .git/objects/info/commit-graph commit-graph-half &&
+	chmod u+w commit-graph-half &&
 	git config core.commitGraph true
 '
 
-- 
2.26.0.113.ge9739cdccc


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

* [PATCH v3 4/5] commit-graph.c: ensure graph layers respect core.sharedRepository
  2020-04-29 17:36 ` [PATCH v3 0/5] commit-graph: write non-split graphs as read-only Taylor Blau
                     ` (2 preceding siblings ...)
  2020-04-29 17:36   ` [PATCH v3 3/5] commit-graph.c: write non-split graphs as read-only Taylor Blau
@ 2020-04-29 17:36   ` Taylor Blau
  2020-04-29 17:36   ` [PATCH v3 5/5] commit-graph.c: make 'commit-graph-chain's read-only Taylor Blau
  2020-05-01  5:52   ` [PATCH v3 0/5] commit-graph: write non-split graphs as read-only Jeff King
  5 siblings, 0 replies; 36+ messages in thread
From: Taylor Blau @ 2020-04-29 17:36 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster, mhagger

Non-layered commit-graphs use 'adjust_shared_perm' to make the
commit-graph file readable (or not) to a combination of the user, group,
and others.

Call 'adjust_shared_perm' for split-graph layers to make sure that these
also respect 'core.sharedRepository'. The 'commit-graph-chain' file
already respects this configuration since it uses
'hold_lock_file_for_update' (which calls 'adjust_shared_perm' eventually
in 'create_tempfile_mode').

Suggested-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 commit-graph.c                |  6 ++++++
 t/t5324-split-commit-graph.sh | 22 ++++++++++++++++++++++
 2 files changed, 28 insertions(+)

diff --git a/commit-graph.c b/commit-graph.c
index 5b5047a7dd..d05a55901d 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -1386,6 +1386,12 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 			return -1;
 		}
 
+		if (adjust_shared_perm(ctx->graph_name)) {
+			error(_("unable to adjust shared permissions for '%s'"),
+			      ctx->graph_name);
+			return -1;
+		}
+
 		f = hashfd(fd, ctx->graph_name);
 	} else {
 		hold_lock_file_for_update_mode(&lk, ctx->graph_name,
diff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh
index 53b2e6b455..699c23d077 100755
--- a/t/t5324-split-commit-graph.sh
+++ b/t/t5324-split-commit-graph.sh
@@ -36,6 +36,10 @@ graph_read_expect() {
 	test_cmp expect output
 }
 
+test_expect_success POSIXPERM 'tweak umask for modebit tests' '
+	umask 022
+'
+
 test_expect_success 'create commits and write commit-graph' '
 	for i in $(test_seq 3)
 	do
@@ -351,4 +355,22 @@ test_expect_success 'split across alternate where alternate is not split' '
 	test_cmp commit-graph .git/objects/info/commit-graph
 '
 
+while read mode modebits
+do
+	test_expect_success POSIXPERM "split commit-graph respects core.sharedrepository $mode" '
+		rm -rf $graphdir $infodir/commit-graph &&
+		git reset --hard commits/1 &&
+		test_config core.sharedrepository "$mode" &&
+		git commit-graph write --split --reachable &&
+		ls $graphdir/graph-*.graph >graph-files &&
+		test_line_count = 1 graph-files &&
+		echo "$modebits" >expect &&
+		test_modebits $graphdir/graph-*.graph >actual &&
+		test_cmp expect actual
+	'
+done <<\EOF
+0666 -r--r--r--
+0600 -r--------
+EOF
+
 test_done
-- 
2.26.0.113.ge9739cdccc


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

* [PATCH v3 5/5] commit-graph.c: make 'commit-graph-chain's read-only
  2020-04-29 17:36 ` [PATCH v3 0/5] commit-graph: write non-split graphs as read-only Taylor Blau
                     ` (3 preceding siblings ...)
  2020-04-29 17:36   ` [PATCH v3 4/5] commit-graph.c: ensure graph layers respect core.sharedRepository Taylor Blau
@ 2020-04-29 17:36   ` Taylor Blau
  2020-05-01  5:52   ` [PATCH v3 0/5] commit-graph: write non-split graphs as read-only Jeff King
  5 siblings, 0 replies; 36+ messages in thread
From: Taylor Blau @ 2020-04-29 17:36 UTC (permalink / raw)
  To: git; +Cc: peff, dstolee, gitster, mhagger

In a previous commit, we made incremental graph layers read-only by
using 'git_mkstemp_mode' with permissions '0444'.

There is no reason that 'commit-graph-chain's should be modifiable by
the user, since they are generated at a temporary location and then
atomically renamed into place.

To ensure that these files are read-only, too, use
'hold_lock_file_for_update_mode' with the same read-only permission
bits, and let the umask and 'adjust_shared_perm' take care of the rest.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
 commit-graph.c                | 3 ++-
 t/t5324-split-commit-graph.sh | 2 ++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/commit-graph.c b/commit-graph.c
index d05a55901d..b2dfd7701f 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -1378,7 +1378,8 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 	if (ctx->split) {
 		char *lock_name = get_chain_filename(ctx->odb);
 
-		hold_lock_file_for_update(&lk, lock_name, LOCK_DIE_ON_ERROR);
+		hold_lock_file_for_update_mode(&lk, lock_name,
+					       LOCK_DIE_ON_ERROR, 0444);
 
 		fd = git_mkstemp_mode(ctx->graph_name, 0444);
 		if (fd < 0) {
diff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh
index 699c23d077..cff5a41f48 100755
--- a/t/t5324-split-commit-graph.sh
+++ b/t/t5324-split-commit-graph.sh
@@ -366,6 +366,8 @@ do
 		test_line_count = 1 graph-files &&
 		echo "$modebits" >expect &&
 		test_modebits $graphdir/graph-*.graph >actual &&
+		test_cmp expect actual &&
+		test_modebits $graphdir/commit-graph-chain >actual &&
 		test_cmp expect actual
 	'
 done <<\EOF
-- 
2.26.0.113.ge9739cdccc

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

* Re: [PATCH v3 0/5] commit-graph: write non-split graphs as read-only
  2020-04-29 17:36 ` [PATCH v3 0/5] commit-graph: write non-split graphs as read-only Taylor Blau
                     ` (4 preceding siblings ...)
  2020-04-29 17:36   ` [PATCH v3 5/5] commit-graph.c: make 'commit-graph-chain's read-only Taylor Blau
@ 2020-05-01  5:52   ` Jeff King
  5 siblings, 0 replies; 36+ messages in thread
From: Jeff King @ 2020-05-01  5:52 UTC (permalink / raw)
  To: Taylor Blau; +Cc: git, dstolee, gitster, mhagger

On Wed, Apr 29, 2020 at 11:36:26AM -0600, Taylor Blau wrote:

> Here's a brief reroll to incorporate suggestions from Junio and Peff in
> the sub-thread beginning at [1]. Not much at all has changed since v2,
> with the exception of:
> 
>   * fixing the aforementioned issue by sprinkling in some 'umask 022's
>     in throughout the new tests
> 
>   * adding in a new final patch to apply the same treatment to
>     the 'commit-graph-chain' file

Thanks, this version looks good to me.

-Peff

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

end of thread, other threads:[~2020-05-01  5:59 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-20 22:50 [PATCH 0/3] commit-graph: write non-split graphs as read-only Taylor Blau
2020-04-20 22:51 ` [PATCH 1/3] tempfile.c: introduce 'create_tempfile_mode' Taylor Blau
2020-04-20 23:31   ` Junio C Hamano
2020-04-20 22:51 ` [PATCH 2/3] lockfile.c: introduce 'hold_lock_file_for_update_mode' Taylor Blau
2020-04-20 22:51 ` [PATCH 3/3] commit-graph.c: write non-split graphs as read-only Taylor Blau
2020-04-20 23:23 ` [PATCH 0/3] commit-graph: " Junio C Hamano
2020-04-20 23:39   ` Taylor Blau
2020-04-21  1:17     ` Junio C Hamano
2020-04-21  7:01       ` Jeff King
2020-04-21 18:59         ` Junio C Hamano
2020-04-27 16:27 ` [PATCH v2 0/4] " Taylor Blau
2020-04-27 16:27   ` [PATCH v2 1/4] tempfile.c: introduce 'create_tempfile_mode' Taylor Blau
2020-04-27 16:27   ` [PATCH v2 2/4] lockfile.c: introduce 'hold_lock_file_for_update_mode' Taylor Blau
2020-04-27 16:28   ` [PATCH v2 3/4] commit-graph.c: write non-split graphs as read-only Taylor Blau
2020-04-27 23:54     ` Junio C Hamano
2020-04-27 23:59       ` Taylor Blau
2020-04-28  0:25         ` Junio C Hamano
2020-04-28  3:34         ` Jeff King
2020-04-28 16:50           ` Junio C Hamano
2020-04-28 20:59             ` Jeff King
2020-04-28 21:05               ` Junio C Hamano
2020-04-28 21:08                 ` Jeff King
2020-04-28 21:44                   ` Taylor Blau
2020-04-28 21:58                     ` Jeff King
2020-04-28 23:22                       ` Junio C Hamano
2020-04-29 11:52                         ` Derrick Stolee
2020-04-27 16:28   ` [PATCH v2 4/4] commit-graph.c: ensure graph layers respect core.sharedRepository Taylor Blau
2020-04-27 17:21     ` Taylor Blau
2020-04-27 20:58       ` Jeff King
2020-04-29 17:36 ` [PATCH v3 0/5] commit-graph: write non-split graphs as read-only Taylor Blau
2020-04-29 17:36   ` [PATCH v3 1/5] tempfile.c: introduce 'create_tempfile_mode' Taylor Blau
2020-04-29 17:36   ` [PATCH v3 2/5] lockfile.c: introduce 'hold_lock_file_for_update_mode' Taylor Blau
2020-04-29 17:36   ` [PATCH v3 3/5] commit-graph.c: write non-split graphs as read-only Taylor Blau
2020-04-29 17:36   ` [PATCH v3 4/5] commit-graph.c: ensure graph layers respect core.sharedRepository Taylor Blau
2020-04-29 17:36   ` [PATCH v3 5/5] commit-graph.c: make 'commit-graph-chain's read-only Taylor Blau
2020-05-01  5:52   ` [PATCH v3 0/5] commit-graph: write non-split graphs as read-only Jeff King

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