3 test_description
='check broken or malicious patterns in .git* files
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
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 &&
30 test-tool submodule check-name >actual <<-\EOF &&
45 test_cmp expect actual
48 test_expect_success
'check urls' '
49 cat >expect <<-\EOF &&
51 https://example.com/foo.git
52 http://example.com:80/deeper/foo.git
55 test-tool submodule check-url >actual <<-\EOF &&
57 https://example.com/foo.git
58 http://example.com:80/deeper/foo.git
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
71 test_cmp expect actual
74 test_expect_success
'create innocent subrepo' '
76 git -C innocent commit --allow-empty -m foo
79 test_expect_success
'submodule add refuses invalid names' '
81 git submodule add --name ../../modules/evil "$PWD/innocent" evil
84 test_expect_success
'add evil submodule' '
85 git submodule add "$PWD/innocent" evil &&
88 cp -r .git/modules/evil modules &&
89 write_script modules/evil/hooks/post-checkout <<-\EOF &&
90 echo >&2 "RUNNING POST CHECKOUT"
93 git config -f .gitmodules submodule.evil.update checkout &&
94 git config -f .gitmodules --rename-section \
95 submodule.evil submodule.../../modules/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)' '
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)' '
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 &&
145 pack_obj $(git rev-parse HEAD:.gitmodules) &&
146 pack_obj $(git rev-parse HEAD^{tree}) &&
147 pack_obj $(git rev-parse HEAD)
149 pack_trailer odd.pack
152 test_expect_success
'transfer.fsckObjects handles odd pack (unpack)' '
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)' '
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' '
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
190 dir
=symlink-
$name-$type
192 test_expect_success
"set up repo with symlinked $name ($type)" '
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"
210 tree=$(git -C $dir mktree <$dir/bad-tree)
213 test_expect_success
"fsck detects symlinked $name ($type)" '
217 # Check not only that we fail, but that it is due to the
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)" '
228 -c core.protectntfs \
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' '
258 # As above, make the funny tree directly to avoid index
261 cp ../.gitmodules subdir/file &&
262 git add subdir/file &&
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' '
276 echo "[broken" >.gitmodules &&
277 git add .gitmodules &&
278 git commit -m "broken gitmodules" &&
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 &&
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 &&
312 git -c core.protectNTFS=false commit -m "module"
314 if test_have_prereq MINGW
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
'git dirs of sibling submodules must not be nested' '
325 test_commit -C nested nested &&
328 cat >.gitmodules <<-EOF &&
332 [submodule "hippo/hooks"]
336 git clone . thing1 &&
337 git clone . thing2 &&
338 git add .gitmodules thing1 thing2 &&
342 test_must_fail git clone --recurse-submodules nested clone 2>err &&
343 test_grep "is inside git dir" err