Patchwork [STABLE] server: ensure the incoming request falls under the prefix value

login
register
mail settings
Submitter Matt Harbison
Date April 2, 2018, 10:42 p.m.
Message ID <0d5e334fc39e821a2dcd.1522708934@Envy>
Download mbox | patch
Permalink /patch/30148/
State Accepted
Headers show

Comments

Matt Harbison - April 2, 2018, 10:42 p.m.
# HG changeset patch
# User Matt Harbison <matt_harbison@yahoo.com>
# Date 1522560438 14400
#      Sun Apr 01 01:27:18 2018 -0400
# Branch stable
# Node ID 0d5e334fc39e821a2dcd07db4d901adf37b4b80c
# Parent  177f3b90335fc49c23a8880de57dc865f0832849
server: ensure the incoming request falls under the prefix value

Prior to this, the first test asserted in wsgiref.validate.check_environ()
saying PATH didn't start with '/', but the second test served up the repo.  The
assertion was just added in this cycle (though the value of PATH is still wrong
without the assertion).  Allowing access to the repo at any URL outside of the
prefix is a long standing bug.  This also affected hgwebdir, atleast when used
via --subrepo.

Paths are not being canonicalized, so accesses to things like 'foo/../bar' will
get tossed out here, unless the prefix also matches.
Yuya Nishihara - April 3, 2018, 1:02 p.m.
On Mon, 02 Apr 2018 18:42:14 -0400, Matt Harbison wrote:
> # HG changeset patch
> # User Matt Harbison <matt_harbison@yahoo.com>
> # Date 1522560438 14400
> #      Sun Apr 01 01:27:18 2018 -0400
> # Branch stable
> # Node ID 0d5e334fc39e821a2dcd07db4d901adf37b4b80c
> # Parent  177f3b90335fc49c23a8880de57dc865f0832849
> server: ensure the incoming request falls under the prefix value

Queued for stable, thanks.

Patch

diff --git a/mercurial/hgweb/server.py b/mercurial/hgweb/server.py
--- a/mercurial/hgweb/server.py
+++ b/mercurial/hgweb/server.py
@@ -118,6 +118,14 @@  class _httprequesthandler(httpservermod.
         self.sent_headers = False
         path, query = _splitURI(self.path)
 
+        # Ensure the slicing of path below is valid
+        if (path != self.server.prefix
+            and not path.startswith(self.server.prefix + b'/')):
+            self._start_response(common.statusmessage(404), [])
+            self._write("Not Found")
+            self._done()
+            return
+
         env = {}
         env[r'GATEWAY_INTERFACE'] = r'CGI/1.1'
         env[r'REQUEST_METHOD'] = self.command
diff --git a/tests/test-serve.t b/tests/test-serve.t
--- a/tests/test-serve.t
+++ b/tests/test-serve.t
@@ -78,4 +78,24 @@  With --prefix /foo/
   listening at http://localhost/foo/ (bound to *$LOCALIP*:HGPORT1) (glob) (?)
   % errors
 
+  $ $PYTHON $RUNTESTDIR/killdaemons.py $DAEMON_PIDS
+
+With out of bounds accesses
+
+  $ rm access.log
+  $ hg serve -a localhost -p $HGPORT -d --prefix some/dir \
+  >    --pid-file=hg.pid -E errors.log
+  $ cat hg.pid >> "$DAEMON_PIDS"
+
+  $ hg id http://localhost:$HGPORT/some/dir7
+  abort: HTTP Error 404: Not Found
+  [255]
+  $ hg id http://localhost:$HGPORT/some
+  abort: HTTP Error 404: Not Found
+  [255]
+
+  $ cat access.log errors.log
+  $LOCALIP - - [$LOGDATE$] "GET /some/dir7?cmd=capabilities HTTP/1.1" 404 - (glob)
+  $LOCALIP - - [$LOGDATE$] "GET /some?cmd=capabilities HTTP/1.1" 404 - (glob)
+
   $ cd ..