Validate paths before reading or writing files in repository or working dir.
Fixes security relevant
issue134.
--- a/mercurial/commands.py Fri Mar 03 13:41:12 2006 -0800
+++ b/mercurial/commands.py Sat Mar 04 19:01:45 2006 +0100
@@ -1014,7 +1014,7 @@
def debugancestor(ui, index, rev1, rev2):
"""find the ancestor revision of two revisions in a given index"""
- r = revlog.revlog(util.opener(os.getcwd()), index, "")
+ r = revlog.revlog(util.opener(os.getcwd(), audit=False), index, "")
a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
ui.write("%d:%s\n" % (r.rev(a), hex(a)))
@@ -1100,7 +1100,8 @@
def debugdata(ui, file_, rev):
"""dump the contents of an data file revision"""
- r = revlog.revlog(util.opener(os.getcwd()), file_[:-2] + ".i", file_)
+ r = revlog.revlog(util.opener(os.getcwd(), audit=False),
+ file_[:-2] + ".i", file_)
try:
ui.write(r.revision(r.lookup(rev)))
except KeyError:
@@ -1108,7 +1109,7 @@
def debugindex(ui, file_):
"""dump the contents of an index file"""
- r = revlog.revlog(util.opener(os.getcwd()), file_, "")
+ r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "")
ui.write(" rev offset length base linkrev" +
" nodeid p1 p2\n")
for i in range(r.count()):
@@ -1119,7 +1120,7 @@
def debugindexdot(ui, file_):
"""dump an index DAG as a .dot file"""
- r = revlog.revlog(util.opener(os.getcwd()), file_, "")
+ r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "")
ui.write("digraph G {\n")
for i in range(r.count()):
e = r.index[i]
--- a/mercurial/localrepo.py Fri Mar 03 13:41:12 2006 -0800
+++ b/mercurial/localrepo.py Sat Mar 04 19:01:45 2006 +0100
@@ -1679,6 +1679,7 @@
remove.sort()
for f in remove:
self.ui.note(_("removing %s\n") % f)
+ util.audit_path(f)
try:
util.unlink(self.wjoin(f))
except OSError, inst:
--- a/mercurial/util.py Fri Mar 03 13:41:12 2006 -0800
+++ b/mercurial/util.py Sat Mar 04 19:01:45 2006 +0100
@@ -363,7 +363,14 @@
else:
shutil.copy(src, dst)
-def opener(base):
+def audit_path(path):
+ """Abort if path contains dangerous components"""
+ parts = os.path.normcase(path).split(os.sep)
+ if (os.path.splitdrive(path)[0] or parts[0] in ('.hg', '')
+ or os.pardir in parts):
+ raise Abort(_("path contains illegal component: %s\n") % path)
+
+def opener(base, audit=True):
"""
return a function that opens files relative to base
@@ -371,6 +378,7 @@
remote file access from higher level code.
"""
p = base
+ audit_p = audit
def mktempcopy(name):
d, fn = os.path.split(name)
@@ -401,6 +409,8 @@
self.close()
def o(path, mode="r", text=False, atomic=False):
+ if audit_p:
+ audit_path(path)
f = os.path.join(p, path)
if not text: