On Tue, Mar 29, 2016 at 21:34:20 +0200, Salvatore Bonaccorso wrote: > the following vulnerabilities were published for mercurial. > > CVE-2016-3068[0]: > arbitrary code execution with Git subrepos > > CVE-2016-3069[1]: > arbitrary code execution when converting Git repos > > CVE-2016-3630[2]: > remote code execution in binary delta decoding > Hi,
here's a diff for jessie, modulo s/UNRELEASED/jessie-security/ in the changelog. OK to upload to security-master? I'll work on wheezy next. Cheers, Julien
diff -Nru mercurial-3.1.2/debian/changelog mercurial-3.1.2/debian/changelog --- mercurial-3.1.2/debian/changelog 2015-05-02 09:37:01.000000000 +0200 +++ mercurial-3.1.2/debian/changelog 2016-03-30 11:57:49.000000000 +0200 @@ -1,3 +1,19 @@ +mercurial (3.1.2-2+deb8u2) UNRELEASED; urgency=medium + + * CVE-2016-3630: + + parsers: fix list sizing rounding error + + parsers: detect short records + * CVE-2016-3068: + + subrepo: set GIT_ALLOW_PROTOCOL to limit git clone protocols + * CVE-2016-3069: + + convert: add new, non-clowny interface for shelling out to git + + convert: rewrite calls to Git to use the new shelling mechanism + + convert: dead code removal - old git calling functions + + convert: rewrite gitpipe to use common.commandline + + convert: test for shell injection in git calls + + -- Julien Cristau <julien.cris...@logilab.fr> Wed, 30 Mar 2016 11:55:27 +0200 + mercurial (3.1.2-2+deb8u1) jessie-security; urgency=high * Fix "CVE-2014-9462" by adding patch diff -Nru mercurial-3.1.2/debian/patches/from_upstream__convert-add-new,-non-clowny-interface-for-shelling-out-to-git.patch mercurial-3.1.2/debian/patches/from_upstream__convert-add-new,-non-clowny-interface-for-shelling-out-to-git.patch --- mercurial-3.1.2/debian/patches/from_upstream__convert-add-new,-non-clowny-interface-for-shelling-out-to-git.patch 1970-01-01 01:00:00.000000000 +0100 +++ mercurial-3.1.2/debian/patches/from_upstream__convert-add-new,-non-clowny-interface-for-shelling-out-to-git.patch 2016-03-30 12:04:55.000000000 +0200 @@ -0,0 +1,80 @@ +# HG changeset patch +# User Mateusz Kwapich <mitran...@fb.com> +# Date 1458691511 25200 +# Tue Mar 22 17:05:11 2016 -0700 +# Branch stable +# Node ID 197eed39e3d5e9a8cadfd9ba5839eb14cc265caa +# Parent 34d43cb85de8d06764039d8868eee19d00fddeab +convert: add new, non-clowny interface for shelling out to git (SEC) + +CVE-2016-3069 (1/5) + +To avoid shell injection and for the sake of simplicity let's use the +common.commandline for calling git. + +--- mercurial-3.1.2.orig/hgext/convert/git.py ++++ mercurial-3.1.2/hgext/convert/git.py +@@ -9,11 +9,11 @@ import os + import subprocess + from mercurial import util, config + from mercurial.node import hex, nullid + from mercurial.i18n import _ + +-from common import NoRepo, commit, converter_source, checktool ++from common import NoRepo, commit, converter_source, checktool, commandline + + class submodule(object): + def __init__(self, path, node, url): + self.path = path + self.node = node +@@ -23,11 +23,11 @@ class submodule(object): + return "%s = [git]%s" % (self.path, self.url) + + def hgsubstate(self): + return "%s %s" % (self.node, self.path) + +-class convert_git(converter_source): ++class convert_git(converter_source, commandline): + # Windows does not support GIT_DIR= construct while other systems + # cannot remove environment variable. Just assume none have + # both issues. + if util.safehasattr(os, 'unsetenv'): + def gitopen(self, s, err=None): +@@ -69,10 +69,25 @@ class convert_git(converter_source): + return util.popen('GIT_DIR=%s %s' % (self.path, s), 'rb') + + def gitpipe(self, s): + return util.popen3('GIT_DIR=%s %s' % (self.path, s)) + ++ def _gitcmd(self, cmd, *args, **kwargs): ++ return cmd('--git-dir=%s' % self.path, *args, **kwargs) ++ ++ def gitrun0(self, *args, **kwargs): ++ return self._gitcmd(self.run0, *args, **kwargs) ++ ++ def gitrun(self, *args, **kwargs): ++ return self._gitcmd(self.run, *args, **kwargs) ++ ++ def gitrunlines0(self, *args, **kwargs): ++ return self._gitcmd(self.runlines0, *args, **kwargs) ++ ++ def gitrunlines(self, *args, **kwargs): ++ return self._gitcmd(self.runlines, *args, **kwargs) ++ + def popen_with_stderr(self, s): + p = subprocess.Popen(s, shell=True, bufsize=-1, + close_fds=util.closefds, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, +@@ -86,10 +101,11 @@ class convert_git(converter_source): + data = fh.read() + return data, fh.close() + + def __init__(self, ui, path, rev=None): + super(convert_git, self).__init__(ui, path, rev=rev) ++ commandline.__init__(self, ui, 'git') + + if os.path.isdir(path + "/.git"): + path += "/.git" + if not os.path.exists(path + "/objects"): + raise NoRepo(_("%s does not look like a Git repository") % path) diff -Nru mercurial-3.1.2/debian/patches/from_upstream__convert-dead-code-removal---old-git-calling-functions.patch mercurial-3.1.2/debian/patches/from_upstream__convert-dead-code-removal---old-git-calling-functions.patch --- mercurial-3.1.2/debian/patches/from_upstream__convert-dead-code-removal---old-git-calling-functions.patch 1970-01-01 01:00:00.000000000 +0100 +++ mercurial-3.1.2/debian/patches/from_upstream__convert-dead-code-removal---old-git-calling-functions.patch 2016-03-30 11:53:08.000000000 +0200 @@ -0,0 +1,83 @@ +# HG changeset patch +# User Mateusz Kwapich <mitran...@fb.com> +# Date 1458691511 25200 +# Tue Mar 22 17:05:11 2016 -0700 +# Branch stable +# Node ID b732e7f2aba4c4c417278c7c7488006301551855 +# Parent cdda7b96afff3433eafdeeb83ded83a5b25b7a5b +convert: dead code removal - old git calling functions (SEC) + +CVE-2016-3069 (3/5) + +diff --git a/hgext/convert/git.py b/hgext/convert/git.py +--- a/hgext/convert/git.py ++++ b/hgext/convert/git.py +@@ -28,27 +28,10 @@ class submodule(object): + class convert_git(converter_source, commandline): + # Windows does not support GIT_DIR= construct while other systems + # cannot remove environment variable. Just assume none have + # both issues. + if util.safehasattr(os, 'unsetenv'): +- def gitopen(self, s, err=None): +- prevgitdir = os.environ.get('GIT_DIR') +- os.environ['GIT_DIR'] = self.path +- try: +- if err == subprocess.PIPE: +- (stdin, stdout, stderr) = util.popen3(s) +- return stdout +- elif err == subprocess.STDOUT: +- return self.popen_with_stderr(s) +- else: +- return util.popen(s, 'rb') +- finally: +- if prevgitdir is None: +- del os.environ['GIT_DIR'] +- else: +- os.environ['GIT_DIR'] = prevgitdir +- + def gitpipe(self, s): + prevgitdir = os.environ.get('GIT_DIR') + os.environ['GIT_DIR'] = self.path + try: + return util.popen3(s) +@@ -57,19 +40,10 @@ class convert_git(converter_source, comm + del os.environ['GIT_DIR'] + else: + os.environ['GIT_DIR'] = prevgitdir + + else: +- def gitopen(self, s, err=None): +- if err == subprocess.PIPE: +- (sin, so, se) = util.popen3('GIT_DIR=%s %s' % (self.path, s)) +- return so +- elif err == subprocess.STDOUT: +- return self.popen_with_stderr(s) +- else: +- return util.popen('GIT_DIR=%s %s' % (self.path, s), 'rb') +- + def gitpipe(self, s): + return util.popen3('GIT_DIR=%s %s' % (self.path, s)) + + def _gitcmd(self, cmd, *args, **kwargs): + return cmd('--git-dir=%s' % self.path, *args, **kwargs) +@@ -84,20 +58,10 @@ class convert_git(converter_source, comm + return self._gitcmd(self.runlines0, *args, **kwargs) + + def gitrunlines(self, *args, **kwargs): + return self._gitcmd(self.runlines, *args, **kwargs) + +- def popen_with_stderr(self, s): +- p = subprocess.Popen(s, shell=True, bufsize=-1, +- close_fds=util.closefds, +- stdin=subprocess.PIPE, +- stdout=subprocess.PIPE, +- stderr=subprocess.STDOUT, +- universal_newlines=False, +- env=None) +- return p.stdout +- + def gitread(self, s): + fh = self.gitopen(s) + data = fh.read() + return data, fh.close() + diff -Nru mercurial-3.1.2/debian/patches/from_upstream__convert-rewrite-calls-to-Git-to-use-the-new-shelling-mechanism.patch mercurial-3.1.2/debian/patches/from_upstream__convert-rewrite-calls-to-Git-to-use-the-new-shelling-mechanism.patch --- mercurial-3.1.2/debian/patches/from_upstream__convert-rewrite-calls-to-Git-to-use-the-new-shelling-mechanism.patch 1970-01-01 01:00:00.000000000 +0100 +++ mercurial-3.1.2/debian/patches/from_upstream__convert-rewrite-calls-to-Git-to-use-the-new-shelling-mechanism.patch 2016-03-30 12:22:00.000000000 +0200 @@ -0,0 +1,190 @@ +# HG changeset patch +# User Mateusz Kwapich <mitran...@fb.com> +# Date 1458691511 25200 +# Tue Mar 22 17:05:11 2016 -0700 +# Branch stable +# Node ID cdda7b96afff3433eafdeeb83ded83a5b25b7a5b +# Parent 197eed39e3d5e9a8cadfd9ba5839eb14cc265caa +convert: rewrite calls to Git to use the new shelling mechanism (SEC) + +CVE-2016-3069 (2/5) + +One test output changed because we were ignoring git return code in numcommits +before. + +--- mercurial-3.1.2.orig/hgext/convert/git.py ++++ mercurial-3.1.2/hgext/convert/git.py +@@ -121,16 +121,16 @@ class convert_git(converter_source, comm + for f in self.catfilepipe: + f.close() + + def getheads(self): + if not self.rev: +- heads, ret = self.gitread('git rev-parse --branches --remotes') +- heads = heads.splitlines() ++ output, status = self.gitrun('rev-parse', '--branches', '--remotes') ++ heads = output.splitlines() + else: +- heads, ret = self.gitread("git rev-parse --verify %s" % self.rev) +- heads = [heads[:-1]] +- if ret: ++ rawhead, status = self.gitrun('rev-parse', '--verify', self.rev) ++ heads = [rawhead[:-1]] ++ if status: + raise util.Abort(_('cannot retrieve git heads')) + return heads + + def catfile(self, rev, type): + if rev == hex(nullid): +@@ -183,30 +183,33 @@ class convert_git(converter_source, comm + s = c[sec] + if 'url' in s and 'path' in s: + self.submodules.append(submodule(s['path'], '', s['url'])) + + def retrievegitmodules(self, version): +- modules, ret = self.gitread("git show %s:%s" % (version, '.gitmodules')) ++ modules, ret = self.gitrun('show', '%s:%s' % (version, '.gitmodules')) + if ret: + raise util.Abort(_('cannot read submodules config file in %s') % + version) + self.parsegitmodules(modules) + for m in self.submodules: +- node, ret = self.gitread("git rev-parse %s:%s" % (version, m.path)) ++ node, ret = self.gitrun('rev-parse', '%s:%s' % (version, m.path)) + if ret: + continue + m.node = node.strip() + + def getchanges(self, version): + self.modecache = {} +- fh = self.gitopen("git diff-tree -z --root -m -r %s" % version) ++ cmd = ['diff-tree','-z', '--root', '-m', '-r', version] ++ output, status = self.gitrun(*cmd) ++ if status: ++ raise util.Abort(_('cannot read changes in %s') % version) + changes = [] + seen = set() + entry = None + subexists = False + subdeleted = False +- for l in fh.read().split('\x00'): ++ for l in output.split('\x00'): + if not entry: + if not l.startswith(':'): + continue + entry = l + continue +@@ -229,12 +232,10 @@ class convert_git(converter_source, comm + subexists = True + else: + self.modecache[(f, h)] = (p and "x") or (s and "l") or "" + changes.append((f, h)) + entry = None +- if fh.close(): +- raise util.Abort(_('cannot read changes in %s') % version) + + if subexists: + if subdeleted: + changes.append(('.hgsubstate', hex(nullid))) + else: +@@ -278,25 +279,25 @@ class convert_git(converter_source, comm + return c + + def gettags(self): + tags = {} + alltags = {} +- fh = self.gitopen('git ls-remote --tags "%s"' % self.path, +- err=subprocess.STDOUT) ++ output, status = self.gitrunlines('ls-remote', '--tags', self.path) ++ ++ if status: ++ raise util.Abort(_('cannot read tags from %s') % self.path) + prefix = 'refs/tags/' + + # Build complete list of tags, both annotated and bare ones +- for line in fh: ++ for line in output: + line = line.strip() + if line.startswith("error:") or line.startswith("fatal:"): + raise util.Abort(_('cannot read tags from %s') % self.path) + node, tag = line.split(None, 1) + if not tag.startswith(prefix): + continue + alltags[tag[len(prefix):]] = node +- if fh.close(): +- raise util.Abort(_('cannot read tags from %s') % self.path) + + # Filter out tag objects for annotated tag refs + for tag in alltags: + if tag.endswith('^{}'): + tags[tag[:-3]] = alltags[tag] +@@ -309,22 +310,24 @@ class convert_git(converter_source, comm + return tags + + def getchangedfiles(self, version, i): + changes = [] + if i is None: +- fh = self.gitopen("git diff-tree --root -m -r %s" % version) +- for l in fh: ++ output, status = self.gitrunlines('diff-tree', '--root', '-m', ++ '-r', version) ++ if status: ++ raise util.Abort(_('cannot read changes in %s') % version) ++ for l in output: + if "\t" not in l: + continue + m, f = l[:-1].split("\t") + changes.append(f) + else: +- fh = self.gitopen('git diff-tree --name-only --root -r %s ' +- '"%s^%s" --' % (version, version, i + 1)) +- changes = [f.rstrip('\n') for f in fh] +- if fh.close(): +- raise util.Abort(_('cannot read changes in %s') % version) ++ output, status = self.gitrunlines('diff-tree', '--name-only', ++ '--root', '-r', version, ++ '%s^%s' % (version, i + 1), '--') ++ changes = [f.rstrip('\n') for f in output] + + return changes + + def getbookmarks(self): + bookmarks = {} +@@ -332,18 +335,18 @@ class convert_git(converter_source, comm + # Interesting references in git are prefixed + prefix = 'refs/heads/' + prefixlen = len(prefix) + + # factor two commands +- gitcmd = { 'remote/': 'git ls-remote --heads origin', +- '': 'git show-ref'} ++ gitcmd = { 'remote/': ['ls-remote', '--heads', 'origin'], ++ '': ['show-ref']} + + # Origin heads + for reftype in gitcmd: + try: +- fh = self.gitopen(gitcmd[reftype], err=subprocess.PIPE) +- for line in fh: ++ output, status = self.gitrunlines(*gitcmd[reftype]) ++ for line in output: + line = line.strip() + rev, name = line.split(None, 1) + if not name.startswith(prefix): + continue + name = '%s%s' % (reftype, name[prefixlen:]) +--- mercurial-3.1.2.orig/tests/test-convert-git.t ++++ mercurial-3.1.2/tests/test-convert-git.t +@@ -389,11 +389,11 @@ cd ../../.. + + damage git repository by renaming a commit object + $ COMMIT_OBJ=1c/0ce3c5886f83a1d78a7b517cdff5cf9ca17bdd + $ mv git-repo4/.git/objects/$COMMIT_OBJ git-repo4/.git/objects/$COMMIT_OBJ.tmp + $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:' +- abort: cannot read tags from git-repo4/.git ++ abort: cannot retrieve number of commits in git-repo4/.git + $ mv git-repo4/.git/objects/$COMMIT_OBJ.tmp git-repo4/.git/objects/$COMMIT_OBJ + damage git repository by renaming a blob object + + $ BLOB_OBJ=8b/137891791fe96927ad78e64b0aad7bded08bdc + $ mv git-repo4/.git/objects/$BLOB_OBJ git-repo4/.git/objects/$BLOB_OBJ.tmp diff -Nru mercurial-3.1.2/debian/patches/from_upstream__convert-rewrite-gitpipe-to-use-common.commandline.patch mercurial-3.1.2/debian/patches/from_upstream__convert-rewrite-gitpipe-to-use-common.commandline.patch --- mercurial-3.1.2/debian/patches/from_upstream__convert-rewrite-gitpipe-to-use-common.commandline.patch 1970-01-01 01:00:00.000000000 +0100 +++ mercurial-3.1.2/debian/patches/from_upstream__convert-rewrite-gitpipe-to-use-common.commandline.patch 2016-03-30 12:25:02.000000000 +0200 @@ -0,0 +1,82 @@ +# HG changeset patch +# User Mateusz Kwapich <mitran...@fb.com> +# Date 1458691511 25200 +# Tue Mar 22 17:05:11 2016 -0700 +# Branch stable +# Node ID 80cac1de6aea89f9d068abb09b0ea58c70bd7130 +# Parent b732e7f2aba4c4c417278c7c7488006301551855 +convert: rewrite gitpipe to use common.commandline (SEC) + +CVE-2016-3069 (4/5) + +--- mercurial-3.1.2.orig/hgext/convert/common.py ++++ mercurial-3.1.2/hgext/convert/common.py +@@ -312,10 +312,13 @@ class commandline(object): + return self._dorun(popen, cmd, *args, **kwargs) + + def _run2(self, cmd, *args, **kwargs): + return self._dorun(util.popen2, cmd, *args, **kwargs) + ++ def _run3(self, cmd, *args, **kwargs): ++ return self._dorun(util.popen3, cmd, *args, **kwargs) ++ + def _dorun(self, openfunc, cmd, *args, **kwargs): + cmdline = self._cmdline(cmd, *args, **kwargs) + self.ui.debug('running: %s\n' % (cmdline,)) + self.prerun() + try: +--- mercurial-3.1.2.orig/hgext/convert/git.py ++++ mercurial-3.1.2/hgext/convert/git.py +@@ -27,25 +27,10 @@ class submodule(object): + + class convert_git(converter_source, commandline): + # Windows does not support GIT_DIR= construct while other systems + # cannot remove environment variable. Just assume none have + # both issues. +- if util.safehasattr(os, 'unsetenv'): +- def gitpipe(self, s): +- prevgitdir = os.environ.get('GIT_DIR') +- os.environ['GIT_DIR'] = self.path +- try: +- return util.popen3(s) +- finally: +- if prevgitdir is None: +- del os.environ['GIT_DIR'] +- else: +- os.environ['GIT_DIR'] = prevgitdir +- +- else: +- def gitpipe(self, s): +- return util.popen3('GIT_DIR=%s %s' % (self.path, s)) + + def _gitcmd(self, cmd, *args, **kwargs): + return cmd('--git-dir=%s' % self.path, *args, **kwargs) + + def gitrun0(self, *args, **kwargs): +@@ -58,10 +43,13 @@ class convert_git(converter_source, comm + return self._gitcmd(self.runlines0, *args, **kwargs) + + def gitrunlines(self, *args, **kwargs): + return self._gitcmd(self.runlines, *args, **kwargs) + ++ def gitpipe(self, *args, **kwargs): ++ return self._gitcmd(self._run3, *args, **kwargs) ++ + def gitread(self, s): + fh = self.gitopen(s) + data = fh.read() + return data, fh.close() + +@@ -77,11 +65,11 @@ class convert_git(converter_source, comm + checktool('git', 'git', debname='git-core') + + self.path = path + self.submodules = [] + +- self.catfilepipe = self.gitpipe('git cat-file --batch') ++ self.catfilepipe = self.gitpipe('cat-file', '--batch') + + def after(self): + for f in self.catfilepipe: + f.close() + diff -Nru mercurial-3.1.2/debian/patches/from_upstream__convert-test-for-shell-injection-in-git-calls.patch mercurial-3.1.2/debian/patches/from_upstream__convert-test-for-shell-injection-in-git-calls.patch --- mercurial-3.1.2/debian/patches/from_upstream__convert-test-for-shell-injection-in-git-calls.patch 1970-01-01 01:00:00.000000000 +0100 +++ mercurial-3.1.2/debian/patches/from_upstream__convert-test-for-shell-injection-in-git-calls.patch 2016-03-30 12:26:07.000000000 +0200 @@ -0,0 +1,40 @@ +# HG changeset patch +# User Mateusz Kwapich <mitran...@fb.com> +# Date 1458692847 25200 +# Tue Mar 22 17:27:27 2016 -0700 +# Branch stable +# Node ID ae279d4a19e9683214cbd1fe8298cf0b50571432 +# Parent 80cac1de6aea89f9d068abb09b0ea58c70bd7130 +convert: test for shell injection in git calls (SEC) + +CVE-2016-3069 (5/5) + +Before recent refactoring we were not escaping calls to git at all +which made such injections possible. Let's have a test for that to +avoid this problem in the future. Reported by Blake Burkhart. + +--- mercurial-3.1.2.orig/tests/test-convert-git.t ++++ mercurial-3.1.2/tests/test-convert-git.t +@@ -404,5 +404,22 @@ damage git repository by renaming a tree + + $ TREE_OBJ=72/49f083d2a63a41cc737764a86981eb5f3e4635 + $ mv git-repo4/.git/objects/$TREE_OBJ git-repo4/.git/objects/$TREE_OBJ.tmp + $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | grep 'abort:' + abort: cannot read changes in 1c0ce3c5886f83a1d78a7b517cdff5cf9ca17bdd ++ ++test for escaping the repo name (CVE-2016-3069) ++ ++ $ git init '`echo pwned >COMMAND-INJECTION`' ++ Initialized empty Git repository in $TESTTMP/`echo pwned >COMMAND-INJECTION`/.git/ ++ $ cd '`echo pwned >COMMAND-INJECTION`' ++ $ git commit -q --allow-empty -m 'empty' ++ $ cd .. ++ $ hg convert '`echo pwned >COMMAND-INJECTION`' 'converted' ++ initializing destination converted repository ++ scanning source... ++ sorting... ++ converting... ++ 0 empty ++ updating bookmarks ++ $ test -f COMMAND-INJECTION ++ [1] diff -Nru mercurial-3.1.2/debian/patches/from_upstream__parsers-detect-short-records.patch mercurial-3.1.2/debian/patches/from_upstream__parsers-detect-short-records.patch --- mercurial-3.1.2/debian/patches/from_upstream__parsers-detect-short-records.patch 1970-01-01 01:00:00.000000000 +0100 +++ mercurial-3.1.2/debian/patches/from_upstream__parsers-detect-short-records.patch 2016-03-30 11:53:08.000000000 +0200 @@ -0,0 +1,33 @@ +# HG changeset patch +# User Matt Mackall <m...@selenic.com> +# Date 1458174626 25200 +# Wed Mar 16 17:30:26 2016 -0700 +# Branch stable +# Node ID b9714d958e89cd6ff1da46b46f39076c03325ac7 +# Parent b6ed2505d6cf1d73f7f5c62e7369c4ce65cd3732 +parsers: detect short records (SEC) + +CVE-2016-3630 (2/2) + +This addresses part of a vulnerability in binary delta application. + +diff --git a/mercurial/mpatch.c b/mercurial/mpatch.c +--- a/mercurial/mpatch.c ++++ b/mercurial/mpatch.c +@@ -213,14 +213,14 @@ static struct flist *decode(const char * + + while (pos >= 0 && pos < len) { + lt->start = getbe32(bin + pos); + lt->end = getbe32(bin + pos + 4); + lt->len = getbe32(bin + pos + 8); +- if (lt->start > lt->end) +- break; /* sanity check */ + lt->data = bin + pos + 12; + pos += 12 + lt->len; ++ if (lt->start > lt->end || lt->len < 0) ++ break; /* sanity check */ + lt++; + } + + if (pos != len) { + if (!PyErr_Occurred()) diff -Nru mercurial-3.1.2/debian/patches/from_upstream__parsers-fix-list-sizing-rounding-error.patch mercurial-3.1.2/debian/patches/from_upstream__parsers-fix-list-sizing-rounding-error.patch --- mercurial-3.1.2/debian/patches/from_upstream__parsers-fix-list-sizing-rounding-error.patch 1970-01-01 01:00:00.000000000 +0100 +++ mercurial-3.1.2/debian/patches/from_upstream__parsers-fix-list-sizing-rounding-error.patch 2016-03-30 11:53:08.000000000 +0200 @@ -0,0 +1,50 @@ +# HG changeset patch +# User Matt Mackall <m...@selenic.com> +# Date 1458174569 25200 +# Wed Mar 16 17:29:29 2016 -0700 +# Branch stable +# Node ID b6ed2505d6cf1d73f7f5c62e7369c4ce65cd3732 +# Parent a2c2dd399f3b9fb84edd75a930e895f0c5e4ad5b +parsers: fix list sizing rounding error (SEC) + +CVE-2016-3630 (1/2) + +This addresses part of a vulnerability in application of binary +deltas. + +diff --git a/mercurial/mpatch.c b/mercurial/mpatch.c +--- a/mercurial/mpatch.c ++++ b/mercurial/mpatch.c +@@ -203,11 +203,11 @@ static struct flist *decode(const char * + struct flist *l; + struct frag *lt; + int pos = 0; + + /* assume worst case size, we won't have many of these lists */ +- l = lalloc(len / 12); ++ l = lalloc(len / 12 + 1); + if (!l) + return NULL; + + lt = l->tail; + +diff --git a/tests/test-revlog.t b/tests/test-revlog.t +new file mode 100644 +--- /dev/null ++++ b/tests/test-revlog.t +@@ -0,0 +1,15 @@ ++Test for CVE-2016-3630 ++ ++ $ hg init ++ ++ >>> open("a.i", "w").write( ++ ... """eJxjYGZgZIAAYQYGxhgom+k/FMx8YKx9ZUaKSOyqo4cnuKb8mbqHV5cBCVTMWb1Cwqkhe4Gsg9AD ++ ... Joa3dYtcYYYBAQ8Qr4OqZAYRICPTSr5WKd/42rV36d+8/VmrNpv7NP1jQAXrQE4BqQUARngwVA==""" ++ ... .decode("base64").decode("zlib")) ++ ++ $ hg debugindex a.i ++ rev offset length delta linkrev nodeid p1 p2 ++ 0 0 19 -1 2 99e0332bd498 000000000000 000000000000 ++ 1 19 12 0 3 6674f57a23d8 99e0332bd498 000000000000 ++ $ hg debugdata a.i 1 2>&1 | grep decoded ++ mpatch.mpatchError: patch cannot be decoded diff -Nru mercurial-3.1.2/debian/patches/from_upstream__subrepo-set-GIT_ALLOW_PROTOCOL-to-limit-git-clone-protocols.patch mercurial-3.1.2/debian/patches/from_upstream__subrepo-set-GIT_ALLOW_PROTOCOL-to-limit-git-clone-protocols.patch --- mercurial-3.1.2/debian/patches/from_upstream__subrepo-set-GIT_ALLOW_PROTOCOL-to-limit-git-clone-protocols.patch 1970-01-01 01:00:00.000000000 +0100 +++ mercurial-3.1.2/debian/patches/from_upstream__subrepo-set-GIT_ALLOW_PROTOCOL-to-limit-git-clone-protocols.patch 2016-03-30 12:28:00.000000000 +0200 @@ -0,0 +1,97 @@ +# HG changeset patch +# User Mateusz Kwapich <mitran...@fb.com> +# Date 1458535941 25200 +# Sun Mar 20 21:52:21 2016 -0700 +# Branch stable +# Node ID 34d43cb85de8d06764039d8868eee19d00fddeab +# Parent b9714d958e89cd6ff1da46b46f39076c03325ac7 +subrepo: set GIT_ALLOW_PROTOCOL to limit git clone protocols (SEC) + +CVE-2016-3068 (1/1) + +Git's git-remote-ext remote helper provides an ext:: URL scheme that +allows running arbitrary shell commands. This feature allows +implementing simple git smart transports with a single shell shell +command. However, git submodules could clone arbitrary URLs specified +in the .gitmodules file. This was reported as CVE-2015-7545 and fixed +in git v2.6.1. + +However, if a user directly clones a malicious ext URL, the git client +will still run arbitrary shell commands. + +Mercurial is similarly effected. Mercurial allows specifying git +repositories as subrepositories. Git ext:: URLs can be specified as +Mercurial subrepositories allowing arbitrary shell commands to be run +on `hg clone ...`. + + +The Mercurial community would like to thank Blake Burkhart for +reporting this issue. The description of the issue is copied from +Blake's report. + +This commit changes submodules to pass the GIT_ALLOW_PROTOCOL env +variable to git commands with the same list of allowed protocols that +git submodule is using. + +When the GIT_ALLOW_PROTOCOL env variable is already set, we just pass it +to git without modifications. + +--- mercurial-3.1.2.orig/mercurial/subrepo.py ++++ mercurial-3.1.2/mercurial/subrepo.py +@@ -1198,10 +1198,15 @@ class gitsubrepo(abstractsubrepo): + + The methods tries to call the git command. versions prior to 1.6.0 + are not supported and very probably fail. + """ + self._ui.debug('%s: git %s\n' % (self._relpath, ' '.join(commands))) ++ if env is None: ++ env = os.environ.copy() ++ # fix for Git CVE-2015-7545 ++ if 'GIT_ALLOW_PROTOCOL' not in env: ++ env['GIT_ALLOW_PROTOCOL'] = 'file:git:http:https:ssh' + # unless ui.quiet is set, print git's stderr, + # which is mostly progress and useful info + errpipe = None + if self._ui.quiet: + errpipe = open(os.devnull, 'w') +--- mercurial-3.1.2.orig/tests/test-subrepo-git.t ++++ mercurial-3.1.2/tests/test-subrepo-git.t +@@ -659,6 +659,38 @@ Test that sanitizing is omitted in meta + $ echo '.hg/hgrc in git metadata area' > s/.git/.hg/hgrc + $ hg update -q -C af6d2edbb0d3 + checking out detached HEAD in subrepo s + check out a git branch if you intend to make changes + ++test for Git CVE-2016-3068 ++ $ hg init malicious-subrepository ++ $ cd malicious-subrepository ++ $ echo "s = [git]ext::sh -c echo% pwned% >&2" > .hgsub ++ $ git init s ++ Initialized empty Git repository in $TESTTMP/tc/malicious-subrepository/s/.git/ ++ $ cd s ++ $ git commit --allow-empty -m 'empty' ++ [master (root-commit) 153f934] empty + $ cd .. ++ $ hg add .hgsub ++ $ hg commit -m "add subrepo" ++ $ cd .. ++ $ env -u GIT_ALLOW_PROTOCOL hg clone malicious-subrepository malicious-subrepository-protected ++ Cloning into '$TESTTMP/tc/malicious-subrepository-protected/s'... ++ fatal: transport 'ext' not allowed ++ updating to branch default ++ cloning subrepo s from ext::sh -c echo% pwned% >&2 ++ abort: git clone error 128 in s (in subrepo s) ++ [255] ++ ++whitelisting of ext should be respected (that's the git submodule behaviour) ++ $ env GIT_ALLOW_PROTOCOL=ext hg clone malicious-subrepository malicious-subrepository-clone-allowed ++ Cloning into '$TESTTMP/tc/malicious-subrepository-clone-allowed/s'... ++ pwned ++ fatal: Could not read from remote repository. ++ ++ Please make sure you have the correct access rights ++ and the repository exists. ++ updating to branch default ++ cloning subrepo s from ext::sh -c echo% pwned% >&2 ++ abort: git clone error 128 in s (in subrepo s) ++ [255] diff -Nru mercurial-3.1.2/debian/patches/series mercurial-3.1.2/debian/patches/series --- mercurial-3.1.2/debian/patches/series 2015-05-01 19:33:14.000000000 +0200 +++ mercurial-3.1.2/debian/patches/series 2016-03-30 11:54:10.000000000 +0200 @@ -13,3 +13,11 @@ from_upstream__pathauditor_check_for_codepoints_ignored_on_OS_X.patch from_upstream__pathauditor_check_for_Windows_shortname_aliases.patch from_upstream__sshpeer_more_thorough_shell_quoting.patch +from_upstream__parsers-fix-list-sizing-rounding-error.patch +from_upstream__parsers-detect-short-records.patch +from_upstream__subrepo-set-GIT_ALLOW_PROTOCOL-to-limit-git-clone-protocols.patch +from_upstream__convert-add-new,-non-clowny-interface-for-shelling-out-to-git.patch +from_upstream__convert-rewrite-calls-to-Git-to-use-the-new-shelling-mechanism.patch +from_upstream__convert-dead-code-removal---old-git-calling-functions.patch +from_upstream__convert-rewrite-gitpipe-to-use-common.commandline.patch +from_upstream__convert-test-for-shell-injection-in-git-calls.patch