Skip to content

Commit

Permalink
When parsing json from untrusted sources, remove templating tags
Browse files Browse the repository at this point in the history
  • Loading branch information
jimi-c committed Jul 1, 2014
1 parent d36195a commit 3761bc1
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 19 deletions.
2 changes: 1 addition & 1 deletion lib/ansible/inventory/script.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def __init__(self, filename=C.DEFAULT_HOST_LIST):
def _parse(self, err):

all_hosts = {}
self.raw = utils.parse_json(self.data)
self.raw = utils.parse_json(self.data, from_remote=True)
all = Group('all')
groups = dict(all=all)
group = None
Expand Down
2 changes: 1 addition & 1 deletion lib/ansible/runner/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ def _execute_module(self, conn, tmp, module_name, args,
cmd2 = "rm -rf %s >/dev/null 2>&1" % tmp
self._low_level_exec_command(conn, cmd2, tmp, sudoable=False)

data = utils.parse_json(res['stdout'])
data = utils.parse_json(res['stdout'], from_remote=True)
if 'parsed' in data and data['parsed'] == False:
data['msg'] += res['stderr']
return ReturnData(conn=conn, result=data)
Expand Down
3 changes: 1 addition & 2 deletions lib/ansible/runner/return_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ def __init__(self, conn=None, host=None, result=None,
self.diff = diff

if type(self.result) in [ str, unicode ]:
self.result = utils.parse_json(self.result)

self.result = utils.parse_json(self.result, from_remote=True)

if self.host is None:
raise Exception("host not set")
Expand Down
42 changes: 38 additions & 4 deletions lib/ansible/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,38 @@ def json_loads(data):

return json.loads(data)

def parse_json(raw_data):
def _clean_data(orig_data):
''' remove template tags from a string '''
data = orig_data
if isinstance(orig_data, basestring):
for pattern,replacement in (('{{','{#'), ('}}','#}'), ('{%','{#'), ('%}','#}')):
data = data.replace(pattern, replacement)
return data

def _clean_data_struct(orig_data):
'''
walk a complex data structure, and use _clean_data() to
remove any template tags that may exist
'''
if isinstance(orig_data, dict):
data = orig_data.copy()
for key in data:
new_key = _clean_data_struct(key)
new_val = _clean_data_struct(data[key])
if key != new_key:
del data[key]
data[new_key] = new_val
elif isinstance(orig_data, list):
data = orig_data[:]
for i in range(0, len(data)):
data[i] = _clean_data_struct(data[i])
elif isinstance(orig_data, basestring):
data = _clean_data(orig_data)
else:
data = orig_data
return data

def parse_json(raw_data, from_remote=False):
''' this version for module return data only '''

orig_data = raw_data
Expand All @@ -322,7 +353,7 @@ def parse_json(raw_data):
data = filter_leading_non_json_lines(raw_data)

try:
return json.loads(data)
results = json.loads(data)
except:
# not JSON, but try "Baby JSON" which allows many of our modules to not
# require JSON and makes writing modules in bash much simpler
Expand All @@ -332,7 +363,6 @@ def parse_json(raw_data):
except:
print "failed to parse json: "+ data
raise

for t in tokens:
if "=" not in t:
raise errors.AnsibleError("failed to parse: %s" % orig_data)
Expand All @@ -347,7 +377,11 @@ def parse_json(raw_data):
results[key] = value
if len(results.keys()) == 0:
return { "failed" : True, "parsed" : False, "msg" : orig_data }
return results

if from_remote:
results = _clean_data_struct(results)

return results

def smush_braces(data):
''' smush Jinaj2 braces so unresolved templates like {{ foo }} don't get parsed weird by key=value code '''
Expand Down
11 changes: 0 additions & 11 deletions lib/ansible/utils/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ class Flags:

FILTER_PLUGINS = None
_LISTRE = re.compile(r"(\w+)\[(\d+)\]")
JINJA2_OVERRIDE='#jinja2:'

def lookup(name, *args, **kwargs):
from ansible import utils
Expand Down Expand Up @@ -228,16 +227,6 @@ def my_finalize(thing):
except:
raise errors.AnsibleError("unable to read %s" % realpath)


# Get jinja env overrides from template
if data.startswith(JINJA2_OVERRIDE):
eol = data.find('\n')
line = data[len(JINJA2_OVERRIDE):eol]
data = data[eol+1:]
for pair in line.split(','):
(key,val) = pair.split(':')
setattr(environment,key.strip(),ast.literal_eval(val.strip()))

environment.template_class = J2Template
try:
t = environment.from_string(data)
Expand Down

0 comments on commit 3761bc1

Please sign in to comment.