changeset 34984:071cbeba4212 stable

subrepo: disallow symlink traversal across subrepo mount point (SEC) It wasn't easy to extend the pathauditor to check symlink traversal across subrepos because pathauditor._checkfs() rejects a directory having ".hg" directory. That's why I added the explicit islink() check. No idea if this patch is necessary after we've fixed the issue5730 by splitting submerge() into planning and execution phases.
author Yuya Nishihara <yuya@tcha.org>
date Fri, 03 Nov 2017 20:12:50 +0900
parents 80d7dbda9294
children 5e27afeddaee
files mercurial/subrepo.py tests/test-audit-subrepo.t tests/test-subrepo-git.t
diffstat 3 files changed, 33 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/subrepo.py	Fri Nov 03 19:17:25 2017 +0900
+++ b/mercurial/subrepo.py	Fri Nov 03 20:12:50 2017 +0900
@@ -359,6 +359,12 @@
                           "in '%s'\n") % vfs.join(dirname))
                 vfs.unlink(vfs.reljoin(dirname, f))
 
+def _auditsubrepopath(repo, path):
+    # auditor doesn't check if the path itself is a symlink
+    pathutil.pathauditor(repo.root)(path)
+    if repo.wvfs.islink(path):
+        raise error.Abort(_("subrepo '%s' traverses symbolic link") % path)
+
 def subrepo(ctx, path, allowwdir=False, allowcreate=True):
     """return instance of the right subrepo class for subrepo in path"""
     # subrepo inherently violates our import layering rules
@@ -369,7 +375,7 @@
     from . import hg as h
     hg = h
 
-    pathutil.pathauditor(ctx.repo().root)(path)
+    _auditsubrepopath(ctx.repo(), path)
     state = ctx.substate[path]
     if state[2] not in types:
         raise error.Abort(_('unknown subrepo type %s') % state[2])
@@ -387,7 +393,7 @@
     from . import hg as h
     hg = h
 
-    pathutil.pathauditor(ctx.repo().root)(path)
+    _auditsubrepopath(ctx.repo(), path)
     state = ctx.substate[path]
     if state[2] not in types:
         raise error.Abort(_('unknown subrepo type %s') % state[2])
--- a/tests/test-audit-subrepo.t	Fri Nov 03 19:17:25 2017 +0900
+++ b/tests/test-audit-subrepo.t	Fri Nov 03 20:12:50 2017 +0900
@@ -50,17 +50,35 @@
   $ hg ci -qAm 'add symlink "out"'
   $ hg init ../out
   $ echo 'out = out' >> .hgsub
-BROKEN: should fail
   $ 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
-BROKEN: should fail to update
   $ hg clone -q hgsymdir/root hgsymdir2/root
+  abort: subrepo 'out' traverses symbolic link
+  [255]
   $ ls hgsymdir2
-  out
   root
 
 #endif
--- a/tests/test-subrepo-git.t	Fri Nov 03 19:17:25 2017 +0900
+++ b/tests/test-subrepo-git.t	Fri Nov 03 20:12:50 2017 +0900
@@ -400,11 +400,13 @@
 Don't crash if subrepo is a broken symlink
   $ ln -s broken s
   $ hg status -S
+  abort: subrepo 's' traverses symbolic link
+  [255]
   $ hg push -q
-  abort: subrepo s is missing (in subrepository "s")
+  abort: subrepo 's' traverses symbolic link
   [255]
   $ hg commit --subrepos -qm missing
-  abort: subrepo s is missing (in subrepository "s")
+  abort: subrepo 's' traverses symbolic link
   [255]
   $ rm s
 #endif