Skip to content

Commit

Permalink
Additional fixes for security related to CVE-2016-9587
Browse files Browse the repository at this point in the history
(cherry picked from commit d316068)
  • Loading branch information
jimi-c committed Jan 11, 2017
1 parent eb8c26c commit cc4634a
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 19 deletions.
10 changes: 5 additions & 5 deletions lib/ansible/playbook/conditional.py
Expand Up @@ -104,7 +104,7 @@ def _check_conditional(self, conditional, templar, all_vars):
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
Expand All @@ -116,12 +116,12 @@ def _check_conditional(self, conditional, templar, all_vars):
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":
Expand Down
28 changes: 14 additions & 14 deletions lib/ansible/template/__init__.py
Expand Up @@ -30,10 +30,8 @@
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.compat.six import string_types, text_type
from ansible.errors import AnsibleError, AnsibleFilterError, AnsibleUndefinedVariable
Expand All @@ -42,7 +40,6 @@
from ansible.template.template import AnsibleJ2Template
from ansible.template.vars import AnsibleJ2Vars
from ansible.module_utils._text import to_native, to_text
from ansible.vars.unsafe_proxy import UnsafeProxy, wrap_var

try:
from hashlib import sha1
Expand Down Expand Up @@ -127,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
Expand All @@ -143,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):
Expand Down Expand Up @@ -335,7 +324,7 @@ def set_available_variables(self, variables):
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}}')
Expand Down Expand Up @@ -391,6 +380,7 @@ def template(self, variable, convert_bare=False, preserve_trailing_newlines=True
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:
Expand All @@ -401,6 +391,7 @@ def template(self, variable, convert_bare=False, preserve_trailing_newlines=True
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?
Expand Down Expand Up @@ -482,6 +473,9 @@ def _finalize(self, thing):
'''
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)

Expand All @@ -501,6 +495,7 @@ def _lookup(self, name, *args, **kwargs):
ran = None

if ran:
from ansible.vars.unsafe_proxy import UnsafeProxy, wrap_var
if wantlist:
ran = wrap_var(ran)
else:
Expand All @@ -516,7 +511,7 @@ def _lookup(self, name, *args, **kwargs):
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)
data_newlines = _count_newlines_from_end(data)
Expand Down Expand Up @@ -560,7 +555,11 @@ def do_template(self, data, preserve_trailing_newlines=True, escape_backslashes=
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)
Expand All @@ -571,6 +570,7 @@ def do_template(self, data, preserve_trailing_newlines=True, escape_backslashes=
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_native(te):
Expand Down

0 comments on commit cc4634a

Please sign in to comment.