Merge branch 'cl/config-regexp-docfix' into maint-2.46
[git/gitster.git] / t / t7450-bad-git-dotfiles.sh
blob4a9c22c9e2b627dbb666a9b52052aea215869297
1 #!/bin/sh
3 test_description='check broken or malicious patterns in .git* files
5 Such as:
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.
11 - nested submodule names
13 - symlinked .gitmodules, etc
16 TEST_PASSES_SANITIZE_LEAK=true
17 . ./test-lib.sh
18 . "$TEST_DIRECTORY"/lib-pack.sh
20 test_expect_success 'setup' '
21 git config --global protocol.file.allow always
24 test_expect_success 'check names' '
25 cat >expect <<-\EOF &&
26 valid
27 valid/with/paths
28 EOF
30 test-tool submodule check-name >actual <<-\EOF &&
31 valid
32 valid/with/paths
34 ../foo
35 /../foo
36 ..\foo
37 \..\foo
38 foo/..
39 foo/../
40 foo\..
41 foo\..\
42 foo/../bar
43 EOF
45 test_cmp expect actual
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
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
71 test_cmp expect actual
74 test_expect_success 'create innocent subrepo' '
75 git init innocent &&
76 git -C innocent commit --allow-empty -m foo
79 test_expect_success 'submodule add refuses invalid names' '
80 test_must_fail \
81 git submodule add --name ../../modules/evil "$PWD/innocent" evil
84 test_expect_success 'add evil submodule' '
85 git submodule add "$PWD/innocent" evil &&
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
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
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
111 test_expect_success 'clone evil superproject' '
112 git clone --recurse-submodules . victim >output 2>&1 &&
113 ! grep "RUNNING POST CHECKOUT" output
116 test_expect_success 'fsck detects evil superproject' '
117 test_must_fail git fsck
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
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
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 &&
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
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
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
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
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
185 esac
187 name=$1
188 type=$2
189 path=$3
190 dir=symlink-$name-$type
192 test_expect_success "set up repo with symlinked $name ($type)" '
193 git init $dir &&
195 cd $dir &&
197 # Make the tree directly to avoid index restrictions.
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) &&
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)
213 test_expect_success "fsck detects symlinked $name ($type)" '
215 cd $dir &&
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
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
237 check_dotx_symlink gitmodules vanilla .gitmodules
238 check_dotx_symlink gitmodules ntfs ".gitmodules ."
239 check_dotx_symlink gitmodules hfs ".${u200c}gitmodules"
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"
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"
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"
253 test_expect_success 'fsck detects non-blob .gitmodules' '
254 git init non-blob &&
256 cd non-blob &&
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 &&
266 test_must_fail git fsck 2>output &&
267 test_grep gitmodulesBlob output
271 test_expect_success 'fsck detects corrupt .gitmodules' '
272 git init corrupt &&
274 cd corrupt &&
276 echo "[broken" >.gitmodules &&
277 git add .gitmodules &&
278 git commit -m "broken gitmodules" &&
280 git fsck 2>output &&
281 test_grep gitmodulesParse output &&
282 test_grep ! "bad config" output
286 test_expect_success WINDOWS 'prevent git~1 squatting on Windows' '
287 git init squatting &&
289 cd squatting &&
290 mkdir a &&
291 touch a/..git &&
292 git add a/..git &&
293 test_tick &&
294 git commit -m initial &&
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
323 test_expect_success 'setup submodules with nested git dirs' '
324 git init nested &&
325 test_commit -C nested nested &&
327 cd nested &&
328 cat >.gitmodules <<-EOF &&
329 [submodule "hippo"]
330 url = .
331 path = thing1
332 [submodule "hippo/hooks"]
333 url = .
334 path = thing2
336 git clone . thing1 &&
337 git clone . thing2 &&
338 git add .gitmodules thing1 thing2 &&
339 test_tick &&
340 git commit -m nested
344 test_expect_success 'git dirs of sibling submodules must not be nested' '
345 test_must_fail git clone --recurse-submodules nested clone 2>err &&
346 test_grep "is inside git dir" err
349 test_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 &&
354 test_path_is_missing .git/modules/hippo/HEAD ||
355 test_path_is_missing .git/modules/hippo/hooks/HEAD
359 test_expect_success 'checkout -f --recurse-submodules must not use a nested gitdir' '
360 git clone nested nested_checkout &&
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
376 test_done