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