git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH] shallow: verify shallow file after taking lock

From
Jeff King <peff@peff.net>
Date
Feb 27, 2014, 09:10 UTC
Message-ID
<20140227091012.GB21892@sigill.intra.peff.net>
In-Reply-To
<20140227090426.GA21892@sigill.intra.peff.net>

Before writing the shallow file, we stat() the existing file to make sure it has not been updated since our operation began. However, we do not do so under a lock, so there is a possible race:

  1. Process A takes the lock.
  2. Process B calls check_shallow_file_for_update and finds
     no update.
  3. Process A commits the lockfile.
  4. Process B takes the lock, then overwrite's process A's
     changes.
We can fix this by doing our check while we hold the lock.
Signed-off-by: Jeff King <peff@peff.net>
---
On Thu, Feb 27, 2014 at 04:04:26AM -0500, Jeff King wrote:
> by the way, shouldn't we do that check under the lock? I think
> setup_alternate_shallow has a race condition).

Here is the fix. I didn't actually reproduce the race experimentally, but it seems pretty straightforward.

I also notice that check_shallow_file_for_update returns early if !is_shallow. Is that safe? Is it possible for another process to have made us shallow since the program began? In that case, we would have to stat() the file always, then complain if it exists and !is_shallow.

 shallow.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/shallow.c b/shallow.c
index bbc98b5..75da07a 100644
--- a/shallow.c
+++ b/shallow.c
@@ -246,9 +246,9 @@ void setup_alternate_shallow(struct lock_file *shallow_lock,
 	struct strbuf sb = STRBUF_INIT;
 	int fd;
 
-	check_shallow_file_for_update();
 	fd = hold_lock_file_for_update(shallow_lock, git_path("shallow"),
 				       LOCK_DIE_ON_ERROR);
+	check_shallow_file_for_update();
 	if (write_shallow_commits(&sb, 0, extra)) {
 		if (write_in_full(fd, sb.buf, sb.len) != sb.len)
 			die_errno("failed to write to %s",
@@ -293,9 +293,9 @@ void prune_shallow(int show_only)
 		strbuf_release(&sb);
 		return;
 	}
-	check_shallow_file_for_update();
 	fd = hold_lock_file_for_update(&shallow_lock, git_path("shallow"),
 				       LOCK_DIE_ON_ERROR);
+	check_shallow_file_for_update();
 	if (write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY)) {
 		if (write_in_full(fd, sb.buf, sb.len) != sb.len)
 			die_errno("failed to write to %s",
-- 
1.8.5.2.500.g8060133
Previous: Jeff KingNext: Jeff King
Message 3 of 21 in “upload-pack: allow shallow fetching from a read-only repository”
  1. upload-pack: allow shallow fetching from a read-only repositoryNguyễn Thái Ngọc Duy, Feb 27, 2014
  2. Jeff KingFeb 27, 2014
  3. shallow: verify shallow file after taking lockJeff King, Feb 27, 2014
  4. Jeff KingFeb 27, 2014
  5. Duy NguyenFeb 27, 2014
  6. shallow: use stat_validity to check for up-to-date fileJeff King, Feb 27, 2014
  7. Duy NguyenFeb 27, 2014
  8. shallow: automatically clean up shallow tempfilesJeff King, Feb 27, 2014
  9. upload-pack: allow shallow fetching from a read-only repositoryNguyễn Thái Ngọc Duy, Mar 4, 2014
  10. Junio C HamanoMar 4, 2014
  11. Duy NguyenMar 5, 2014
  12. Junio C HamanoMar 5, 2014
  13. upload-pack: send shallow info over stdin to pack-objectsNguyễn Thái Ngọc Duy, Mar 6, 2014
  14. Junio C HamanoMar 6, 2014
  15. Duy NguyenMar 6, 2014
  16. Junio C HamanoMar 7, 2014
  17. Duy NguyenMar 8, 2014
  18. Junio C HamanoMar 10, 2014
  19. Duy NguyenMar 7, 2014
  20. Junio C HamanoMar 7, 2014
  21. upload-pack: send shallow info over stdin to pack-objectsNguyễn Thái Ngọc Duy, Mar 11, 2014

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.