Mercurial > hg
view tests/test-audit-subrepo.t @ 41456:31286c9282df stable
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.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Tue, 08 Jan 2019 21:51:54 +0900 |
parents | 4441705b7111 |
children | 6c10eba6b9cd |
line wrap: on
line source
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