Additional fixes for security related to CVE-2016-9587
(cherry picked from commit d316068831
)
This commit is contained in:
parent
eb8c26c105
commit
cc4634a5e7
2 changed files with 19 additions and 19 deletions
lib/ansible
|
@ -104,7 +104,7 @@ class Conditional:
|
||||||
if conditional is None or conditional == '':
|
if conditional is None or conditional == '':
|
||||||
return True
|
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]
|
conditional = all_vars[conditional]
|
||||||
|
|
||||||
# make sure the templar is using the variables specified with this method
|
# make sure the templar is using the variables specified with this method
|
||||||
|
@ -116,12 +116,12 @@ class Conditional:
|
||||||
return conditional
|
return conditional
|
||||||
|
|
||||||
# a Jinja2 evaluation that results in something Python can eval!
|
# a Jinja2 evaluation that results in something Python can eval!
|
||||||
if hasattr(conditional, '__UNSAFE__') and LOOKUP_REGEX.match(conditional):
|
disable_lookups = False
|
||||||
raise AnsibleError("The conditional '%s' contains variables which came from an unsafe " \
|
if hasattr(conditional, '__UNSAFE__'):
|
||||||
"source and also contains a lookup() call, failing conditional check" % conditional)
|
disable_lookups = True
|
||||||
|
|
||||||
presented = "{%% if %s %%} True {%% else %%} False {%% endif %%}" % conditional
|
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":
|
if val == "True":
|
||||||
return True
|
return True
|
||||||
elif val == "False":
|
elif val == "False":
|
||||||
|
|
|
@ -30,10 +30,8 @@ from numbers import Number
|
||||||
from jinja2 import Environment
|
from jinja2 import Environment
|
||||||
from jinja2.loaders import FileSystemLoader
|
from jinja2.loaders import FileSystemLoader
|
||||||
from jinja2.exceptions import TemplateSyntaxError, UndefinedError
|
from jinja2.exceptions import TemplateSyntaxError, UndefinedError
|
||||||
from jinja2.nodes import EvalContext
|
|
||||||
from jinja2.utils import concat as j2_concat
|
from jinja2.utils import concat as j2_concat
|
||||||
from jinja2.runtime import Context, StrictUndefined
|
from jinja2.runtime import Context, StrictUndefined
|
||||||
|
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.compat.six import string_types, text_type
|
from ansible.compat.six import string_types, text_type
|
||||||
from ansible.errors import AnsibleError, AnsibleFilterError, AnsibleUndefinedVariable
|
from ansible.errors import AnsibleError, AnsibleFilterError, AnsibleUndefinedVariable
|
||||||
|
@ -42,7 +40,6 @@ from ansible.template.safe_eval import safe_eval
|
||||||
from ansible.template.template import AnsibleJ2Template
|
from ansible.template.template import AnsibleJ2Template
|
||||||
from ansible.template.vars import AnsibleJ2Vars
|
from ansible.template.vars import AnsibleJ2Vars
|
||||||
from ansible.module_utils._text import to_native, to_text
|
from ansible.module_utils._text import to_native, to_text
|
||||||
from ansible.vars.unsafe_proxy import UnsafeProxy, wrap_var
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from hashlib import sha1
|
from hashlib import sha1
|
||||||
|
@ -127,13 +124,6 @@ def _count_newlines_from_end(in_str):
|
||||||
# Uncommon cases: zero length string and string containing only newlines
|
# Uncommon cases: zero length string and string containing only newlines
|
||||||
return i
|
return i
|
||||||
|
|
||||||
class AnsibleEvalContext(EvalContext):
|
|
||||||
'''
|
|
||||||
A custom jinja2 EvalContext, which is currently unused and saved
|
|
||||||
here for possible future use.
|
|
||||||
'''
|
|
||||||
pass
|
|
||||||
|
|
||||||
class AnsibleContext(Context):
|
class AnsibleContext(Context):
|
||||||
'''
|
'''
|
||||||
A custom context, which intercepts resolve() calls and sets a flag
|
A custom context, which intercepts resolve() calls and sets a flag
|
||||||
|
@ -143,7 +133,6 @@ class AnsibleContext(Context):
|
||||||
'''
|
'''
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(AnsibleContext, self).__init__(*args, **kwargs)
|
super(AnsibleContext, self).__init__(*args, **kwargs)
|
||||||
self.eval_ctx = AnsibleEvalContext(self.environment, self.name)
|
|
||||||
self.unsafe = False
|
self.unsafe = False
|
||||||
|
|
||||||
def _is_unsafe(self, val):
|
def _is_unsafe(self, val):
|
||||||
|
@ -335,7 +324,7 @@ class Templar:
|
||||||
self._available_variables = variables
|
self._available_variables = variables
|
||||||
self._cached_result = {}
|
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
|
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}}')
|
set to True, the given data will be wrapped as a jinja2 variable ('{{foo}}')
|
||||||
|
@ -391,6 +380,7 @@ class Templar:
|
||||||
escape_backslashes=escape_backslashes,
|
escape_backslashes=escape_backslashes,
|
||||||
fail_on_undefined=fail_on_undefined,
|
fail_on_undefined=fail_on_undefined,
|
||||||
overrides=overrides,
|
overrides=overrides,
|
||||||
|
disable_lookups=disable_lookups,
|
||||||
)
|
)
|
||||||
unsafe = hasattr(result, '__UNSAFE__')
|
unsafe = hasattr(result, '__UNSAFE__')
|
||||||
if convert_data and not self._no_type_regex.match(variable) and not unsafe:
|
if convert_data and not self._no_type_regex.match(variable) and not unsafe:
|
||||||
|
@ -401,6 +391,7 @@ class Templar:
|
||||||
if eval_results[1] is None:
|
if eval_results[1] is None:
|
||||||
result = eval_results[0]
|
result = eval_results[0]
|
||||||
if unsafe:
|
if unsafe:
|
||||||
|
from ansible.vars.unsafe_proxy import wrap_var
|
||||||
result = wrap_var(result)
|
result = wrap_var(result)
|
||||||
else:
|
else:
|
||||||
# FIXME: if the safe_eval raised an error, should we do something with it?
|
# FIXME: if the safe_eval raised an error, should we do something with it?
|
||||||
|
@ -482,6 +473,9 @@ class Templar:
|
||||||
'''
|
'''
|
||||||
return thing if thing is not None else ''
|
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):
|
def _lookup(self, name, *args, **kwargs):
|
||||||
instance = self._lookup_loader.get(name.lower(), loader=self._loader, templar=self)
|
instance = self._lookup_loader.get(name.lower(), loader=self._loader, templar=self)
|
||||||
|
|
||||||
|
@ -501,6 +495,7 @@ class Templar:
|
||||||
ran = None
|
ran = None
|
||||||
|
|
||||||
if ran:
|
if ran:
|
||||||
|
from ansible.vars.unsafe_proxy import UnsafeProxy, wrap_var
|
||||||
if wantlist:
|
if wantlist:
|
||||||
ran = wrap_var(ran)
|
ran = wrap_var(ran)
|
||||||
else:
|
else:
|
||||||
|
@ -516,7 +511,7 @@ class Templar:
|
||||||
else:
|
else:
|
||||||
raise AnsibleError("lookup plugin (%s) not found" % name)
|
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
|
# For preserving the number of input newlines in the output (used
|
||||||
# later in this method)
|
# later in this method)
|
||||||
data_newlines = _count_newlines_from_end(data)
|
data_newlines = _count_newlines_from_end(data)
|
||||||
|
@ -560,7 +555,11 @@ class Templar:
|
||||||
else:
|
else:
|
||||||
return data
|
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
|
t.globals['finalize'] = self._finalize
|
||||||
|
|
||||||
jvars = AnsibleJ2Vars(self, t.globals)
|
jvars = AnsibleJ2Vars(self, t.globals)
|
||||||
|
@ -571,6 +570,7 @@ class Templar:
|
||||||
try:
|
try:
|
||||||
res = j2_concat(rf)
|
res = j2_concat(rf)
|
||||||
if new_context.unsafe:
|
if new_context.unsafe:
|
||||||
|
from ansible.vars.unsafe_proxy import wrap_var
|
||||||
res = wrap_var(res)
|
res = wrap_var(res)
|
||||||
except TypeError as te:
|
except TypeError as te:
|
||||||
if 'StrictUndefined' in to_native(te):
|
if 'StrictUndefined' in to_native(te):
|
||||||
|
|
Loading…
Add table
Reference in a new issue