3 test_description
='bounds-checking of access to mmapped on-disk file formats'
5 TEST_PASSES_SANITIZE_LEAK
=true
9 test_when_finished
'restore_base' &&
14 cp -r base-backup
/* .git
/objects
/pack
/
18 pack_objects
=$1; shift
20 for i
in $pack_objects
23 done | git pack-objects
"$@" .git
/objects
/pack
/pack
25 pack
=.git
/objects
/pack
/pack-
$sha1.pack
&&
26 idx
=.git
/objects
/pack
/pack-
$sha1.idx
&&
27 chmod +w
$pack $idx &&
28 test_when_finished
'rm -f "$pack" "$idx"'
32 printf "$3" |
dd of
="$1" bs
=1 conv
=notrunc seek
=$2
35 # Offset in a v2 .idx to its initial and extended offset tables. For an index
36 # with "nr" objects, this is:
38 # magic(4) + version(4) + fan-out(4*256) + sha1s(20*nr) + crc(4*nr),
40 # for the initial, and another ofs(4*nr) past that for the extended.
43 echo $
((4 + 4 + 4*256 + $
(test_oid rawsz
)*$1 + 4*$1))
46 echo $
(($
(ofs_table
"$1") + 4*$1))
49 test_expect_success
'setup' '
59 test_expect_success
'set up base packfile and variables' '
60 # the hash of this content starts with ff, which
61 # makes some later computations much simpler
62 test_oid oidfff >file &&
66 base=$(echo .git/objects/pack/*) &&
69 cp -r $base base-backup/ &&
70 object=$(git rev-parse HEAD:file)
73 test_expect_success
'pack/index object count mismatch' '
75 munge $pack 8 "\377\0\0\0" &&
78 # We enumerate the objects from the completely-fine
79 # .idx, but notice later that the .pack is bogus
80 # and fail to show any data.
81 echo "$object missing" >expect &&
82 git cat-file --batch-all-objects --batch-check >actual &&
83 test_cmp expect actual &&
85 # ...and here fail to load the object (without segfaulting),
86 # but fallback to a good copy if available.
87 test_must_fail git cat-file blob $object &&
89 git cat-file blob $object >actual &&
90 test_cmp file actual &&
92 # ...and make sure that index-pack --verify, which has its
93 # own reading routines, does not segfault.
94 test_must_fail git index-pack --verify $pack
97 test_expect_success
'matched bogus object count' '
99 munge $pack 8 "\377\0\0\0" &&
100 munge $idx $((255 * 4)) "\377\0\0\0" &&
103 # Unlike above, we should notice early that the .idx is totally
104 # bogus, and not even enumerate its contents.
105 git cat-file --batch-all-objects --batch-check >actual &&
106 test_must_be_empty actual &&
108 # But as before, we can do the same object-access checks.
109 test_must_fail git cat-file blob $object &&
111 git cat-file blob $object >actual &&
112 test_cmp file actual &&
114 test_must_fail git index-pack --verify $pack
117 # Note that we cannot check the fallback case for these
118 # further .idx tests, as we notice the problem in functions
119 # whose interface doesn't allow an error return (like use_pack()),
120 # and thus we just die().
122 # There's also no point in doing enumeration tests, as
123 # we are munging offsets here, which are about looking up
126 test_expect_success
'bogus object offset (v1)' '
127 do_pack $object --index-version=1 &&
128 munge $idx $((4 * 256)) "\377\0\0\0" &&
130 test_must_fail git cat-file blob $object &&
131 test_must_fail git index-pack --verify $pack
134 test_expect_success
'bogus object offset (v2, no msb)' '
135 do_pack $object --index-version=2 &&
136 munge $idx $(ofs_table 1) "\0\377\0\0" &&
138 test_must_fail git cat-file blob $object &&
139 test_must_fail git index-pack --verify $pack
142 test_expect_success
'bogus offset into v2 extended table' '
143 do_pack $object --index-version=2 &&
144 munge $idx $(ofs_table 1) "\377\0\0\0" &&
146 test_must_fail git cat-file blob $object &&
147 test_must_fail git index-pack --verify $pack
150 test_expect_success
'bogus offset inside v2 extended table' '
151 # We need two objects here, so we can plausibly require
152 # an extended table (if the first object were larger than 2^31).
154 # Note that the value is important here. We want $object as
155 # the second entry in sorted-hash order. The hash of this object starts
156 # with "000", which sorts before that of $object (which starts
158 second=$(test_oid oid000 | git hash-object -w --stdin) &&
159 do_pack "$object $second" --index-version=2 &&
161 # We have to make extra room for the table, so we cannot
162 # just munge in place as usual.
164 dd if=$idx bs=1 count=$(($(ofs_table 2) + 4)) &&
165 printf "\200\0\0\0" &&
166 printf "\377\0\0\0\0\0\0\0" &&
167 dd if=$idx bs=1 skip=$(extended_table 2)
171 test_must_fail git cat-file blob $object &&
172 test_must_fail git index-pack --verify $pack
175 test_expect_success
'bogus OFS_DELTA in packfile' '
176 # Generate a pack with a delta in it.
177 base=$(test-tool genrandom foo 3000 | git hash-object --stdin -w) &&
178 delta=$(test-tool genrandom foo 2000 | git hash-object --stdin -w) &&
179 do_pack "$base $delta" --delta-base-offset &&
180 rm -f .git/objects/??/* &&
182 # Double check that we have the delta we expect.
183 echo $base >expect &&
184 echo $delta | git cat-file --batch-check="%(deltabase)" >actual &&
185 test_cmp expect actual &&
187 # Now corrupt it. We assume the varint size for the delta is small
188 # enough to fit in the first byte (which it should be, since it
189 # is a pure deletion from the base), and that original ofs_delta
190 # takes 2 bytes (which it should, as it should be ~3000).
191 ofs=$(git show-index <$idx | grep $delta | cut -d" " -f1) &&
192 munge $pack $(($ofs + 1)) "\177\377" &&
193 test_must_fail git cat-file blob $delta >/dev/null