changeset 31793:62f9679df1f2

hgweb: extract path traversal checking into standalone function A common exploit in web applications that access paths is to insert path separator strings like ".." to try to get the server to serve up files it shouldn't. We have code for detecting this in staticfile(). A subsequent commit will need to perform this test as well. Since this is security code, let's factor the check so we don't have to reinvent the wheel.
author Gregory Szorc <gregory.szorc@gmail.com>
date Fri, 31 Mar 2017 21:47:26 -0700
parents 161a87ed456e
children 39f6333e968c
files mercurial/hgweb/common.py
diffstat 1 files changed, 15 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/hgweb/common.py	Fri Mar 31 22:30:38 2017 -0700
+++ b/mercurial/hgweb/common.py	Fri Mar 31 21:47:26 2017 -0700
@@ -135,6 +135,17 @@
 def get_mtime(spath):
     return get_stat(spath, "00changelog.i").st_mtime
 
+def ispathsafe(path):
+    """Determine if a path is safe to use for filesystem access."""
+    parts = path.split('/')
+    for part in parts:
+        if (part in ('', os.curdir, os.pardir) or
+            pycompat.ossep in part or
+            pycompat.osaltsep is not None and pycompat.osaltsep in part):
+            return False
+
+    return True
+
 def staticfile(directory, fname, req):
     """return a file inside directory with guessed Content-Type header
 
@@ -144,13 +155,10 @@
     Return an empty string if fname is illegal or file not found.
 
     """
-    parts = fname.split('/')
-    for part in parts:
-        if (part in ('', os.curdir, os.pardir) or
-            pycompat.ossep in part or
-            pycompat.osaltsep is not None and pycompat.osaltsep in part):
-            return
-    fpath = os.path.join(*parts)
+    if not ispathsafe(fname):
+        return
+
+    fpath = os.path.join(*fname.split('/'))
     if isinstance(directory, str):
         directory = [directory]
     for d in directory: