Jeff King | 0383bbb | 2018-04-30 03:25:25 -0400 | [diff] [blame] | 1 | #!/bin/sh |
| 2 | |
Jeff King | 43a2220 | 2021-05-01 11:42:08 -0400 | [diff] [blame] | 3 | test_description='check broken or malicious patterns in .git* files |
Jeff King | 0383bbb | 2018-04-30 03:25:25 -0400 | [diff] [blame] | 4 | |
Jeff King | 43a2220 | 2021-05-01 11:42:08 -0400 | [diff] [blame] | 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 |
Jeff King | 0383bbb | 2018-04-30 03:25:25 -0400 | [diff] [blame] | 14 | ' |
Ævar Arnfjörð Bjarmason | c65d18c | 2023-02-07 00:07:54 +0100 | [diff] [blame] | 15 | |
| 16 | TEST_PASSES_SANITIZE_LEAK=true |
Jeff King | 0383bbb | 2018-04-30 03:25:25 -0400 | [diff] [blame] | 17 | . ./test-lib.sh |
Jeff King | 73c3f0f | 2018-05-04 19:45:01 -0400 | [diff] [blame] | 18 | . "$TEST_DIRECTORY"/lib-pack.sh |
Jeff King | 0383bbb | 2018-04-30 03:25:25 -0400 | [diff] [blame] | 19 | |
Taylor Blau | 0d3beb7 | 2022-07-29 15:21:40 -0400 | [diff] [blame] | 20 | test_expect_success 'setup' ' |
| 21 | git config --global protocol.file.allow always |
| 22 | ' |
| 23 | |
Jeff King | 0383bbb | 2018-04-30 03:25:25 -0400 | [diff] [blame] | 24 | test_expect_success 'check names' ' |
| 25 | cat >expect <<-\EOF && |
| 26 | valid |
| 27 | valid/with/paths |
| 28 | EOF |
| 29 | |
Ævar Arnfjörð Bjarmason | 85321a3 | 2022-09-01 01:17:49 +0200 | [diff] [blame] | 30 | test-tool submodule check-name >actual <<-\EOF && |
Jeff King | 0383bbb | 2018-04-30 03:25:25 -0400 | [diff] [blame] | 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 | |
Victoria Dye | 7e2fc39 | 2024-01-18 01:55:17 +0000 | [diff] [blame] | 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 |
Victoria Dye | 8430b43 | 2024-01-18 01:55:18 +0000 | [diff] [blame] | 66 | http://example.com:test/foo.git |
Victoria Dye | 7e2fc39 | 2024-01-18 01:55:17 +0000 | [diff] [blame] | 67 | https::example.com/foo.git |
| 68 | http:::example.com/foo.git |
| 69 | EOF |
| 70 | |
| 71 | test_cmp expect actual |
| 72 | ' |
| 73 | |
Jeff King | 0383bbb | 2018-04-30 03:25:25 -0400 | [diff] [blame] | 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 | |
Jeff King | 1995b5e | 2018-05-02 17:20:35 -0400 | [diff] [blame] | 116 | test_expect_success 'fsck detects evil superproject' ' |
| 117 | test_must_fail git fsck |
| 118 | ' |
| 119 | |
Jeff King | 6e328d6 | 2018-05-04 19:40:08 -0400 | [diff] [blame] | 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 | |
Jeff King | 73c3f0f | 2018-05-04 19:45:01 -0400 | [diff] [blame] | 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 | |
Jeff King | 368b4e5 | 2018-05-31 18:45:31 -0400 | [diff] [blame] | 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 | |
Jeff King | 1cb12f3 | 2021-05-03 16:43:18 -0400 | [diff] [blame] | 174 | check_dotx_symlink () { |
Jeff King | bb6832d | 2021-05-03 16:43:25 -0400 | [diff] [blame] | 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 |
Jeff King | b7b1fca | 2018-05-04 20:03:35 -0400 | [diff] [blame] | 186 | |
Jeff King | 1cb12f3 | 2021-05-03 16:43:18 -0400 | [diff] [blame] | 187 | name=$1 |
| 188 | type=$2 |
| 189 | path=$3 |
| 190 | dir=symlink-$name-$type |
Jeff King | b7b1fca | 2018-05-04 20:03:35 -0400 | [diff] [blame] | 191 | |
Jeff King | 1cb12f3 | 2021-05-03 16:43:18 -0400 | [diff] [blame] | 192 | test_expect_success "set up repo with symlinked $name ($type)" ' |
| 193 | git init $dir && |
| 194 | ( |
| 195 | cd $dir && |
Jeff King | a1ca398 | 2021-05-03 16:43:15 -0400 | [diff] [blame] | 196 | |
Jeff King | 1cb12f3 | 2021-05-03 16:43:18 -0400 | [diff] [blame] | 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 | ' |
Jeff King | b7b1fca | 2018-05-04 20:03:35 -0400 | [diff] [blame] | 212 | |
Jeff King | 1cb12f3 | 2021-05-03 16:43:18 -0400 | [diff] [blame] | 213 | test_expect_success "fsck detects symlinked $name ($type)" ' |
| 214 | ( |
| 215 | cd $dir && |
Jeff King | b7b1fca | 2018-05-04 20:03:35 -0400 | [diff] [blame] | 216 | |
Jeff King | 1cb12f3 | 2021-05-03 16:43:18 -0400 | [diff] [blame] | 217 | # Check not only that we fail, but that it is due to the |
| 218 | # symlink detector |
Jeff King | bb6832d | 2021-05-03 16:43:25 -0400 | [diff] [blame] | 219 | $fsck_must_fail git fsck 2>output && |
| 220 | grep "$fsck_prefix.*tree $tree: ${name}Symlink" output |
Jeff King | 1cb12f3 | 2021-05-03 16:43:18 -0400 | [diff] [blame] | 221 | ) |
| 222 | ' |
| 223 | |
Jeff King | bb6832d | 2021-05-03 16:43:25 -0400 | [diff] [blame] | 224 | test -n "$refuse_index" && |
Jeff King | 1cb12f3 | 2021-05-03 16:43:18 -0400 | [diff] [blame] | 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" |
Jeff King | a1ca398 | 2021-05-03 16:43:15 -0400 | [diff] [blame] | 240 | |
Jeff King | bb6832d | 2021-05-03 16:43:25 -0400 | [diff] [blame] | 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" |
Jeff King | 0383bbb | 2018-04-30 03:25:25 -0400 | [diff] [blame] | 252 | |
Jeff King | 47cc913 | 2018-06-11 04:35:45 -0400 | [diff] [blame] | 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 && |
Junio C Hamano | 6789275 | 2023-10-31 14:23:30 +0900 | [diff] [blame] | 267 | test_grep gitmodulesBlob output |
Jeff King | 47cc913 | 2018-06-11 04:35:45 -0400 | [diff] [blame] | 268 | ) |
| 269 | ' |
| 270 | |
Jeff King | de6bd9e | 2018-06-28 18:06:04 -0400 | [diff] [blame] | 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 | |
Jeff King | 64eb14d | 2018-07-13 15:39:58 -0400 | [diff] [blame] | 280 | git fsck 2>output && |
Junio C Hamano | 6789275 | 2023-10-31 14:23:30 +0900 | [diff] [blame] | 281 | test_grep gitmodulesParse output && |
| 282 | test_grep ! "bad config" output |
Jeff King | de6bd9e | 2018-06-28 18:06:04 -0400 | [diff] [blame] | 283 | ) |
| 284 | ' |
| 285 | |
Adam Dinwoodie | bccc37f | 2021-04-29 21:11:44 +0100 | [diff] [blame] | 286 | test_expect_success WINDOWS 'prevent git~1 squatting on Windows' ' |
Johannes Schindelin | 0060fd1 | 2019-09-12 14:20:39 +0200 | [diff] [blame] | 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)" && |
Johannes Schindelin | 224c7d7 | 2019-12-31 22:53:50 +0000 | [diff] [blame] | 302 | test_must_fail git update-index --add \ |
| 303 | --cacheinfo 160000,$rev,d\\a 2>err && |
Junio C Hamano | 6789275 | 2023-10-31 14:23:30 +0900 | [diff] [blame] | 304 | test_grep "Invalid path" err && |
Johannes Schindelin | e1d911d | 2019-09-12 14:54:05 +0200 | [diff] [blame] | 305 | git -c core.protectNTFS=false update-index --add \ |
Johannes Schindelin | 0060fd1 | 2019-09-12 14:20:39 +0200 | [diff] [blame] | 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 && |
Johannes Schindelin | 224c7d7 | 2019-12-31 22:53:50 +0000 | [diff] [blame] | 312 | git -c core.protectNTFS=false commit -m "module" |
Johannes Schindelin | 0060fd1 | 2019-09-12 14:20:39 +0200 | [diff] [blame] | 313 | ) && |
Adam Dinwoodie | bccc37f | 2021-04-29 21:11:44 +0100 | [diff] [blame] | 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 && |
Junio C Hamano | 6789275 | 2023-10-31 14:23:30 +0900 | [diff] [blame] | 318 | test_grep -e "directory not empty" -e "not an empty directory" err && |
Adam Dinwoodie | bccc37f | 2021-04-29 21:11:44 +0100 | [diff] [blame] | 319 | ! grep gitdir squatting-clone/d/a/git~2 |
| 320 | fi |
Johannes Schindelin | 0060fd1 | 2019-09-12 14:20:39 +0200 | [diff] [blame] | 321 | ' |
| 322 | |
Johannes Schindelin | a8dee3c | 2019-10-01 23:27:18 +0200 | [diff] [blame] | 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 && |
Junio C Hamano | 6789275 | 2023-10-31 14:23:30 +0900 | [diff] [blame] | 343 | test_grep "is inside git dir" err |
Johannes Schindelin | a8dee3c | 2019-10-01 23:27:18 +0200 | [diff] [blame] | 344 | ' |
| 345 | |
Jeff King | 0383bbb | 2018-04-30 03:25:25 -0400 | [diff] [blame] | 346 | test_done |