diff --git a/SOURCES/mercurial-cve-2018-1000132.patch b/SOURCES/mercurial-cve-2018-1000132.patch new file mode 100644 index 0000000..4f22e0c --- /dev/null +++ b/SOURCES/mercurial-cve-2018-1000132.patch @@ -0,0 +1,1865 @@ +diff -r cceaf7af4c9e hgext/largefiles/uisetup.py +--- a/hgext/largefiles/uisetup.py Sat Jun 01 17:09:41 2013 -0500 ++++ b/hgext/largefiles/uisetup.py Tue Jul 03 11:25:06 2018 +0200 +@@ -11,7 +11,7 @@ + from mercurial import archival, cmdutil, commands, extensions, filemerge, hg, \ + httppeer, localrepo, merge, scmutil, sshpeer, wireproto, revset + from mercurial.i18n import _ +-from mercurial.hgweb import hgweb_mod, webcommands ++from mercurial.hgweb import webcommands + from mercurial.subrepo import hgsubrepo + + import overrides +@@ -134,9 +134,10 @@ + + # make putlfile behave the same as push and {get,stat}lfile behave + # the same as pull w.r.t. permissions checks +- hgweb_mod.perms['putlfile'] = 'push' +- hgweb_mod.perms['getlfile'] = 'pull' +- hgweb_mod.perms['statlfile'] = 'pull' ++ wireproto.permissions['putlfile'] = 'push' ++ wireproto.permissions['getlfile'] = 'pull' ++ wireproto.permissions['statlfile'] = 'pull' ++ wireproto.permissions['lheads'] = 'pull' + + extensions.wrapfunction(webcommands, 'decodepath', overrides.decodepath) + +diff -r cceaf7af4c9e mercurial/hgweb/hgweb_mod.py +--- a/mercurial/hgweb/hgweb_mod.py Sat Jun 01 17:09:41 2013 -0500 ++++ b/mercurial/hgweb/hgweb_mod.py Tue Jul 03 11:25:06 2018 +0200 +@@ -7,7 +7,7 @@ + # GNU General Public License version 2 or any later version. + + import os +-from mercurial import ui, hg, hook, error, encoding, templater, util, repoview ++from mercurial import ui, hg, hook, error, encoding, templater, util, repoview, wireproto + from mercurial.templatefilters import websub + from mercurial.i18n import _ + from common import get_stat, ErrorResponse, permhooks, caching +@@ -16,15 +16,8 @@ + from request import wsgirequest + import webcommands, protocol, webutil, re + +-perms = { +- 'changegroup': 'pull', +- 'changegroupsubset': 'pull', +- 'getbundle': 'pull', +- 'stream_out': 'pull', +- 'listkeys': 'pull', +- 'unbundle': 'push', +- 'pushkey': 'push', +-} ++# Aliased for API compatibility. ++perms = wireproto.permissions + + def makebreadcrumb(url, prefix=''): + '''Return a 'URL breadcrumb' list +@@ -165,8 +158,13 @@ + try: + if query: + raise ErrorResponse(HTTP_NOT_FOUND) +- if cmd in perms: +- self.check_perm(req, perms[cmd]) ++ ++ req.checkperm = lambda op: self.check_perm(req, op) ++ # Assume commands with no defined permissions are writes / ++ # for pushes. This is the safest from a security perspective ++ # because it doesn't allow commands with undefined semantics ++ # from bypassing permissions checks. ++ req.checkperm(perms.get(cmd, 'push')) + return protocol.call(self.repo, req, cmd) + except ErrorResponse, inst: + # A client that sends unbundle without 100-continue will +diff -r cceaf7af4c9e mercurial/hgweb/protocol.py +--- a/mercurial/hgweb/protocol.py Sat Jun 01 17:09:41 2013 -0500 ++++ b/mercurial/hgweb/protocol.py Tue Jul 03 11:25:06 2018 +0200 +@@ -17,6 +17,7 @@ + self.req = req + self.response = '' + self.ui = ui ++ self.checkperm = req.checkperm + def getargs(self, args): + knownargs = self._args() + data = {} +diff -r cceaf7af4c9e mercurial/wireproto.py +--- a/mercurial/wireproto.py Sat Jun 01 17:09:41 2013 -0500 ++++ b/mercurial/wireproto.py Tue Jul 03 11:25:06 2018 +0200 +@@ -11,6 +11,10 @@ + import changegroup as changegroupmod + import peer, error, encoding, util, store + ++# Maps wire protocol name to operation type. This is used for permissions ++# checking. ++permissions = {} ++ + # abstract batching support + + class future(object): +@@ -361,6 +365,15 @@ + % (cmd, ",".join(others))) + return opts + ++def wireprotocommand(name, args=''): ++ """decorator for wire protocol command""" ++ def register(func): ++ commands[name] = (func, args) ++ return func ++ return register ++ ++# TODO define a more appropriate permissions type to use for this. ++permissions['batch'] = 'pull' + def batch(repo, proto, cmds, others): + repo = repo.filtered("served") + res = [] +@@ -372,6 +385,17 @@ + n, v = a.split('=') + vals[n] = unescapearg(v) + func, spec = commands[op] ++ ++ # If the protocol supports permissions checking, perform that ++ # checking on each batched command. ++ # TODO formalize permission checking as part of protocol interface. ++ if util.safehasattr(proto, 'checkperm'): ++ # Assume commands with no defined permissions are writes / for ++ # pushes. This is the safest from a security perspective because ++ # it doesn't allow commands with undefined semantics from ++ # bypassing permissions checks. ++ proto.checkperm(permissions.get(op, 'push')) ++ + if spec: + keys = spec.split() + data = {} +@@ -392,6 +416,7 @@ + res.append(escapearg(result)) + return ';'.join(res) + ++permissions['between'] = 'pull' + def between(repo, proto, pairs): + pairs = [decodelist(p, '-') for p in pairs.split(" ")] + r = [] +@@ -399,6 +424,7 @@ + r.append(encodelist(b) + "\n") + return "".join(r) + ++permissions['branchmap'] = 'pull' + def branchmap(repo, proto): + branchmap = repo.branchmap() + heads = [] +@@ -408,6 +434,7 @@ + heads.append('%s %s' % (branchname, branchnodes)) + return '\n'.join(heads) + ++permissions['branches'] = 'pull' + def branches(repo, proto, nodes): + nodes = decodelist(nodes) + r = [] +@@ -415,6 +442,7 @@ + r.append(encodelist(b) + "\n") + return "".join(r) + ++permissions['capabilities'] = 'pull' + def capabilities(repo, proto): + caps = ('lookup changegroupsubset branchmap pushkey known getbundle ' + 'unbundlehash batch').split() +@@ -432,22 +460,26 @@ + caps.append('httpheader=1024') + return ' '.join(caps) + ++permissions['changegroup'] = 'pull' + def changegroup(repo, proto, roots): + nodes = decodelist(roots) + cg = repo.changegroup(nodes, 'serve') + return streamres(proto.groupchunks(cg)) + ++permissions['changegroupsubset'] = 'pull' + def changegroupsubset(repo, proto, bases, heads): + bases = decodelist(bases) + heads = decodelist(heads) + cg = repo.changegroupsubset(bases, heads, 'serve') + return streamres(proto.groupchunks(cg)) + ++permissions['debugwireargs'] = 'pull' + def debugwireargs(repo, proto, one, two, others): + # only accept optional args from the known set + opts = options('debugwireargs', ['three', 'four'], others) + return repo.debugwireargs(one, two, **opts) + ++permissions['getbundle'] = 'pull' + def getbundle(repo, proto, others): + opts = options('getbundle', ['heads', 'common'], others) + for k, v in opts.iteritems(): +@@ -455,10 +487,12 @@ + cg = repo.getbundle('serve', **opts) + return streamres(proto.groupchunks(cg)) + ++permissions['heads'] = 'pull' + def heads(repo, proto): + h = repo.heads() + return encodelist(h) + "\n" + ++permissions['hello'] = 'pull' + def hello(repo, proto): + '''the hello command returns a set of lines describing various + interesting things about the server, in an RFC822-like format. +@@ -469,12 +503,14 @@ + ''' + return "capabilities: %s\n" % (capabilities(repo, proto)) + ++permissions['listkeys'] = 'pull' + def listkeys(repo, proto, namespace): + d = repo.listkeys(encoding.tolocal(namespace)).items() + t = '\n'.join(['%s\t%s' % (encoding.fromlocal(k), encoding.fromlocal(v)) + for k, v in d]) + return t + ++permissions['lookup'] = 'pull' + def lookup(repo, proto, key): + try: + k = encoding.tolocal(key) +@@ -486,9 +522,11 @@ + success = 0 + return "%s %s\n" % (success, r) + ++permissions['known'] = 'pull' + def known(repo, proto, nodes, others): + return ''.join(b and "1" or "0" for b in repo.known(decodelist(nodes))) + ++permissions['pushkey'] = 'push' + def pushkey(repo, proto, namespace, key, old, new): + # compatibility with pre-1.8 clients which were accidentally + # sending raw binary nodes rather than utf-8-encoded hex +@@ -523,6 +561,7 @@ + def _allowstream(ui): + return ui.configbool('server', 'uncompressed', True, untrusted=True) + ++permissions['stream_out'] = 'pull' + def stream(repo, proto): + '''If the server supports streaming clone, it advertises the "stream" + capability with a value representing the version and flags of the repo +@@ -589,6 +628,7 @@ + + return streamres(streamer(repo, entries, total_bytes)) + ++permissions['unbundle'] = 'push' + def unbundle(repo, proto, heads): + their_heads = decodelist(heads) + +diff -r cceaf7af4c9e tests/get-with-headers.py +--- a/tests/get-with-headers.py Sat Jun 01 17:09:41 2013 -0500 ++++ b/tests/get-with-headers.py Tue Jul 03 11:25:06 2018 +0200 +@@ -3,6 +3,7 @@ + """This does HTTP GET requests given a host:port and path and returns + a subset of the headers plus the body of the result.""" + ++import argparse + import httplib, sys + + try: +@@ -12,14 +13,22 @@ + except ImportError: + pass + +-twice = False +-if '--twice' in sys.argv: +- sys.argv.remove('--twice') +- twice = True +-headeronly = False +-if '--headeronly' in sys.argv: +- sys.argv.remove('--headeronly') +- headeronly = True ++parser = argparse.ArgumentParser() ++parser.add_argument('--twice', action='store_true') ++parser.add_argument('--headeronly', action='store_true') ++parser.add_argument('--requestheader', nargs='*', default=[], ++ help='Send an additional HTTP request header. Argument ' ++ 'value is
=') ++parser.add_argument('--bodyfile', ++ help='Write HTTP response body to a file') ++parser.add_argument('host') ++parser.add_argument('path') ++parser.add_argument('show', nargs='*') ++args = parser.parse_args() ++ ++twice = args.twice ++headeronly = args.headeronly ++requestheaders = args.requestheader + + reasons = {'Not modified': 'Not Modified'} # python 2.4 + +@@ -31,6 +40,10 @@ + if tag: + headers['If-None-Match'] = tag + ++ for header in requestheaders: ++ key, value = header.split('=', 1) ++ headers[key] = value ++ + conn = httplib.HTTPConnection(host) + conn.request("GET", '/' + path, None, headers) + response = conn.getresponse() +@@ -44,16 +57,22 @@ + if not headeronly: + print + data = response.read() +- sys.stdout.write(data) ++ if args.bodyfile: ++ bodyfh = open(args.bodyfile, 'wb') ++ else: ++ bodyfh = sys.stdout ++ bodyfh.write(data) + + if twice and response.getheader('ETag', None): + tag = response.getheader('ETag') + ++ if args.bodyfile: ++ bodyfh.close() + return response.status + +-status = request(sys.argv[1], sys.argv[2], sys.argv[3:]) ++status = request(args.host, args.path, args.show) + if twice: +- status = request(sys.argv[1], sys.argv[2], sys.argv[3:]) ++ status = request(args.host, args.path, args.show) + + if 200 <= status <= 305: + sys.exit(0) +diff -r cceaf7af4c9e tests/killdaemons.py +--- a/tests/killdaemons.py Sat Jun 01 17:09:41 2013 -0500 ++++ b/tests/killdaemons.py Tue Jul 03 11:25:06 2018 +0200 +@@ -49,6 +49,10 @@ + pass + + if __name__ == '__main__': +- path, = sys.argv[1:] ++ if len(sys.argv) > 1: ++ path, = sys.argv[1:] ++ else: ++ path = os.environ["DAEMON_PIDS"] ++ + killdaemons(path) + +diff -r cceaf7af4c9e tests/run-tests.py +--- a/tests/run-tests.py Sat Jun 01 17:09:41 2013 -0500 ++++ b/tests/run-tests.py Tue Jul 03 11:25:06 2018 +0200 +@@ -1321,6 +1321,7 @@ + os.environ["HGPORT"] = str(options.port) + os.environ["HGPORT1"] = str(options.port + 1) + os.environ["HGPORT2"] = str(options.port + 2) ++ os.environ["LOCALIP"] = '127.0.0.1' + + if options.with_hg: + INST = None +diff -r cceaf7af4c9e tests/test-http-permissions.t +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/tests/test-http-permissions.t Tue Jul 03 11:25:06 2018 +0200 +@@ -0,0 +1,1491 @@ ++#require killdaemons ++ ++ $ cat > fakeremoteuser.py << EOF ++ > import os ++ > from mercurial.hgweb import hgweb_mod ++ > from mercurial import wireproto ++ > class testenvhgweb(hgweb_mod.hgweb): ++ > def __call__(self, env, respond): ++ > # Allow REMOTE_USER to define authenticated user. ++ > if r'REMOTE_USER' in os.environ: ++ > env[r'REMOTE_USER'] = os.environ[r'REMOTE_USER'] ++ > # Allow REQUEST_METHOD to override HTTP method ++ > if r'REQUEST_METHOD' in os.environ: ++ > env[r'REQUEST_METHOD'] = os.environ[r'REQUEST_METHOD'] ++ > return super(testenvhgweb, self).__call__(env, respond) ++ > hgweb_mod.hgweb = testenvhgweb ++ > ++ > @wireproto.wireprotocommand('customreadnoperm') ++ > def customread(repo, proto): ++ > return b'read-only command no defined permissions\n' ++ > @wireproto.wireprotocommand('customwritenoperm') ++ > def customwritenoperm(repo, proto): ++ > return b'write command no defined permissions\n' ++ > wireproto.permissions['customreadwithperm'] = 'pull' ++ > @wireproto.wireprotocommand('customreadwithperm') ++ > def customreadwithperm(repo, proto): ++ > return b'read-only command w/ defined permissions\n' ++ > wireproto.permissions['customwritewithperm'] = 'push' ++ > @wireproto.wireprotocommand('customwritewithperm') ++ > def customwritewithperm(repo, proto): ++ > return b'write command w/ defined permissions\n' ++ > EOF ++ ++ $ cat >> $HGRCPATH << EOF ++ > [extensions] ++ > fakeremoteuser = $TESTTMP/fakeremoteuser.py ++ > EOF ++ ++ $ hg init test ++ $ cd test ++ $ echo a > a ++ $ hg ci -Ama ++ adding a ++ $ cd .. ++ $ hg clone test test2 ++ updating to branch default ++ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved ++ $ cd test2 ++ $ echo a >> a ++ $ hg ci -mb ++ $ hg book bm -r 0 ++ $ cd ../test ++ ++web.deny_read=* prevents access to wire protocol for all users ++ ++ $ cat > .hg/hgrc < [web] ++ > deny_read = * ++ > EOF ++ ++ $ hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=capabilities' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=stream_out' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ hg --cwd ../test2 pull http://localhost:$HGPORT/ ++ abort: authorization failed ++ [255] ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++web.deny_read=* with REMOTE_USER set still locks out clients ++ ++ $ REMOTE_USER=authed_user hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=capabilities' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=stream_out' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ hg --cwd ../test2 pull http://localhost:$HGPORT/ ++ abort: authorization failed ++ [255] ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++web.deny_read= denies access to unauthenticated user ++ ++ $ cat > .hg/hgrc < [web] ++ > deny_read = baduser1,baduser2 ++ > EOF ++ ++ $ hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ hg --cwd ../test2 pull http://localhost:$HGPORT/ ++ abort: authorization failed ++ [255] ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++web.deny_read= denies access to users in deny list ++ ++ $ REMOTE_USER=baduser2 hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ hg --cwd ../test2 pull http://localhost:$HGPORT/ ++ abort: authorization failed ++ [255] ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++web.deny_read= allows access to authenticated users not in list ++ ++ $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases' ++ 200 Script output follows ++ ++ cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1 ++ publishing True (no-eol) ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' ++ 200 Script output follows ++ ++ cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1 ++ publishing True (no-eol) ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm' ++ 200 Script output follows ++ ++ read-only command w/ defined permissions ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ hg --cwd ../test2 pull http://localhost:$HGPORT/ ++ pulling from http://localhost:$HGPORT/ ++ searching for changes ++ no changes found ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++web.allow_read=* allows reads for unauthenticated users ++ ++ $ cat > .hg/hgrc < [web] ++ > allow_read = * ++ > EOF ++ ++ $ hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases' ++ 200 Script output follows ++ ++ cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1 ++ publishing True (no-eol) ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' ++ 200 Script output follows ++ ++ cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1 ++ publishing True (no-eol) ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm' ++ 200 Script output follows ++ ++ read-only command w/ defined permissions ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ hg --cwd ../test2 pull http://localhost:$HGPORT/ ++ pulling from http://localhost:$HGPORT/ ++ searching for changes ++ no changes found ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++web.allow_read=* allows read for authenticated user ++ ++ $ REMOTE_USER=authed_user hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases' ++ 200 Script output follows ++ ++ cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1 ++ publishing True (no-eol) ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' ++ 200 Script output follows ++ ++ cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1 ++ publishing True (no-eol) ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm' ++ 200 Script output follows ++ ++ read-only command w/ defined permissions ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ hg --cwd ../test2 pull http://localhost:$HGPORT/ ++ pulling from http://localhost:$HGPORT/ ++ searching for changes ++ no changes found ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++web.allow_read= does not allow unauthenticated users to read ++ ++ $ cat > .hg/hgrc < [web] ++ > allow_read = gooduser ++ > EOF ++ ++ $ hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ hg --cwd ../test2 pull http://localhost:$HGPORT/ ++ abort: authorization failed ++ [255] ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++web.allow_read= does not allow user not in list to read ++ ++ $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ hg --cwd ../test2 pull http://localhost:$HGPORT/ ++ abort: authorization failed ++ [255] ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++web.allow_read= allows read from user in list ++ ++ $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases' ++ 200 Script output follows ++ ++ cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1 ++ publishing True (no-eol) ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' ++ 200 Script output follows ++ ++ cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1 ++ publishing True (no-eol) ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm' ++ 200 Script output follows ++ ++ read-only command w/ defined permissions ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ hg --cwd ../test2 pull http://localhost:$HGPORT/ ++ pulling from http://localhost:$HGPORT/ ++ searching for changes ++ no changes found ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++web.deny_read takes precedence over web.allow_read ++ ++ $ cat > .hg/hgrc < [web] ++ > allow_read = baduser ++ > deny_read = baduser ++ > EOF ++ ++ $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ hg --cwd ../test2 pull http://localhost:$HGPORT/ ++ abort: authorization failed ++ [255] ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++web.allowpull=false denies read access to repo ++ ++ $ cat > .hg/hgrc < [web] ++ > allowpull = false ++ > EOF ++ ++ $ hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=capabilities' ++ 401 pull not authorized ++ ++ 0 ++ pull not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases' ++ 401 pull not authorized ++ ++ 0 ++ pull not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases' ++ 401 pull not authorized ++ ++ 0 ++ pull not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm' ++ 401 pull not authorized ++ ++ 0 ++ pull not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ hg --cwd ../test2 pull http://localhost:$HGPORT/ ++ abort: authorization failed ++ [255] ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++Attempting a write command with HTTP GET fails ++ ++ $ cat > .hg/hgrc < EOF ++ ++ $ REQUEST_METHOD=GET hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ hg bookmarks ++ no bookmarks set ++ $ hg bookmark -d bm ++ abort: bookmark 'bm' does not exist ++ [255] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++Attempting a write command with an unknown HTTP verb fails ++ ++ $ REQUEST_METHOD=someverb hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ hg bookmarks ++ no bookmarks set ++ $ hg bookmark -d bm ++ abort: bookmark 'bm' does not exist ++ [255] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 405 push requires POST request ++ ++ 0 ++ push requires POST request ++ [1] ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++Pushing on a plaintext channel is disabled by default ++ ++ $ cat > .hg/hgrc < EOF ++ ++ $ REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 200 ssl required ++ ++ 0 ++ ssl required ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 200 ssl required ++ ++ 0 ++ ssl required ++ ++ $ hg bookmarks ++ no bookmarks set ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 200 ssl required ++ ++ 0 ++ ssl required ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 200 ssl required ++ ++ 0 ++ ssl required ++ ++Reset server to remove REQUEST_METHOD hack to test hg client ++ ++ $ "$TESTDIR/killdaemons.py" ++ $ hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/ ++ pushing to http://localhost:$HGPORT/ ++ searching for changes ++ no changes found ++ exporting bookmark bm ++ remote: ssl required ++ updating bookmark bm failed! ++ [1] ++ ++ $ hg --cwd ../test2 push http://localhost:$HGPORT/ ++ pushing to http://localhost:$HGPORT/ ++ searching for changes ++ remote: ssl required ++ remote: ssl required ++ updating cb9a9f314b8b to public failed! ++ [1] ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++web.deny_push=* denies pushing to unauthenticated users ++ ++ $ cat > .hg/hgrc < [web] ++ > push_ssl = false ++ > deny_push = * ++ > EOF ++ ++ $ REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++ $ hg bookmarks ++ no bookmarks set ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++Reset server to remove REQUEST_METHOD hack to test hg client ++ ++ $ "$TESTDIR/killdaemons.py" ++ $ hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/ ++ pushing to http://localhost:$HGPORT/ ++ searching for changes ++ no changes found ++ exporting bookmark bm ++ abort: authorization failed ++ [255] ++ ++ $ hg --cwd ../test2 push http://localhost:$HGPORT/ ++ pushing to http://localhost:$HGPORT/ ++ searching for changes ++ abort: authorization failed ++ [255] ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++web.deny_push=* denies pushing to authenticated users ++ ++ $ REMOTE_USER=someuser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++ $ hg bookmarks ++ no bookmarks set ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++Reset server to remove REQUEST_METHOD hack to test hg client ++ ++ $ "$TESTDIR/killdaemons.py" ++ $ REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/ ++ pushing to http://localhost:$HGPORT/ ++ searching for changes ++ no changes found ++ exporting bookmark bm ++ abort: authorization failed ++ [255] ++ ++ $ hg --cwd ../test2 push http://localhost:$HGPORT/ ++ pushing to http://localhost:$HGPORT/ ++ searching for changes ++ abort: authorization failed ++ [255] ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++web.deny_push= denies pushing to user in list ++ ++ $ cat > .hg/hgrc < [web] ++ > push_ssl = false ++ > deny_push = baduser ++ > EOF ++ ++ $ REMOTE_USER=baduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++ $ hg bookmarks ++ no bookmarks set ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++Reset server to remove REQUEST_METHOD hack to test hg client ++ ++ $ "$TESTDIR/killdaemons.py" ++ $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/ ++ pushing to http://localhost:$HGPORT/ ++ searching for changes ++ no changes found ++ exporting bookmark bm ++ abort: authorization failed ++ [255] ++ ++ $ hg --cwd ../test2 push http://localhost:$HGPORT/ ++ pushing to http://localhost:$HGPORT/ ++ searching for changes ++ abort: authorization failed ++ [255] ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++web.deny_push= denies pushing to user not in list because allow_push isn't set ++ ++ $ REMOTE_USER=gooduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++ $ hg bookmarks ++ no bookmarks set ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++Reset server to remove REQUEST_METHOD hack to test hg client ++ ++ $ "$TESTDIR/killdaemons.py" ++ $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/ ++ pushing to http://localhost:$HGPORT/ ++ searching for changes ++ no changes found ++ exporting bookmark bm ++ abort: authorization failed ++ [255] ++ ++ $ hg --cwd ../test2 push http://localhost:$HGPORT/ ++ pushing to http://localhost:$HGPORT/ ++ searching for changes ++ abort: authorization failed ++ [255] ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++web.allow_push=* allows pushes from unauthenticated users ++ ++ $ cat > .hg/hgrc < [web] ++ > push_ssl = false ++ > allow_push = * ++ > EOF ++ ++ $ REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 200 Script output follows ++ ++ 1 ++ ++ $ hg bookmarks ++ bm 0:cb9a9f314b8b ++ $ hg book -d bm ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 200 Script output follows ++ ++ write command no defined permissions ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 200 Script output follows ++ ++ write command w/ defined permissions ++ ++Reset server to remove REQUEST_METHOD hack to test hg client ++ ++ $ "$TESTDIR/killdaemons.py" ++ $ hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/ ++ pushing to http://localhost:$HGPORT/ ++ searching for changes ++ no changes found ++ exporting bookmark bm ++ [1] ++ ++ $ hg book -d bm ++ ++ $ hg --cwd ../test2 push http://localhost:$HGPORT/ ++ pushing to http://localhost:$HGPORT/ ++ searching for changes ++ remote: adding changesets ++ remote: adding manifests ++ remote: adding file changes ++ remote: added 1 changesets with 1 changes to 1 files ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++web.allow_push=* allows pushes from authenticated users ++ ++ $ REMOTE_USER=someuser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 200 Script output follows ++ ++ 1 ++ ++ $ hg bookmarks ++ bm 0:cb9a9f314b8b ++ $ hg book -d bm ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 200 Script output follows ++ ++ write command no defined permissions ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 200 Script output follows ++ ++ write command w/ defined permissions ++ ++Reset server to remove REQUEST_METHOD hack to test hg client ++ ++ $ "$TESTDIR/killdaemons.py" ++ $ cd .. ++ $ rm -rf test2 ++ $ hg clone test test2 ++ updating to branch default ++ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved ++ $ cd test2 ++ $ echo a >> a ++ $ hg ci -mb ++ $ hg book bm -r 0 ++ $ cd ../test ++ $ REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/ ++ pushing to http://localhost:$HGPORT/ ++ searching for changes ++ no changes found ++ exporting bookmark bm ++ [1] ++ ++ $ hg book -d bm ++ ++ $ hg --cwd ../test2 push http://localhost:$HGPORT/ ++ pushing to http://localhost:$HGPORT/ ++ searching for changes ++ remote: adding changesets ++ remote: adding manifests ++ remote: adding file changes ++ remote: added 1 changesets with 1 changes to 1 files ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++web.allow_push= denies push to user not in list ++ ++ $ cat > .hg/hgrc < [web] ++ > push_ssl = false ++ > allow_push = gooduser ++ > EOF ++ ++ $ REMOTE_USER=baduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++ $ hg bookmarks ++ no bookmarks set ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++Reset server to remove REQUEST_METHOD hack to test hg client ++ ++ $ "$TESTDIR/killdaemons.py" ++ $ cd .. ++ $ rm -rf test2 ++ $ hg clone test test2 ++ updating to branch default ++ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved ++ $ cd test2 ++ $ echo a >> a ++ $ hg ci -mb ++ $ hg book bm -r 0 ++ $ cd ../test ++ $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/ ++ pushing to http://localhost:$HGPORT/ ++ searching for changes ++ no changes found ++ exporting bookmark bm ++ abort: authorization failed ++ [255] ++ ++ $ hg --cwd ../test2 push http://localhost:$HGPORT/ ++ pushing to http://localhost:$HGPORT/ ++ searching for changes ++ abort: authorization failed ++ [255] ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++web.allow_push= allows push from user in list ++ ++ $ REMOTE_USER=gooduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 200 Script output follows ++ ++ 1 ++ ++ $ hg bookmarks ++ bm 0:cb9a9f314b8b ++ $ hg book -d bm ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 200 Script output follows ++ ++ 1 ++ ++ $ hg bookmarks ++ bm 0:cb9a9f314b8b ++ $ hg book -d bm ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 200 Script output follows ++ ++ write command no defined permissions ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 200 Script output follows ++ ++ write command w/ defined permissions ++ ++Reset server to remove REQUEST_METHOD hack to test hg client ++ ++ $ "$TESTDIR/killdaemons.py" ++ $ cd .. ++ $ rm -rf test2 ++ $ hg clone test test2 ++ updating to branch default ++ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved ++ $ cd test2 ++ $ echo a >> a ++ $ hg ci -mb ++ $ hg book bm -r 0 ++ $ cd ../test ++ $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/ ++ pushing to http://localhost:$HGPORT/ ++ searching for changes ++ no changes found ++ exporting bookmark bm ++ [1] ++ ++ $ hg book -d bm ++ ++ $ hg --cwd ../test2 push http://localhost:$HGPORT/ ++ pushing to http://localhost:$HGPORT/ ++ searching for changes ++ remote: adding changesets ++ remote: adding manifests ++ remote: adding file changes ++ remote: added 1 changesets with 1 changes to 1 files ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++web.deny_push takes precedence over web.allow_push ++ ++ $ cat > .hg/hgrc < [web] ++ > push_ssl = false ++ > allow_push = someuser ++ > deny_push = someuser ++ > EOF ++ ++ $ REMOTE_USER=someuser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++ $ hg bookmarks ++ no bookmarks set ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm' ++ 401 push not authorized ++ ++ 0 ++ push not authorized ++ [1] ++ ++Reset server to remove REQUEST_METHOD hack to test hg client ++ ++ $ "$TESTDIR/killdaemons.py" ++ $ cd .. ++ $ rm -rf test2 ++ $ hg clone test test2 ++ updating to branch default ++ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved ++ $ cd test2 ++ $ echo a >> a ++ $ hg ci -mb ++ $ hg book bm -r 0 ++ $ cd ../test ++ $ REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/ ++ pushing to http://localhost:$HGPORT/ ++ searching for changes ++ no changes found ++ exporting bookmark bm ++ abort: authorization failed ++ [255] ++ ++ $ hg --cwd ../test2 push http://localhost:$HGPORT/ ++ pushing to http://localhost:$HGPORT/ ++ searching for changes ++ abort: authorization failed ++ [255] ++ ++ $ "$TESTDIR/killdaemons.py" ++ ++web.allow_push has no effect if web.deny_read is set ++ ++ $ cat > .hg/hgrc < [web] ++ > push_ssl = false ++ > allow_push = * ++ > deny_read = * ++ > EOF ++ ++ $ REQUEST_METHOD=POST REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid ++ $ cat hg.pid > $DAEMON_PIDS ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] ++ ++ $ hg bookmarks ++ no bookmarks set ++ ++ $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm' ++ 401 read not authorized ++ ++ 0 ++ read not authorized ++ [1] +diff -r cceaf7af4c9e tests/test-pull-http.t +--- a/tests/test-pull-http.t Sat Jun 01 17:09:41 2013 -0500 ++++ b/tests/test-pull-http.t Tue Jul 03 11:25:06 2018 +0200 +@@ -37,7 +37,6 @@ + $ hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log + $ cat hg.pid >> $DAEMON_PIDS + $ hg clone http://localhost:$HGPORT/ test4 +- requesting all changes + abort: authorization failed + [255] + $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS +@@ -57,7 +56,6 @@ + expect error, pulling not allowed + + $ req +- pulling from http://localhost:$HGPORT/ + abort: authorization failed + % serve errors + diff --git a/SOURCES/mercurial-cve-2018-13346-cve-2018-13347.patch b/SOURCES/mercurial-cve-2018-13346-cve-2018-13347.patch new file mode 100644 index 0000000..a54175b --- /dev/null +++ b/SOURCES/mercurial-cve-2018-13346-cve-2018-13347.patch @@ -0,0 +1,202 @@ +diff -ru mercurial-2.6.2/mercurial/mpatch.c mercurial-2.6.2_patched/mercurial/mpatch.c +--- mercurial-2.6.2/mercurial/mpatch.c 2013-06-02 00:10:16.000000000 +0200 ++++ mercurial-2.6.2_patched/mercurial/mpatch.c 2019-05-07 16:51:13.631774481 +0200 +@@ -74,6 +74,35 @@ + return a->tail - a->head; + } + ++/* add helper to add src and *dest iff it won't overflow */ ++static inline int safeadd(int src, int *dest) ++{ ++ if ((src > 0) == (*dest > 0)) { ++ if (*dest > 0) { ++ if (src > (INT_MAX - *dest)) { ++ return 0; ++ } ++ } else { ++ if (src < (INT_MIN - *dest)) { ++ return 0; ++ } ++ } ++ } ++ *dest += src; ++ return 1; ++} ++ ++/* subtract src from dest and store result in dest */ ++static inline int safesub(int src, int *dest) ++{ ++ if (((src > 0) && (*dest < INT_MIN + src)) || ++ ((src < 0) && (*dest > INT_MAX + src))) { ++ return 0; ++ } ++ *dest -= src; ++ return 1; ++} ++ + /* move hunks in source that are less cut to dest, compensating + for changes in offset. the last hunk may be split if necessary. + */ +@@ -83,18 +112,37 @@ + int postend, c, l; + + while (s != src->tail) { +- if (s->start + offset >= cut) ++ int soffset = s->start; ++ if (!safeadd(offset, &soffset)) ++ break; /* add would overflow, oh well */ ++ if (soffset >= cut) + break; /* we've gone far enough */ + +- postend = offset + s->start + s->len; ++ postend = offset; ++ if (!safeadd(s->start, &postend) || ++ !safeadd(s->len, &postend)) { ++ break; ++ } + if (postend <= cut) { + /* save this hunk */ +- offset += s->start + s->len - s->end; ++ int tmp = s->start; ++ if (!safesub(s->end, &tmp)) { ++ break; ++ } ++ if (!safeadd(s->len, &tmp)) { ++ break; ++ } ++ if (!safeadd(tmp, &offset)) { ++ break; /* add would overflow, oh well */ ++ } + *d++ = *s++; + } + else { + /* break up this hunk */ +- c = cut - offset; ++ c = cut; ++ if (!safesub(offset, &c)) { ++ break; ++ } + if (s->end < c) + c = s->end; + l = cut - offset - s->start; +@@ -128,16 +176,40 @@ + int postend, c, l; + + while (s != src->tail) { +- if (s->start + offset >= cut) ++ int cmpcut = s->start; ++ if (!safeadd(offset, &cmpcut)) { ++ break; ++ } ++ if (cmpcut >= cut) + break; + +- postend = offset + s->start + s->len; ++ postend = offset; ++ if (!safeadd(s->start, &postend)) { ++ break; ++ } ++ if (!safeadd(s->len, &postend)) { ++ break; ++ } + if (postend <= cut) { +- offset += s->start + s->len - s->end; ++ /* do the subtraction first to avoid UB integer overflow ++ */ ++ int tmp = s->start; ++ if (!safesub(s->end, &tmp)) { ++ break; ++ } ++ if (!safeadd(s->len, &tmp)) { ++ break; ++ } ++ if (!safeadd(tmp, &offset)) { ++ break; ++ } + s++; + } + else { +- c = cut - offset; ++ c = cut; ++ if (!safesub(offset, &c)) { ++ break; ++ } + if (s->end < c) + c = s->end; + l = cut - offset - s->start; +@@ -179,8 +251,18 @@ + + /* insert new hunk */ + ct = c->tail; +- ct->start = bh->start - offset; +- ct->end = bh->end - post; ++ ct->start = bh->start; ++ ct->end = bh->end; ++ if (!safesub(offset, &(ct->start)) || ++ !safesub(post, &(ct->end))) { ++ /* It was already possible to exit ++ * this function with a return value ++ * of NULL before the safesub()s were ++ * added, so this should be fine. */ ++ lfree(c); ++ c = NULL; ++ goto done; ++ } + ct->len = bh->len; + ct->data = bh->data; + c->tail++; +@@ -191,7 +273,7 @@ + memcpy(c->tail, a->head, sizeof(struct frag) * lsize(a)); + c->tail += lsize(a); + } +- ++done: + lfree(a); + lfree(b); + return c; +@@ -215,13 +297,17 @@ + lt->start = getbe32(bin); + lt->end = getbe32(bin + 4); + lt->len = getbe32(bin + 8); +- if (lt->start > lt->end) +- break; /* sanity check */ +- bin = data + lt->len; +- if (bin < data) ++ if (lt->start < 0 || lt->start > lt->end || lt->len < 0) ++ break; /* sanity check */ ++ bin = data; ++ if (!safeadd(lt->len, &bin)) { + break; /* big data + big (bogus) len can wrap around */ ++ } + lt->data = data; +- data = bin + 12; ++ data = bin; ++ if (!safeadd(12, &data)) { ++ break; ++ } + lt++; + } + +@@ -266,7 +352,8 @@ + char *p = buf; + + while (f != l->tail) { +- if (f->start < last || f->end > len) { ++ if (f->start < last || f->start > len || f->end > len || ++ last < 0) { + if (!PyErr_Occurred()) + PyErr_SetString(mpatch_Error, + "invalid patch"); +@@ -279,6 +366,12 @@ + p += f->len; + f++; + } ++ if (last < 0) { ++ if (!PyErr_Occurred()) ++ PyErr_SetString(mpatch_Error, ++ "invalid patch"); ++ return 0; ++ } + memcpy(p, orig + last, len - last); + return 1; + } diff --git a/SPECS/mercurial.spec b/SPECS/mercurial.spec index 8b727f2..3b32409 100644 --- a/SPECS/mercurial.spec +++ b/SPECS/mercurial.spec @@ -3,7 +3,7 @@ Summary: Mercurial -- a distributed SCM Name: mercurial Version: 2.6.2 -Release: 8%{?dist} +Release: 10%{?dist} #Release: 1.rc1%{?dist} #%define upstreamversion %{version}-rc @@ -24,6 +24,8 @@ Patch3: mercurial-cve-2016-3068.patch Patch4: mercurial-cve-2016-3069.patch Patch5: mercurial-cve-2017-9462.patch Patch6: mercurial-cve-2017-1000115-1000116.patch +Patch7: mercurial-cve-2018-1000132.patch +Patch8: mercurial-cve-2018-13346-cve-2018-13347.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root BuildRequires: python python-devel @@ -99,6 +101,8 @@ documentation. %patch4 -p1 %patch5 -p1 %patch6 -p1 +%patch7 -p1 +%patch8 -p1 %build make all @@ -201,10 +205,18 @@ rm -rf $RPM_BUILD_ROOT %{_libexecdir}/mercurial/ %{_sysconfdir}/mercurial/hgrc.d/hgk.rc -##%%check -##cd tests && %{__python} run-tests.py +#%%check +#cd tests && %%{__python} run-tests.py %changelog +* Tue May 07 2019 Marcel Plch - 2.6.2-10 +- Add missing hunk for CVE-2018-13347 patch +- Related: CVE-2018-13347 + +* Wed Mar 20 2019 Marcel Plch - 2.6.2-9 +- Fix various CVE's +- Resolves: CVE-2018-1000132 CVE-2018-13346 CVE-2018-13347 + * Tue Aug 15 2017 Petr Stodulka - 2.6.2-8 - Fix CVE-2017-1000115 and CVE-2017-1000116