Skip to content

Commit d1b44bb

Browse files
ttaylorrpeff
authored andcommitted
finalize_object_file(): check for name collision before renaming
We prefer link()/unlink() to rename() for object files, with the idea that we should prefer the data that is already on disk to what is incoming. But we may fall back to rename() if the user has configured us to do so, or if the filesystem seems not to support cross-directory links. This loses the "prefer what is on disk" property. We can mitigate this somewhat by trying to stat() the destination filename before doing the rename. This is racy, since the object could be created between the stat() and rename() calls. But in practice it is expanding the definition of "what is already on disk" to be the point that the function is called. That is enough to deal with any potential attacks where an attacker is trying to collide hashes with what's already in the repository. Co-authored-by: Jeff King <[email protected]> Signed-off-by: Jeff King <[email protected]> Signed-off-by: Taylor Blau <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 2e7b89e commit d1b44bb

File tree

1 file changed

+6
-2
lines changed

1 file changed

+6
-2
lines changed

object-file.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1904,6 +1904,7 @@ static void write_object_file_prepare_literally(const struct git_hash_algo *algo
19041904
*/
19051905
int finalize_object_file(const char *tmpfile, const char *filename)
19061906
{
1907+
struct stat st;
19071908
int ret = 0;
19081909

19091910
if (object_creation_mode == OBJECT_CREATION_USES_RENAMES)
@@ -1924,9 +1925,12 @@ int finalize_object_file(const char *tmpfile, const char *filename)
19241925
*/
19251926
if (ret && ret != EEXIST) {
19261927
try_rename:
1927-
if (!rename(tmpfile, filename))
1928+
if (!stat(filename, &st))
1929+
ret = EEXIST;
1930+
else if (!rename(tmpfile, filename))
19281931
goto out;
1929-
ret = errno;
1932+
else
1933+
ret = errno;
19301934
}
19311935
unlink_or_warn(tmpfile);
19321936
if (ret) {

0 commit comments

Comments
 (0)