1#!/bin/sh 2 3test_description='bounds-checking of access to mmapped on-disk file formats' 4. ./test-lib.sh 5 6clear_base () { 7 test_when_finished 'restore_base'&& 8rm-f$base 9} 10 11restore_base () { 12cp base-backup/* .git/objects/pack/ 13} 14 15do_pack () { 16 pack_objects=$1;shift 17 sha1=$( 18for i in$pack_objects 19do 20echo$i 21done| git pack-objects"$@" .git/objects/pack/pack 22) && 23 pack=.git/objects/pack/pack-$sha1.pack && 24 idx=.git/objects/pack/pack-$sha1.idx && 25chmod+w $pack $idx&& 26 test_when_finished 'rm -f "$pack" "$idx"' 27} 28 29munge () { 30printf"$3"|dd of="$1" bs=1 conv=notrunc seek=$2 31} 32 33# Offset in a v2 .idx to its initial and extended offset tables. For an index 34# with "nr" objects, this is: 35# 36# magic(4) + version(4) + fan-out(4*256) + sha1s(20*nr) + crc(4*nr), 37# 38# for the initial, and another ofs(4*nr) past that for the extended. 39# 40ofs_table () { 41echo$((4 + 4 + 4*256 + 20*$1 + 4*$1)) 42} 43extended_table () { 44echo$(($(ofs_table "$1")+4*$1)) 45} 46 47test_expect_success 'set up base packfile and variables'' 48 # the hash of this content starts with ff, which 49 # makes some later computations much simpler 50 echo 74 >file && 51 git add file && 52 git commit -m base && 53 git repack -ad && 54 base=$(echo .git/objects/pack/*)&& 55 chmod +w$base&& 56 mkdir base-backup && 57 cp$basebase-backup/ && 58 object=$(git rev-parse HEAD:file) 59' 60 61test_expect_success 'pack/index object count mismatch'' 62 do_pack$object&& 63 munge$pack8 "\377\0\0\0" && 64 clear_base && 65 66 # We enumerate the objects from the completely-fine 67 # .idx, but notice later that the .pack is bogus 68 # and fail to show any data. 69 echo "$objectmissing" >expect && 70 git cat-file --batch-all-objects --batch-check >actual && 71 test_cmp expect actual && 72 73 # ...and here fail to load the object (without segfaulting), 74 # but fallback to a good copy if available. 75 test_must_fail git cat-file blob$object&& 76 restore_base && 77 git cat-file blob$object>actual && 78 test_cmp file actual && 79 80 # ...and make sure that index-pack --verify, which has its 81 # own reading routines, does not segfault. 82 test_must_fail git index-pack --verify$pack 83' 84 85test_expect_success 'matched bogus object count'' 86 do_pack$object&& 87 munge$pack8 "\377\0\0\0" && 88 munge$idx$((255 * 4)) "\377\0\0\0" && 89 clear_base && 90 91 # Unlike above, we should notice early that the .idx is totally 92 # bogus, and not even enumerate its contents. 93 git cat-file --batch-all-objects --batch-check >actual && 94 test_must_be_empty actual && 95 96 # But as before, we can do the same object-access checks. 97 test_must_fail git cat-file blob$object&& 98 restore_base && 99 git cat-file blob$object>actual && 100 test_cmp file actual && 101 102 test_must_fail git index-pack --verify$pack 103' 104 105# Note that we cannot check the fallback case for these 106# further .idx tests, as we notice the problem in functions 107# whose interface doesn't allow an error return (like use_pack()), 108# and thus we just die(). 109# 110# There's also no point in doing enumeration tests, as 111# we are munging offsets here, which are about looking up 112# specific objects. 113 114test_expect_success 'bogus object offset (v1)'' 115 do_pack$object--index-version=1 && 116 munge$idx$((4 * 256)) "\377\0\0\0" && 117 clear_base && 118 test_must_fail git cat-file blob$object&& 119 test_must_fail git index-pack --verify$pack 120' 121 122test_expect_success 'bogus object offset (v2, no msb)'' 123 do_pack$object--index-version=2 && 124 munge$idx$(ofs_table 1)"\0\377\0\0" && 125 clear_base && 126 test_must_fail git cat-file blob$object&& 127 test_must_fail git index-pack --verify$pack 128' 129 130test_expect_success 'bogus offset into v2 extended table'' 131 do_pack$object--index-version=2 && 132 munge$idx$(ofs_table 1)"\377\0\0\0" && 133 clear_base && 134 test_must_fail git cat-file blob$object&& 135 test_must_fail git index-pack --verify$pack 136' 137 138test_expect_success 'bogus offset inside v2 extended table'' 139 # We need two objects here, so we can plausibly require 140 # an extended table (if the first object were larger than 2^31). 141 # 142 # Note that the value is important here. We want$objectas 143 # the second entry in sorted-sha1 order. The sha1 of 1485 starts 144 # with "000", which sorts before that of$object(which starts 145 # with "fff"). 146 second=$(echo 1485 | git hash-object -w --stdin)&& 147 do_pack "$object$second" --index-version=2 && 148 149 # We have to make extra room for the table, so we cannot 150 # just munge in place as usual. 151 { 152 dd if=$idxbs=1 count=$(($(ofs_table 2)+ 4)) && 153 printf "\200\0\0\0" && 154 printf "\377\0\0\0\0\0\0\0" && 155 dd if=$idxbs=1 skip=$(extended_table 2) 156 } >tmp && 157 mv tmp "$idx" && 158 clear_base && 159 test_must_fail git cat-file blob$object&& 160 test_must_fail git index-pack --verify$pack 161' 162 163test_expect_success 'bogus OFS_DELTA in packfile'' 164 # Generate a pack with a delta in it. 165 base=$(test-tool genrandom foo 3000 | git hash-object --stdin -w)&& 166 delta=$(test-tool genrandom foo 2000 | git hash-object --stdin -w)&& 167 do_pack "$base$delta" --delta-base-offset && 168 rm -f .git/objects/??/* && 169 170 # Double check that we have the delta we expect. 171 echo$base>expect && 172 echo$delta| git cat-file --batch-check="%(deltabase)" >actual && 173 test_cmp expect actual && 174 175 # Now corrupt it. We assume the varint size for the delta is small 176 # enough to fit in the first byte (which it should be, since it 177 # is a pure deletion from the base), and that original ofs_delta 178 # takes 2 bytes (which it should, as it should be ~3000). 179 ofs=$(git show-index <$idx | grep $delta | cut -d" " -f1)&& 180 munge$pack$(($ofs + 1)) "\177\377" && 181 test_must_fail git cat-file blob$delta>/dev/null 182' 183 184test_done