]> git.ipfire.org Git - thirdparty/git.git/blame - t/t7450-bad-git-dotfiles.sh
Sync with Git 2.45.1
[thirdparty/git.git] / t / t7450-bad-git-dotfiles.sh
CommitLineData
0383bbb9
JK
1#!/bin/sh
2
43a2220f 3test_description='check broken or malicious patterns in .git* files
0383bbb9 4
43a2220f
JK
5Such 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
0383bbb9 14'
c65d18cb
ÆAB
15
16TEST_PASSES_SANITIZE_LEAK=true
0383bbb9 17. ./test-lib.sh
73c3f0f7 18. "$TEST_DIRECTORY"/lib-pack.sh
0383bbb9 19
0d3beb71
TB
20test_expect_success 'setup' '
21 git config --global protocol.file.allow always
22'
23
0383bbb9
JK
24test_expect_success 'check names' '
25 cat >expect <<-\EOF &&
26 valid
27 valid/with/paths
28 EOF
29
85321a34 30 test-tool submodule check-name >actual <<-\EOF &&
0383bbb9
JK
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
7e2fc39d
VD
48test_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
8430b438 66 http://example.com:test/foo.git
7e2fc39d
VD
67 https::example.com/foo.git
68 http:::example.com/foo.git
69 EOF
70
71 test_cmp expect actual
72'
73
0383bbb9
JK
74test_expect_success 'create innocent subrepo' '
75 git init innocent &&
76 git -C innocent commit --allow-empty -m foo
77'
78
79test_expect_success 'submodule add refuses invalid names' '
80 test_must_fail \
81 git submodule add --name ../../modules/evil "$PWD/innocent" evil
82'
83
84test_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.
105test_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
111test_expect_success 'clone evil superproject' '
112 git clone --recurse-submodules . victim >output 2>&1 &&
113 ! grep "RUNNING POST CHECKOUT" output
114'
115
1995b5e0
JK
116test_expect_success 'fsck detects evil superproject' '
117 test_must_fail git fsck
118'
119
6e328d6c
JK
120test_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
73c3f0f7
JK
127test_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.
138test_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
152test_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
158test_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
368b4e59
JK
164test_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
1cb12f33 174check_dotx_symlink () {
bb6832d5
JK
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
1cb12f33
JK
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
bb6832d5
JK
219 $fsck_must_fail git fsck 2>output &&
220 grep "$fsck_prefix.*tree $tree: ${name}Symlink" output
1cb12f33
JK
221 )
222 '
223
bb6832d5 224 test -n "$refuse_index" &&
1cb12f33
JK
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
237check_dotx_symlink gitmodules vanilla .gitmodules
238check_dotx_symlink gitmodules ntfs ".gitmodules ."
239check_dotx_symlink gitmodules hfs ".${u200c}gitmodules"
a1ca398b 240
bb6832d5
JK
241check_dotx_symlink --warning gitattributes vanilla .gitattributes
242check_dotx_symlink --warning gitattributes ntfs ".gitattributes ."
243check_dotx_symlink --warning gitattributes hfs ".${u200c}gitattributes"
244
245check_dotx_symlink --warning gitignore vanilla .gitignore
246check_dotx_symlink --warning gitignore ntfs ".gitignore ."
247check_dotx_symlink --warning gitignore hfs ".${u200c}gitignore"
248
249check_dotx_symlink --warning mailmap vanilla .mailmap
250check_dotx_symlink --warning mailmap ntfs ".mailmap ."
251check_dotx_symlink --warning mailmap hfs ".${u200c}mailmap"
b7b1fca1 252
47cc9131
JK
253test_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 &&
6789275d 267 test_grep gitmodulesBlob output
47cc9131
JK
268 )
269'
270
de6bd9e3
JK
271test_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
64eb14d3 280 git fsck 2>output &&
6789275d
JH
281 test_grep gitmodulesParse output &&
282 test_grep ! "bad config" output
de6bd9e3
JK
283 )
284'
285
bccc37fd 286test_expect_success WINDOWS 'prevent git~1 squatting on Windows' '
0060fd15
JS
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)" &&
224c7d70
JS
302 test_must_fail git update-index --add \
303 --cacheinfo 160000,$rev,d\\a 2>err &&
6789275d 304 test_grep "Invalid path" err &&
e1d911dd 305 git -c core.protectNTFS=false update-index --add \
0060fd15
JS
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 &&
224c7d70 312 git -c core.protectNTFS=false commit -m "module"
0060fd15 313 ) &&
bccc37fd
AD
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 &&
6789275d 318 test_grep -e "directory not empty" -e "not an empty directory" err &&
bccc37fd
AD
319 ! grep gitdir squatting-clone/d/a/git~2
320 fi
0060fd15
JS
321'
322
9cf85473 323test_expect_success 'setup submodules with nested git dirs' '
a8dee3ca
JS
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
9cf85473
FH
341 )
342'
343
344test_expect_success 'git dirs of sibling submodules must not be nested' '
a8dee3ca 345 test_must_fail git clone --recurse-submodules nested clone 2>err &&
6789275d 346 test_grep "is inside git dir" err
a8dee3ca
JS
347'
348
9cf85473
FH
349test_expect_success 'submodule git dir nesting detection must work with parallel cloning' '
350 test_must_fail git clone --recurse-submodules --jobs=2 nested clone_parallel 2>err &&
351 cat err &&
352 grep -E "(already exists|is inside git dir|not a git repository)" err &&
353 {
354 test_path_is_missing .git/modules/hippo/HEAD ||
355 test_path_is_missing .git/modules/hippo/hooks/HEAD
356 }
357'
358
359test_expect_success 'checkout -f --recurse-submodules must not use a nested gitdir' '
360 git clone nested nested_checkout &&
361 (
362 cd nested_checkout &&
363 git submodule init &&
364 git submodule update thing1 &&
365 mkdir -p .git/modules/hippo/hooks/refs &&
366 mkdir -p .git/modules/hippo/hooks/objects/info &&
367 echo "../../../../objects" >.git/modules/hippo/hooks/objects/info/alternates &&
368 echo "ref: refs/heads/master" >.git/modules/hippo/hooks/HEAD
369 ) &&
370 test_must_fail git -C nested_checkout checkout -f --recurse-submodules HEAD 2>err &&
371 cat err &&
372 grep "is inside git dir" err &&
373 test_path_is_missing nested_checkout/thing2/.git
374'
375
0383bbb9 376test_done