From 93cff9a978e1c177ac3e889867004a56773301b2 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sat, 1 Apr 2017 04:05:21 -0400 Subject: sha1_loose_object_info: return error for corrupted objects When sha1_loose_object_info() finds that a loose object file cannot be stat(2)ed or mmap(2)ed, it returns -1 to signal an error to the caller. However, if it found that the loose object file is corrupt and the object data cannot be used from it, it stuffs OBJ_BAD into "type" field of the object_info, but returns zero (i.e., success), which can confuse callers. This is due to 052fe5eac (sha1_loose_object_info: make type lookup optional, 2013-07-12), which switched the return to a strict success/error, rather than returning the type (but botched the return). Callers of regular sha1_object_info() don't notice the difference, as that function returns the type (which is OBJ_BAD in this case). However, direct callers of sha1_object_info_extended() see the function return success, but without setting any meaningful values in the object_info struct, leading them to access potentially uninitialized memory. The easiest way to see the bug is via "cat-file -s", which will happily ignore the corruption and report whatever value happened to be in the "size" variable. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t1060-object-corruption.sh | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 't/t1060-object-corruption.sh') diff --git a/t/t1060-object-corruption.sh b/t/t1060-object-corruption.sh index 3f8705139d..3a88d79c5f 100755 --- a/t/t1060-object-corruption.sh +++ b/t/t1060-object-corruption.sh @@ -53,6 +53,13 @@ test_expect_success 'streaming a corrupt blob fails' ' ) ' +test_expect_success 'getting type of a corrupt blob fails' ' + ( + cd bit-error && + test_must_fail git cat-file -s HEAD:content.t + ) +' + test_expect_success 'read-tree -u detects bit-errors in blobs' ' ( cd bit-error && -- cgit v1.2.3 From 51054177b312ce0795f2866d4c3aed246eeccea9 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sat, 1 Apr 2017 04:09:32 -0400 Subject: index-pack: detect local corruption in collision check When we notice that we have a local copy of an incoming object, we compare the two objects to make sure we haven't found a collision. Before we get to the actual object bytes, though, we compare the type and size from sha1_object_info(). If our local object is corrupted, then the type will be OBJ_BAD, which obviously will not match the incoming type, and we'll report "SHA1 COLLISION FOUND" (with capital letters and everything). This is confusing, as the problem is not a collision but rather local corruption. We should report that instead (just like we do if reading the rest of the object content fails a few lines later). Note that we _could_ just ignore the error and mark it as a non-collision. That would let you "git fetch" to replace a corrupted object. But it's not a very reliable method for repairing a repository. The earlier want/have negotiation tries to get the other side to omit objects we already have, and it would not realize that we are "missing" this corrupted object. So we're better off complaining loudly when we see corruption, and letting the user take more drastic measures to repair (like making a full clone elsewhere and copying the pack into place). Note that the test sets transfer.unpackLimit in the receiving repository so that we use index-pack (which is what does the collision check). Normally for such a small push we'd use unpack-objects, which would simply try to write the loose object, and discard the new one when we see that there's already an old one. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t1060-object-corruption.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 't/t1060-object-corruption.sh') diff --git a/t/t1060-object-corruption.sh b/t/t1060-object-corruption.sh index 3a88d79c5f..ac1f189fd2 100755 --- a/t/t1060-object-corruption.sh +++ b/t/t1060-object-corruption.sh @@ -21,6 +21,14 @@ test_expect_success 'setup corrupt repo' ' cd bit-error && test_commit content && corrupt_byte HEAD:content.t 10 + ) && + git init no-bit-error && + ( + # distinct commit from bit-error, but containing a + # non-corrupted version of the same blob + cd no-bit-error && + test_tick && + test_commit content ) ' @@ -108,4 +116,13 @@ test_expect_failure 'clone --local detects misnamed objects' ' test_must_fail git clone --local misnamed misnamed-checkout ' +test_expect_success 'fetch into corrupted repo with index-pack' ' + ( + cd bit-error && + test_must_fail git -c transfer.unpackLimit=1 \ + fetch ../no-bit-error 2>stderr && + test_i18ngrep ! -i collision stderr + ) +' + test_done -- cgit v1.2.3