diff --git a/mercurial/configitems.py b/mercurial/configitems.py --- a/mercurial/configitems.py +++ b/mercurial/configitems.py @@ -814,6 +814,15 @@ coreconfigitem('sparse', 'missingwarning coreconfigitem('subrepos', 'allowed', default=dynamicdefault, # to make backporting simpler ) +coreconfigitem('subrepos', 'hg:allowed', + default=dynamicdefault, +) +coreconfigitem('subrepos', 'git:allowed', + default=dynamicdefault, +) +coreconfigitem('subrepos', 'svn:allowed', + default=dynamicdefault, +) coreconfigitem('templates', '.*', default=None, generic=True, diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt --- a/mercurial/help/config.txt +++ b/mercurial/help/config.txt @@ -1899,20 +1899,40 @@ relative path alone. The rules are appli This section contains options that control the behavior of the subrepositories feature. See also :hg:`help subrepos`. +Security note: auditing in Mercurial is known to be insufficient to +prevent clone-time code execution with carefully constructed Git +subrepos. It is unknown if a similar detect is present in Subversion +subrepos. Both Git and Subversion subrepos are disabled by default +out of security concerns. These subrepo types can be enabled using +the respective options below. + ``allowed`` - List of subrepository types (hg, git, svn) allowed in the working - directory. - - When disallowed, any commands including :hg:`update` will fail if - subrepositories are involved. - - Security note: auditing in Mercurial is known to be insufficient - to prevent clone-time code execution with carefully constructed - Git subrepos. It is unknown if a similar defect is present in - Subversion subrepos, so both are disabled by default out of an - abundance of caution. Re-enable such subrepos via this setting - with caution. - (default: `hg`) + Whether subrepositories are allowed in the working directory. + + When false, commands involving subrepositories (like :hg:`update`) + will fail for all subrepository types. + (default: true) + +``hg:allowed`` + Whether Mercurial subrepositories are allowed in the working + directory. This option only has an effect if ``subrepos.allowed`` + is true. + (default: true) + +``git:allowed`` + Whether Git subrepositories are allowed in the working directory. + This option only has an effect if ``subrepos.allowed`` is true. + + See the security note above before enabling Git subrepos. + (default: false) + +``svn:allowed`` + Whether Subversion subrepositories are allowed in the working + directory. This option only has an effect if ``subrepos.allowed`` + is true. + + See the security note above before enabling Subversion subrepos. + (default: false) ``templatealias`` ----------------- diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py --- a/mercurial/subrepo.py +++ b/mercurial/subrepo.py @@ -365,10 +365,24 @@ def _auditsubrepopath(repo, path): if repo.wvfs.islink(path): raise error.Abort(_("subrepo '%s' traverses symbolic link") % path) +SUBREPO_ALLOWED_DEFAULTS = { + 'hg': True, + 'git': False, + 'svn': False, +} + def _checktype(ui, kind): - if kind not in ui.configlist('subrepos', 'allowed', ['hg']): - raise error.Abort(_("subrepo type %s not allowed") % kind, + # subrepos.allowed is a master kill switch. If disabled, subrepos are + # disabled period. + if not ui.configbool('subrepos', 'allowed', True): + raise error.Abort(_('subrepos not enabled'), hint=_("see 'hg help config.subrepos' for details")) + + default = SUBREPO_ALLOWED_DEFAULTS.get(kind, False) + if not ui.configbool('subrepos', '%s:allowed' % kind, default): + raise error.Abort(_('%s subrepos not allowed') % kind, + hint=_("see 'hg help config.subrepos' for details")) + if kind not in types: raise error.Abort(_('unknown subrepo type %s') % kind) diff --git a/tests/test-convert-git.t b/tests/test-convert-git.t --- a/tests/test-convert-git.t +++ b/tests/test-convert-git.t @@ -8,7 +8,7 @@ $ echo "convert=" >> $HGRCPATH $ cat >> $HGRCPATH < [subrepos] - > allowed = hg, git + > git:allowed = true > EOF $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL diff --git a/tests/test-mq-subrepo-svn.t b/tests/test-mq-subrepo-svn.t --- a/tests/test-mq-subrepo-svn.t +++ b/tests/test-mq-subrepo-svn.t @@ -6,7 +6,8 @@ > [diff] > nodates = 1 > [subrepos] - > allowed = hg, svn + > allowed = true + > svn:allowed = true > EOF fn to create new repository, and cd into it diff --git a/tests/test-subrepo-git.t b/tests/test-subrepo-git.t --- a/tests/test-subrepo-git.t +++ b/tests/test-subrepo-git.t @@ -45,7 +45,7 @@ add subrepo clone git subrepo is disabled by default $ hg commit -m 'new git subrepo' - abort: subrepo type git not allowed + abort: git subrepos not allowed (see 'hg help config.subrepos' for details) [255] @@ -53,7 +53,7 @@ so enable it $ cat >> $HGRCPATH < [subrepos] - > allowed = hg, git + > git:allowed = true > EOF $ hg commit -m 'new git subrepo' @@ -106,30 +106,22 @@ clone root clone with subrepo disabled (update should fail) - $ hg clone t -U tc2 --config subrepos.allowed= - $ hg update -R tc2 --config subrepos.allowed= - abort: subrepo type git not allowed + $ hg clone t -U tc2 --config subrepos.allowed=false + $ hg update -R tc2 --config subrepos.allowed=false + abort: subrepos not enabled (see 'hg help config.subrepos' for details) [255] $ ls tc2 a - $ hg clone t tc3 --config subrepos.allowed= + $ hg clone t tc3 --config subrepos.allowed=false updating to branch default - abort: subrepo type git not allowed + abort: subrepos not enabled (see 'hg help config.subrepos' for details) [255] $ ls tc3 a - $ hg clone t tc4 --config subrepos.allowed=hg - updating to branch default - abort: subrepo type git not allowed - (see 'hg help config.subrepos' for details) - [255] - $ ls tc4 - a - update to previous substate $ cd tc diff --git a/tests/test-subrepo-svn.t b/tests/test-subrepo-svn.t --- a/tests/test-subrepo-svn.t +++ b/tests/test-subrepo-svn.t @@ -61,7 +61,7 @@ add first svn sub with leading whitespac svn subrepo is disabled by default $ hg ci -m1 - abort: subrepo type svn not allowed + abort: svn subrepos not allowed (see 'hg help config.subrepos' for details) [255] @@ -69,7 +69,7 @@ so enable it $ cat >> $HGRCPATH < [subrepos] - > allowed = hg, svn + > svn:allowed = true > EOF $ hg ci -m1 diff --git a/tests/test-subrepo.t b/tests/test-subrepo.t --- a/tests/test-subrepo.t +++ b/tests/test-subrepo.t @@ -488,30 +488,40 @@ clone clone with subrepo disabled (update should fail) - $ hg clone t -U tc2 --config subrepos.allowed= - $ hg update -R tc2 --config subrepos.allowed= - abort: subrepo type hg not allowed + $ hg clone t -U tc2 --config subrepos.allowed=false + $ hg update -R tc2 --config subrepos.allowed=false + abort: subrepos not enabled (see 'hg help config.subrepos' for details) [255] $ ls tc2 a - $ hg clone t tc3 --config subrepos.allowed= + $ hg clone t tc3 --config subrepos.allowed=false updating to branch default - abort: subrepo type hg not allowed + abort: subrepos not enabled (see 'hg help config.subrepos' for details) [255] $ ls tc3 a - $ hg clone t tc4 --config subrepos.allowed=git - updating to branch default - abort: subrepo type hg not allowed +And again with just the hg type disabled + + $ hg clone t -U tc4 --config subrepos.hg:allowed=false + $ hg update -R tc4 --config subrepos.hg:allowed=false + abort: hg subrepos not allowed (see 'hg help config.subrepos' for details) [255] $ ls tc4 a + $ hg clone t tc5 --config subrepos.hg:allowed=false + updating to branch default + abort: hg subrepos not allowed + (see 'hg help config.subrepos' for details) + [255] + $ ls tc5 + a + push $ cd tc