--- a/mercurial/revset.py Mon May 21 14:24:24 2012 -0500
+++ b/mercurial/revset.py Sat May 19 17:18:29 2012 +0200
@@ -1283,6 +1283,27 @@
return w + wa, (op, x[1], ta)
return 1, x
+_aliasarg = ('func', ('symbol', '_aliasarg'))
+def _getaliasarg(tree):
+ """If tree matches ('func', ('symbol', '_aliasarg'), ('string', X))
+ return X, None otherwise.
+ """
+ if (len(tree) == 3 and tree[:2] == _aliasarg
+ and tree[2][0] == 'string'):
+ return tree[2][1]
+ return None
+
+def _checkaliasarg(tree, known=None):
+ """Check tree contains no _aliasarg construct or only ones which
+ value is in known. Used to avoid alias placeholders injection.
+ """
+ if isinstance(tree, tuple):
+ arg = _getaliasarg(tree)
+ if arg is not None and (not known or arg not in known):
+ raise error.ParseError(_("not a function: %s") % '_aliasarg')
+ for t in tree:
+ _checkaliasarg(t, known)
+
class revsetalias(object):
funcre = re.compile('^([^(]+)\(([^)]+)\)$')
args = None
@@ -1299,7 +1320,9 @@
self.tree = ('func', ('symbol', m.group(1)))
self.args = [x.strip() for x in m.group(2).split(',')]
for arg in self.args:
- value = value.replace(arg, repr(arg))
+ # _aliasarg() is an unknown symbol only used separate
+ # alias argument placeholders from regular strings.
+ value = value.replace(arg, '_aliasarg(%r)' % (arg,))
else:
self.name = name
self.tree = ('symbol', name)
@@ -1307,6 +1330,8 @@
self.replacement, pos = parse(value)
if pos != len(value):
raise error.ParseError(_('invalid token'), pos)
+ # Check for placeholder injection
+ _checkaliasarg(self.replacement, self.args)
def _getalias(aliases, tree):
"""If tree looks like an unexpanded alias, return it. Return None
@@ -1327,13 +1352,14 @@
return None
def _expandargs(tree, args):
- """Replace all occurences of ('string', name) with the
- substitution value of the same name in args, recursively.
+ """Replace _aliasarg instances with the substitution value of the
+ same name in args, recursively.
"""
- if not isinstance(tree, tuple):
+ if not tree or not isinstance(tree, tuple):
return tree
- if len(tree) == 2 and tree[0] == 'string':
- return args.get(tree[1], tree)
+ arg = _getaliasarg(tree)
+ if arg is not None:
+ return args[arg]
return tuple(_expandargs(t, args) for t in tree)
def _expandaliases(aliases, tree, expanding):
@@ -1367,6 +1393,7 @@
return result
def findaliases(ui, tree):
+ _checkaliasarg(tree)
aliases = {}
for k, v in ui.configitems('revsetalias'):
alias = revsetalias(k, v)