summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Cammarata <jimi@sngx.net>2017-01-10 16:54:00 -0600
committerJames Cammarata <jimi@sngx.net>2017-01-11 15:57:38 -0600
commit35480106e50489d8515465cad89ed83794c3d3f9 (patch)
treea03fd950261da7acae5dd85fb2b1295bd9117850
parent51559b0a51e7149b207d5db6f1bd85fe451e6dc2 (diff)
downloadansible-35480106e50489d8515465cad89ed83794c3d3f9.tar.gz
Additional fixes for security related to CVE-2016-9587
(cherry picked from commit d316068831f9e08ef96833200ec7df2132263966)
-rw-r--r--lib/ansible/playbook/conditional.py10
-rw-r--r--lib/ansible/template/__init__.py27
2 files changed, 19 insertions, 18 deletions
diff --git a/lib/ansible/playbook/conditional.py b/lib/ansible/playbook/conditional.py
index bf0da78c8a..e42036bebb 100644
--- a/lib/ansible/playbook/conditional.py
+++ b/lib/ansible/playbook/conditional.py
@@ -87,7 +87,7 @@ class Conditional:
if conditional is None or conditional == '':
return True
- if conditional in all_vars and '-' not in text_type(all_vars[conditional]):
+ if conditional in all_vars and re.match("^[_A-Za-z][_a-zA-Z0-9]*$", conditional):
conditional = all_vars[conditional]
# make sure the templar is using the variables specified with this method
@@ -99,12 +99,12 @@ class Conditional:
return conditional
# a Jinja2 evaluation that results in something Python can eval!
- if hasattr(conditional, '__UNSAFE__') and LOOKUP_REGEX.match(conditional):
- raise AnsibleError("The conditional '%s' contains variables which came from an unsafe " \
- "source and also contains a lookup() call, failing conditional check" % conditional)
+ disable_lookups = False
+ if hasattr(conditional, '__UNSAFE__'):
+ disable_lookups = True
presented = "{%% if %s %%} True {%% else %%} False {%% endif %%}" % conditional
- val = templar.template(presented).strip()
+ val = templar.template(presented, disable_lookups=disable_lookups).strip()
if val == "True":
return True
elif val == "False":
diff --git a/lib/ansible/template/__init__.py b/lib/ansible/template/__init__.py
index 9982535013..bfe375dc78 100644
--- a/lib/ansible/template/__init__.py
+++ b/lib/ansible/template/__init__.py
@@ -30,10 +30,8 @@ from ansible.compat.six import string_types, text_type, binary_type
from jinja2 import Environment
from jinja2.loaders import FileSystemLoader
from jinja2.exceptions import TemplateSyntaxError, UndefinedError
-from jinja2.nodes import EvalContext
from jinja2.utils import concat as j2_concat
from jinja2.runtime import Context, StrictUndefined
-
from ansible import constants as C
from ansible.errors import AnsibleError, AnsibleFilterError, AnsibleUndefinedVariable
from ansible.plugins import filter_loader, lookup_loader, test_loader
@@ -126,13 +124,6 @@ def _count_newlines_from_end(in_str):
# Uncommon cases: zero length string and string containing only newlines
return i
-class AnsibleEvalContext(EvalContext):
- '''
- A custom jinja2 EvalContext, which is currently unused and saved
- here for possible future use.
- '''
- pass
-
class AnsibleContext(Context):
'''
A custom context, which intercepts resolve() calls and sets a flag
@@ -142,7 +133,6 @@ class AnsibleContext(Context):
'''
def __init__(self, *args, **kwargs):
super(AnsibleContext, self).__init__(*args, **kwargs)
- self.eval_ctx = AnsibleEvalContext(self.environment, self.name)
self.unsafe = False
def _is_unsafe(self, val):
@@ -334,7 +324,7 @@ class Templar:
self._available_variables = variables
self._cached_result = {}
- def template(self, variable, convert_bare=False, preserve_trailing_newlines=True, escape_backslashes=True, fail_on_undefined=None, overrides=None, convert_data=True, static_vars = [''], cache = True, bare_deprecated=True):
+ def template(self, variable, convert_bare=False, preserve_trailing_newlines=True, escape_backslashes=True, fail_on_undefined=None, overrides=None, convert_data=True, static_vars = [''], cache = True, bare_deprecated=True, disable_lookups=False):
'''
Templates (possibly recursively) any given data as input. If convert_bare is
set to True, the given data will be wrapped as a jinja2 variable ('{{foo}}')
@@ -391,6 +381,7 @@ class Templar:
escape_backslashes=escape_backslashes,
fail_on_undefined=fail_on_undefined,
overrides=overrides,
+ disable_lookups=disable_lookups,
)
unsafe = hasattr(result, '__UNSAFE__')
if convert_data and not self._no_type_regex.match(variable) and not unsafe:
@@ -401,6 +392,7 @@ class Templar:
if eval_results[1] is None:
result = eval_results[0]
if unsafe:
+ from ansible.vars.unsafe_proxy import wrap_var
result = wrap_var(result)
else:
# FIXME: if the safe_eval raised an error, should we do something with it?
@@ -469,6 +461,9 @@ class Templar:
'''
return thing if thing is not None else ''
+ def _fail_lookup(self, name, *args, **kwargs):
+ raise AnsibleError("The lookup `%s` was found, however lookups were disabled from templating" % name)
+
def _lookup(self, name, *args, **kwargs):
instance = self._lookup_loader.get(name.lower(), loader=self._loader, templar=self)
@@ -488,6 +483,7 @@ class Templar:
ran = None
if ran:
+ from ansible.vars.unsafe_proxy import UnsafeProxy, wrap_var
if wantlist:
ran = wrap_var(ran)
else:
@@ -503,7 +499,7 @@ class Templar:
else:
raise AnsibleError("lookup plugin (%s) not found" % name)
- def _do_template(self, data, preserve_trailing_newlines=True, escape_backslashes=True, fail_on_undefined=None, overrides=None):
+ def _do_template(self, data, preserve_trailing_newlines=True, escape_backslashes=True, fail_on_undefined=None, overrides=None, disable_lookups=False):
# For preserving the number of input newlines in the output (used
# later in this method)
@@ -548,7 +544,11 @@ class Templar:
else:
return data
- t.globals['lookup'] = self._lookup
+ if disable_lookups:
+ t.globals['lookup'] = self._fail_lookup
+ else:
+ t.globals['lookup'] = self._lookup
+
t.globals['finalize'] = self._finalize
jvars = AnsibleJ2Vars(self, t.globals)
@@ -559,6 +559,7 @@ class Templar:
try:
res = j2_concat(rf)
if new_context.unsafe:
+ from ansible.vars.unsafe_proxy import wrap_var
res = wrap_var(res)
except TypeError as te:
if 'StrictUndefined' in to_str(te):