##// END OF EJS Templates
subrepo: extend path auditing test to include more weird patterns (SEC)...
subrepo: extend path auditing test to include more weird patterns (SEC) While reviewing patches for the issue 5739, "$foo in repository path expanded", I realized that subrepo paths can also be cheated. This patch includes various subrepo paths which are potentially unsafe. Since an expanded subrepo path isn't audited, this bug allows symlink check bypass. As a result, a malicious subrepository could be checked out to a sub tree of e.g. $HOME directory. The good news is that the destination directory must be empty or nonexistent, so the existing ~/.bashrc wouldn't be overwritten. See the last part of the tests for details.

File last commit:

r41549:31286c92 stable
r41549:31286c92 stable
Show More
test-audit-subrepo.t
619 lines | 13.6 KiB | text/troff | Tads3Lexer
/ tests / test-audit-subrepo.t
Test illegal name
-----------------
on commit:
$ hg init hgname
$ cd hgname
$ mkdir sub
$ hg init sub/.hg
$ echo 'sub/.hg = sub/.hg' >> .hgsub
$ hg ci -qAm 'add subrepo "sub/.hg"'
abort: path 'sub/.hg' is inside nested repo 'sub'
[255]
prepare tampered repo (including the commit above):
$ hg import --bypass -qm 'add subrepo "sub/.hg"' - <<'EOF'
> diff --git a/.hgsub b/.hgsub
> new file mode 100644
> --- /dev/null
> +++ b/.hgsub
> @@ -0,0 +1,1 @@
> +sub/.hg = sub/.hg
> diff --git a/.hgsubstate b/.hgsubstate
> new file mode 100644
> --- /dev/null
> +++ b/.hgsubstate
> @@ -0,0 +1,1 @@
> +0000000000000000000000000000000000000000 sub/.hg
> EOF
$ cd ..
on clone (and update):
$ hg clone -q hgname hgname2
abort: path 'sub/.hg' is inside nested repo 'sub'
[255]
Test absolute path
------------------
on commit:
$ hg init absolutepath
$ cd absolutepath
$ hg init sub
$ echo '/sub = sub' >> .hgsub
$ hg ci -qAm 'add subrepo "/sub"'
abort: path contains illegal component: /sub
[255]
prepare tampered repo (including the commit above):
$ hg import --bypass -qm 'add subrepo "/sub"' - <<'EOF'
> diff --git a/.hgsub b/.hgsub
> new file mode 100644
> --- /dev/null
> +++ b/.hgsub
> @@ -0,0 +1,1 @@
> +/sub = sub
> diff --git a/.hgsubstate b/.hgsubstate
> new file mode 100644
> --- /dev/null
> +++ b/.hgsubstate
> @@ -0,0 +1,1 @@
> +0000000000000000000000000000000000000000 /sub
> EOF
$ cd ..
on clone (and update):
$ hg clone -q absolutepath absolutepath2
abort: path contains illegal component: /sub
[255]
Test root path
--------------
on commit:
$ hg init rootpath
$ cd rootpath
$ hg init sub
$ echo '/ = sub' >> .hgsub
$ hg ci -qAm 'add subrepo "/"'
abort: path ends in directory separator: /
[255]
prepare tampered repo (including the commit above):
$ hg import --bypass -qm 'add subrepo "/"' - <<'EOF'
> diff --git a/.hgsub b/.hgsub
> new file mode 100644
> --- /dev/null
> +++ b/.hgsub
> @@ -0,0 +1,1 @@
> +/ = sub
> diff --git a/.hgsubstate b/.hgsubstate
> new file mode 100644
> --- /dev/null
> +++ b/.hgsubstate
> @@ -0,0 +1,1 @@
> +0000000000000000000000000000000000000000 /
> EOF
$ cd ..
on clone (and update):
$ hg clone -q rootpath rootpath2
abort: path ends in directory separator: /
[255]
Test empty path
---------------
on commit:
$ hg init emptypath
$ cd emptypath
$ hg init sub
$ echo '= sub' >> .hgsub
$ hg ci -qAm 'add subrepo ""'
hg: parse error at .hgsub:1: = sub
[255]
prepare tampered repo (including the commit above):
$ hg import --bypass -qm 'add subrepo ""' - <<'EOF'
> diff --git a/.hgsub b/.hgsub
> new file mode 100644
> --- /dev/null
> +++ b/.hgsub
> @@ -0,0 +1,1 @@
> += sub
> diff --git a/.hgsubstate b/.hgsubstate
> new file mode 100644
> --- /dev/null
> +++ b/.hgsubstate
> @@ -0,0 +1,1 @@
> +0000000000000000000000000000000000000000
> EOF
$ cd ..
on clone (and update):
$ hg clone -q emptypath emptypath2
hg: parse error at .hgsub:1: = sub
[255]
Test current path
-----------------
on commit:
BROKEN: should fail
$ hg init currentpath
$ cd currentpath
$ hg init sub
$ echo '. = sub' >> .hgsub
$ hg ci -qAm 'add subrepo "."'
$ cd ..
on clone (and update):
$ hg clone -q currentpath currentpath2 --config ui.timeout=1
waiting for lock on working directory of $TESTTMP/currentpath2/. * (glob)
abort: working directory of $TESTTMP/currentpath2/.: timed out waiting for lock held by '*' (glob)
[255]
Test outer path
---------------
on commit:
$ mkdir outerpath
$ cd outerpath
$ hg init main
$ cd main
$ hg init ../sub
$ echo '../sub = ../sub' >> .hgsub
$ hg ci -qAm 'add subrepo "../sub"'
abort: path contains illegal component: ../sub
[255]
prepare tampered repo (including the commit above):
$ hg import --bypass -qm 'add subrepo "../sub"' - <<'EOF'
> diff --git a/.hgsub b/.hgsub
> new file mode 100644
> --- /dev/null
> +++ b/.hgsub
> @@ -0,0 +1,1 @@
> +../sub = ../sub
> diff --git a/.hgsubstate b/.hgsubstate
> new file mode 100644
> --- /dev/null
> +++ b/.hgsubstate
> @@ -0,0 +1,1 @@
> +0000000000000000000000000000000000000000 ../sub
> EOF
$ cd ..
on clone (and update):
$ hg clone -q main main2
abort: path contains illegal component: ../sub
[255]
$ cd ..
Test variable expansion
-----------------------
Subrepository paths shouldn't be expanded, but we fail to handle them
properly. Any local repository paths are expanded.
on commit:
BROKEN: wrong error message
$ mkdir envvar
$ cd envvar
$ hg init main
$ cd main
$ hg init sub1
$ cat <<'EOF' > sub1/hgrc
> [hooks]
> log = echo pwned
> EOF
$ hg -R sub1 ci -qAm 'add sub1 files'
$ hg -R sub1 log -r. -T '{node}\n'
39eb4b4d3e096527668784893a9280578a8f38b8
$ echo '$SUB = sub1' >> .hgsub
$ SUB=sub1 hg ci -qAm 'add subrepo "$SUB"'
abort: repository $TESTTMP/envvar/main/$SUB already exists!
[255]
prepare tampered repo (including the changes above as two commits):
$ hg import --bypass -qm 'add subrepo "$SUB"' - <<'EOF'
> diff --git a/.hgsub b/.hgsub
> new file mode 100644
> --- /dev/null
> +++ b/.hgsub
> @@ -0,0 +1,1 @@
> +$SUB = sub1
> diff --git a/.hgsubstate b/.hgsubstate
> new file mode 100644
> --- /dev/null
> +++ b/.hgsubstate
> @@ -0,0 +1,1 @@
> +0000000000000000000000000000000000000000 $SUB
> EOF
$ hg debugsetparents 0
$ hg import --bypass -qm 'update subrepo "$SUB"' - <<'EOF'
> diff --git a/.hgsubstate b/.hgsubstate
> --- a/.hgsubstate
> +++ b/.hgsubstate
> @@ -1,1 +1,1 @@
> -0000000000000000000000000000000000000000 $SUB
> +39eb4b4d3e096527668784893a9280578a8f38b8 $SUB
> EOF
$ cd ..
on clone (and update) with various substitutions:
$ hg clone -q main main2
$ ls main2
$SUB
$ SUB=sub1 hg clone -q main main3
$ ls main3
sub1
$ SUB=sub2 hg clone -q main main4
$ ls main4
sub2
on clone empty subrepo into .hg, then pull (and update), which at least fails:
BROKEN: the first clone should fail
$ SUB=.hg hg clone -qr0 main main5
$ ls main5
$ ls -d main5/.hg/.hg
main5/.hg/.hg
$ SUB=.hg hg -R main5 pull -u
pulling from $TESTTMP/envvar/main
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
new changesets 7a2f0e59146f
abort: repository $TESTTMP/envvar/main5/$SUB already exists!
[255]
$ cat main5/.hg/hgrc | grep pwned
[1]
on clone (and update) into .hg, which at least fails:
$ SUB=.hg hg clone -q main main6
abort: destination '$TESTTMP/envvar/main6/.hg' is not empty (in subrepository ".hg")
[255]
$ ls main6
$ cat main6/.hg/hgrc | grep pwned
[1]
on clone (and update) into .hg/* subdir:
BROKEN: should fail
$ SUB=.hg/foo hg clone -q main main7
$ ls main7
$ ls main7/.hg/foo
hgrc
on clone (and update) into outer tree:
BROKEN: should fail
$ SUB=../out-of-tree-write hg clone -q main main8
$ ls main8
on clone (and update) into e.g. $HOME, which doesn't work since subrepo paths
are concatenated prior to variable expansion:
$ SUB="$TESTTMP/envvar/fakehome" hg clone -q main main9
$ ls main9 | wc -l
\s*1 (re)
$ ls
main
main2
main3
main4
main5
main6
main7
main8
main9
out-of-tree-write
$ cd ..
Test tilde
----------
The leading tilde may be expanded to $HOME, but it's a valid subrepo path.
However, we might want to prohibit it as it seems potentially unsafe.
on commit:
$ hg init tilde
$ cd tilde
$ hg init './~'
$ echo '~ = ~' >> .hgsub
$ hg ci -qAm 'add subrepo "~"'
$ ls
~
$ cd ..
on clone (and update):
$ hg clone -q tilde tilde2
$ ls tilde2
~
Test direct symlink traversal
-----------------------------
#if symlink
on commit:
$ mkdir hgsymdir
$ hg init hgsymdir/root
$ cd hgsymdir/root
$ ln -s ../out
$ hg ci -qAm 'add symlink "out"'
$ hg init ../out
$ echo 'out = out' >> .hgsub
$ hg ci -qAm 'add subrepo "out"'
abort: subrepo 'out' traverses symbolic link
[255]
prepare tampered repo (including the commit above):
$ hg import --bypass -qm 'add subrepo "out"' - <<'EOF'
> diff --git a/.hgsub b/.hgsub
> new file mode 100644
> --- /dev/null
> +++ b/.hgsub
> @@ -0,0 +1,1 @@
> +out = out
> diff --git a/.hgsubstate b/.hgsubstate
> new file mode 100644
> --- /dev/null
> +++ b/.hgsubstate
> @@ -0,0 +1,1 @@
> +0000000000000000000000000000000000000000 out
> EOF
$ cd ../..
on clone (and update):
$ mkdir hgsymdir2
$ hg clone -q hgsymdir/root hgsymdir2/root
abort: subrepo 'out' traverses symbolic link
[255]
$ ls hgsymdir2
root
#endif
Test indirect symlink traversal
-------------------------------
#if symlink
on commit:
$ mkdir hgsymin
$ hg init hgsymin/root
$ cd hgsymin/root
$ ln -s ../out
$ hg ci -qAm 'add symlink "out"'
$ mkdir ../out
$ hg init ../out/sub
$ echo 'out/sub = out/sub' >> .hgsub
$ hg ci -qAm 'add subrepo "out/sub"'
abort: path 'out/sub' traverses symbolic link 'out'
[255]
prepare tampered repo (including the commit above):
$ hg import --bypass -qm 'add subrepo "out/sub"' - <<'EOF'
> diff --git a/.hgsub b/.hgsub
> new file mode 100644
> --- /dev/null
> +++ b/.hgsub
> @@ -0,0 +1,1 @@
> +out/sub = out/sub
> diff --git a/.hgsubstate b/.hgsubstate
> new file mode 100644
> --- /dev/null
> +++ b/.hgsubstate
> @@ -0,0 +1,1 @@
> +0000000000000000000000000000000000000000 out/sub
> EOF
$ cd ../..
on clone (and update):
$ mkdir hgsymin2
$ hg clone -q hgsymin/root hgsymin2/root
abort: path 'out/sub' traverses symbolic link 'out'
[255]
$ ls hgsymin2
root
#endif
Test symlink traversal by variable expansion
--------------------------------------------
#if symlink
$ FAKEHOME="$TESTTMP/envvarsym/fakehome"
on commit:
BROKEN: wrong error message
$ mkdir envvarsym
$ cd envvarsym
$ hg init main
$ cd main
$ ln -s "`echo "$FAKEHOME" | sed 's|\(.\)/.*|\1|'`"
$ hg ci -qAm 'add symlink to top-level system directory'
$ hg init sub1
$ echo pwned > sub1/pwned
$ hg -R sub1 ci -qAm 'add sub1 files'
$ hg -R sub1 log -r. -T '{node}\n'
f40c9134ba1b6961e12f250868823f0092fb68a8
$ echo '$SUB = sub1' >> .hgsub
$ SUB="$FAKEHOME" hg ci -qAm 'add subrepo "$SUB"'
abort: repository $TESTTMP/envvarsym/main/$SUB already exists!
[255]
prepare tampered repo (including the changes above as two commits):
$ hg import --bypass -qm 'add subrepo "$SUB"' - <<'EOF'
> diff --git a/.hgsub b/.hgsub
> new file mode 100644
> --- /dev/null
> +++ b/.hgsub
> @@ -0,0 +1,1 @@
> +$SUB = sub1
> diff --git a/.hgsubstate b/.hgsubstate
> new file mode 100644
> --- /dev/null
> +++ b/.hgsubstate
> @@ -0,0 +1,1 @@
> +0000000000000000000000000000000000000000 $SUB
> EOF
$ hg debugsetparents 1
$ hg import --bypass -qm 'update subrepo "$SUB"' - <<'EOF'
> diff --git a/.hgsubstate b/.hgsubstate
> --- a/.hgsubstate
> +++ b/.hgsubstate
> @@ -1,1 +1,1 @@
> -0000000000000000000000000000000000000000 $SUB
> +f40c9134ba1b6961e12f250868823f0092fb68a8 $SUB
> EOF
$ cd ..
on clone (and update) without fakehome directory:
BROKEN: should fail
$ rm -fR "$FAKEHOME"
$ SUB="$FAKEHOME" hg clone -q main main2
$ ls "$FAKEHOME"
pwned
on clone (and update) with empty fakehome directory:
BROKEN: should fail
$ rm -fR "$FAKEHOME"
$ mkdir "$FAKEHOME"
$ SUB="$FAKEHOME" hg clone -q main main3
$ ls "$FAKEHOME"
pwned
on clone (and update) with non-empty fakehome directory:
BROKEN: wrong error message
$ rm -fR "$FAKEHOME"
$ mkdir "$FAKEHOME"
$ touch "$FAKEHOME/a"
$ SUB="$FAKEHOME" hg clone -q main main4
abort: destination '$TESTTMP/envvarsym/fakehome' is not empty (in subrepository "*") (glob)
[255]
$ ls "$FAKEHOME"
a
on clone empty subrepo with non-empty fakehome directory,
then pull (and update):
BROKEN: the first clone should fail
$ rm -fR "$FAKEHOME"
$ mkdir "$FAKEHOME"
$ touch "$FAKEHOME/a"
$ SUB="$FAKEHOME" hg clone -qr1 main main5
$ ls "$FAKEHOME"
a
$ ls -d "$FAKEHOME/.hg"
$TESTTMP/envvarsym/fakehome/.hg
$ SUB="$FAKEHOME" hg -R main5 pull -u
pulling from $TESTTMP/envvarsym/main
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
new changesets * (glob)
abort: repository $TESTTMP/envvarsym/main5/$SUB already exists!
[255]
$ ls "$FAKEHOME"
a
on clone empty subrepo with hg-managed fakehome directory,
then pull (and update):
BROKEN: wrong error message
$ rm -fR "$FAKEHOME"
$ hg init "$FAKEHOME"
$ touch "$FAKEHOME/a"
$ hg -R "$FAKEHOME" ci -qAm 'add fakehome file'
$ SUB="$FAKEHOME" hg clone -qr1 main main6
abort: repository $TESTTMP/envvarsym/main6/$SUB already exists!
[255]
$ ls "$FAKEHOME"
a
$ SUB="$FAKEHOME" hg -R main6 pull -u
pulling from $TESTTMP/envvarsym/main
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
new changesets * (glob)
.hgsubstate: untracked file differs
abort: untracked files in working directory differ from files in requested revision
[255]
$ ls "$FAKEHOME"
a
on clone only symlink with hg-managed fakehome directory,
then pull (and update):
BROKEN: wrong error message
$ rm -fR "$FAKEHOME"
$ hg init "$FAKEHOME"
$ touch "$FAKEHOME/a"
$ hg -R "$FAKEHOME" ci -qAm 'add fakehome file'
$ SUB="$FAKEHOME" hg clone -qr0 main main7
$ ls "$FAKEHOME"
a
$ SUB="$FAKEHOME" hg -R main7 pull -uf
pulling from $TESTTMP/envvarsym/main
searching for changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 3 changes to 2 files
new changesets * (glob)
abort: repository $TESTTMP/envvarsym/main7/$SUB already exists!
[255]
$ ls "$FAKEHOME"
a
$ cd ..
#endif