]> git.ipfire.org Git - thirdparty/git.git/blob - t/t7450-bad-git-dotfiles.sh
The third batch
[thirdparty/git.git] / t / t7450-bad-git-dotfiles.sh
1 #!/bin/sh
2
3 test_description='check broken or malicious patterns in .git* files
4
5 Such as:
6
7 - presence of .. in submodule names;
8 Exercise the name-checking function on a variety of names, and then give a
9 real-world setup that confirms we catch this in practice.
10
11 - nested submodule names
12
13 - symlinked .gitmodules, etc
14 '
15
16 TEST_PASSES_SANITIZE_LEAK=true
17 . ./test-lib.sh
18 . "$TEST_DIRECTORY"/lib-pack.sh
19
20 test_expect_success 'setup' '
21 git config --global protocol.file.allow always
22 '
23
24 test_expect_success 'check names' '
25 cat >expect <<-\EOF &&
26 valid
27 valid/with/paths
28 EOF
29
30 test-tool submodule check-name >actual <<-\EOF &&
31 valid
32 valid/with/paths
33
34 ../foo
35 /../foo
36 ..\foo
37 \..\foo
38 foo/..
39 foo/../
40 foo\..
41 foo\..\
42 foo/../bar
43 EOF
44
45 test_cmp expect actual
46 '
47
48 test_expect_success 'check urls' '
49 cat >expect <<-\EOF &&
50 ./bar/baz/foo.git
51 https://example.com/foo.git
52 http://example.com:80/deeper/foo.git
53 EOF
54
55 test-tool submodule check-url >actual <<-\EOF &&
56 ./bar/baz/foo.git
57 https://example.com/foo.git
58 http://example.com:80/deeper/foo.git
59 -a./foo
60 ../../..//test/foo.git
61 ../../../../../:localhost:8080/foo.git
62 ..\../.\../:example.com/foo.git
63 ./%0ahost=example.com/foo.git
64 https://one.example.com/evil?%0ahost=two.example.com
65 https:///example.com/foo.git
66 http://example.com:test/foo.git
67 https::example.com/foo.git
68 http:::example.com/foo.git
69 EOF
70
71 test_cmp expect actual
72 '
73
74 test_expect_success 'create innocent subrepo' '
75 git init innocent &&
76 git -C innocent commit --allow-empty -m foo
77 '
78
79 test_expect_success 'submodule add refuses invalid names' '
80 test_must_fail \
81 git submodule add --name ../../modules/evil "$PWD/innocent" evil
82 '
83
84 test_expect_success 'add evil submodule' '
85 git submodule add "$PWD/innocent" evil &&
86
87 mkdir modules &&
88 cp -r .git/modules/evil modules &&
89 write_script modules/evil/hooks/post-checkout <<-\EOF &&
90 echo >&2 "RUNNING POST CHECKOUT"
91 EOF
92
93 git config -f .gitmodules submodule.evil.update checkout &&
94 git config -f .gitmodules --rename-section \
95 submodule.evil submodule.../../modules/evil &&
96 git add modules &&
97 git commit -am evil
98 '
99
100 # This step seems like it shouldn't be necessary, since the payload is
101 # contained entirely in the evil submodule. But due to the vagaries of the
102 # submodule code, checking out the evil module will fail unless ".git/modules"
103 # exists. Adding another submodule (with a name that sorts before "evil") is an
104 # easy way to make sure this is the case in the victim clone.
105 test_expect_success 'add other submodule' '
106 git submodule add "$PWD/innocent" another-module &&
107 git add another-module &&
108 git commit -am another
109 '
110
111 test_expect_success 'clone evil superproject' '
112 git clone --recurse-submodules . victim >output 2>&1 &&
113 ! grep "RUNNING POST CHECKOUT" output
114 '
115
116 test_expect_success 'fsck detects evil superproject' '
117 test_must_fail git fsck
118 '
119
120 test_expect_success 'transfer.fsckObjects detects evil superproject (unpack)' '
121 rm -rf dst.git &&
122 git init --bare dst.git &&
123 git -C dst.git config transfer.fsckObjects true &&
124 test_must_fail git push dst.git HEAD
125 '
126
127 test_expect_success 'transfer.fsckObjects detects evil superproject (index)' '
128 rm -rf dst.git &&
129 git init --bare dst.git &&
130 git -C dst.git config transfer.fsckObjects true &&
131 git -C dst.git config transfer.unpackLimit 1 &&
132 test_must_fail git push dst.git HEAD
133 '
134
135 # Normally our packs contain commits followed by trees followed by blobs. This
136 # reverses the order, which requires backtracking to find the context of a
137 # blob. We'll start with a fresh gitmodules-only tree to make it simpler.
138 test_expect_success 'create oddly ordered pack' '
139 git checkout --orphan odd &&
140 git rm -rf --cached . &&
141 git add .gitmodules &&
142 git commit -m odd &&
143 {
144 pack_header 3 &&
145 pack_obj $(git rev-parse HEAD:.gitmodules) &&
146 pack_obj $(git rev-parse HEAD^{tree}) &&
147 pack_obj $(git rev-parse HEAD)
148 } >odd.pack &&
149 pack_trailer odd.pack
150 '
151
152 test_expect_success 'transfer.fsckObjects handles odd pack (unpack)' '
153 rm -rf dst.git &&
154 git init --bare dst.git &&
155 test_must_fail git -C dst.git unpack-objects --strict <odd.pack
156 '
157
158 test_expect_success 'transfer.fsckObjects handles odd pack (index)' '
159 rm -rf dst.git &&
160 git init --bare dst.git &&
161 test_must_fail git -C dst.git index-pack --strict --stdin <odd.pack
162 '
163
164 test_expect_success 'index-pack --strict works for non-repo pack' '
165 rm -rf dst.git &&
166 git init --bare dst.git &&
167 cp odd.pack dst.git &&
168 test_must_fail git -C dst.git index-pack --strict odd.pack 2>output &&
169 # Make sure we fail due to bad gitmodules content, not because we
170 # could not read the blob in the first place.
171 grep gitmodulesName output
172 '
173
174 check_dotx_symlink () {
175 fsck_must_fail=test_must_fail
176 fsck_prefix=error
177 refuse_index=t
178 case "$1" in
179 --warning)
180 fsck_must_fail=
181 fsck_prefix=warning
182 refuse_index=
183 shift
184 ;;
185 esac
186
187 name=$1
188 type=$2
189 path=$3
190 dir=symlink-$name-$type
191
192 test_expect_success "set up repo with symlinked $name ($type)" '
193 git init $dir &&
194 (
195 cd $dir &&
196
197 # Make the tree directly to avoid index restrictions.
198 #
199 # Because symlinks store the target as a blob, choose
200 # a pathname that could be parsed as a .gitmodules file
201 # to trick naive non-symlink-aware checking.
202 tricky="[foo]bar=true" &&
203 content=$(git hash-object -w ../.gitmodules) &&
204 target=$(printf "$tricky" | git hash-object -w --stdin) &&
205 {
206 printf "100644 blob $content\t$tricky\n" &&
207 printf "120000 blob $target\t$path\n"
208 } >bad-tree
209 ) &&
210 tree=$(git -C $dir mktree <$dir/bad-tree)
211 '
212
213 test_expect_success "fsck detects symlinked $name ($type)" '
214 (
215 cd $dir &&
216
217 # Check not only that we fail, but that it is due to the
218 # symlink detector
219 $fsck_must_fail git fsck 2>output &&
220 grep "$fsck_prefix.*tree $tree: ${name}Symlink" output
221 )
222 '
223
224 test -n "$refuse_index" &&
225 test_expect_success "refuse to load symlinked $name into index ($type)" '
226 test_must_fail \
227 git -C $dir \
228 -c core.protectntfs \
229 -c core.protecthfs \
230 read-tree $tree 2>err &&
231 grep "invalid path.*$name" err &&
232 git -C $dir ls-files -s >out &&
233 test_must_be_empty out
234 '
235 }
236
237 check_dotx_symlink gitmodules vanilla .gitmodules
238 check_dotx_symlink gitmodules ntfs ".gitmodules ."
239 check_dotx_symlink gitmodules hfs ".${u200c}gitmodules"
240
241 check_dotx_symlink --warning gitattributes vanilla .gitattributes
242 check_dotx_symlink --warning gitattributes ntfs ".gitattributes ."
243 check_dotx_symlink --warning gitattributes hfs ".${u200c}gitattributes"
244
245 check_dotx_symlink --warning gitignore vanilla .gitignore
246 check_dotx_symlink --warning gitignore ntfs ".gitignore ."
247 check_dotx_symlink --warning gitignore hfs ".${u200c}gitignore"
248
249 check_dotx_symlink --warning mailmap vanilla .mailmap
250 check_dotx_symlink --warning mailmap ntfs ".mailmap ."
251 check_dotx_symlink --warning mailmap hfs ".${u200c}mailmap"
252
253 test_expect_success 'fsck detects non-blob .gitmodules' '
254 git init non-blob &&
255 (
256 cd non-blob &&
257
258 # As above, make the funny tree directly to avoid index
259 # restrictions.
260 mkdir subdir &&
261 cp ../.gitmodules subdir/file &&
262 git add subdir/file &&
263 git commit -m ok &&
264 git ls-tree HEAD | sed s/subdir/.gitmodules/ | git mktree &&
265
266 test_must_fail git fsck 2>output &&
267 test_grep gitmodulesBlob output
268 )
269 '
270
271 test_expect_success 'fsck detects corrupt .gitmodules' '
272 git init corrupt &&
273 (
274 cd corrupt &&
275
276 echo "[broken" >.gitmodules &&
277 git add .gitmodules &&
278 git commit -m "broken gitmodules" &&
279
280 git fsck 2>output &&
281 test_grep gitmodulesParse output &&
282 test_grep ! "bad config" output
283 )
284 '
285
286 test_expect_success WINDOWS 'prevent git~1 squatting on Windows' '
287 git init squatting &&
288 (
289 cd squatting &&
290 mkdir a &&
291 touch a/..git &&
292 git add a/..git &&
293 test_tick &&
294 git commit -m initial &&
295
296 modules="$(test_write_lines \
297 "[submodule \"b.\"]" "url = ." "path = c" \
298 "[submodule \"b\"]" "url = ." "path = d\\\\a" |
299 git hash-object -w --stdin)" &&
300 rev="$(git rev-parse --verify HEAD)" &&
301 hash="$(echo x | git hash-object -w --stdin)" &&
302 test_must_fail git update-index --add \
303 --cacheinfo 160000,$rev,d\\a 2>err &&
304 test_grep "Invalid path" err &&
305 git -c core.protectNTFS=false update-index --add \
306 --cacheinfo 100644,$modules,.gitmodules \
307 --cacheinfo 160000,$rev,c \
308 --cacheinfo 160000,$rev,d\\a \
309 --cacheinfo 100644,$hash,d./a/x \
310 --cacheinfo 100644,$hash,d./a/..git &&
311 test_tick &&
312 git -c core.protectNTFS=false commit -m "module"
313 ) &&
314 if test_have_prereq MINGW
315 then
316 test_must_fail git -c core.protectNTFS=false \
317 clone --recurse-submodules squatting squatting-clone 2>err &&
318 test_grep -e "directory not empty" -e "not an empty directory" err &&
319 ! grep gitdir squatting-clone/d/a/git~2
320 fi
321 '
322
323 test_expect_success 'git dirs of sibling submodules must not be nested' '
324 git init nested &&
325 test_commit -C nested nested &&
326 (
327 cd nested &&
328 cat >.gitmodules <<-EOF &&
329 [submodule "hippo"]
330 url = .
331 path = thing1
332 [submodule "hippo/hooks"]
333 url = .
334 path = thing2
335 EOF
336 git clone . thing1 &&
337 git clone . thing2 &&
338 git add .gitmodules thing1 thing2 &&
339 test_tick &&
340 git commit -m nested
341 ) &&
342 test_must_fail git clone --recurse-submodules nested clone 2>err &&
343 test_grep "is inside git dir" err
344 '
345
346 test_done