aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2026-04-13 19:02:31 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2026-04-13 19:04:38 +0200
commit829eb0711305e8946fa2f4a1c57c43354f35e208 (patch)
treeaf4ba00100ac7ce398f6654c693a2f367945d443
parent0d8e5fbc31e1082063bfb5155c35b7869721152b (diff)
downloadcgit-829eb0711305e8946fa2f4a1c57c43354f35e208.tar.xz
cache: truncate lock file before filling
lock_slot() opens the lock file with O_RDWR|O_CREAT but without O_TRUNC. If a previous cgit process was killed between lock_slot() and unlock_slot() (e.g. by a CGI timeout or OOM), the stale lock file remains on disk with the old content, and the kernel releases the fcntl lock. The next process to claim the same cache slot then opens this stale lock file, acquires the fcntl lock, writes its key and generated content on top of the old bytes. If the new response is shorter than what was previously in the file, trailing bytes from the old response survive beyond the end of the new content. fstat() in fill_slot() reports the total file size (including the stale tail), and print_slot() faithfully sends all of it -- producing a response that is the correct page followed by a fragment of whatever previously occupied that lock file. Fix this by truncating the lock file after acquiring the lock and before writing the new key. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r--cache.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/cache.c b/cache.c
index 1c843ba..e70af13 100644
--- a/cache.c
+++ b/cache.c
@@ -185,6 +185,8 @@ static int lock_slot(struct cache_slot *slot)
slot->lock_fd = -1;
return saved_errno;
}
+ if (ftruncate(slot->lock_fd, 0) < 0)
+ return errno;
if (xwrite(slot->lock_fd, slot->key, slot->keylen + 1) < 0)
return errno;
return 0;