diff options
| author | Jason A. Donenfeld <Jason@zx2c4.com> | 2026-04-13 19:02:31 +0200 |
|---|---|---|
| committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2026-04-13 19:04:38 +0200 |
| commit | 829eb0711305e8946fa2f4a1c57c43354f35e208 (patch) | |
| tree | af4ba00100ac7ce398f6654c693a2f367945d443 | |
| parent | 0d8e5fbc31e1082063bfb5155c35b7869721152b (diff) | |
| download | cgit-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.c | 2 |
1 files changed, 2 insertions, 0 deletions
@@ -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; |
