Changeset View
Changeset View
Standalone View
Standalone View
sysutils/ansible/files/extra-patch-cc4634a
- This file was added.
Property | Old Value | New Value |
---|---|---|
fbsd:nokeywords | null | yes \ No newline at end of property |
svn:eol-style | null | native \ No newline at end of property |
svn:mime-type | null | text/plain \ No newline at end of property |
From cc4634a5e73c06c6b4581f11171289ca9228391e Mon Sep 17 00:00:00 2001 | |||||
From: James Cammarata <jimi@sngx.net> | |||||
Date: Tue, 10 Jan 2017 16:54:00 -0600 | |||||
Subject: [PATCH] Additional fixes for security related to CVE-2016-9587 | |||||
(cherry picked from commit d316068831f9e08ef96833200ec7df2132263966) | |||||
--- | |||||
lib/ansible/playbook/conditional.py | 10 +++++----- | |||||
lib/ansible/template/__init__.py | 28 ++++++++++++++-------------- | |||||
2 files changed, 19 insertions(+), 19 deletions(-) | |||||
diff --git lib/ansible/playbook/conditional.py lib/ansible/playbook/conditional.py | |||||
index 99e377c..57e20a0 100644 | |||||
--- lib/ansible/playbook/conditional.py | |||||
+++ lib/ansible/playbook/conditional.py | |||||
@@ -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 | |||||
@@ -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": | |||||
diff --git lib/ansible/template/__init__.py lib/ansible/template/__init__.py | |||||
index 53b2675..1a43486 100644 | |||||
--- lib/ansible/template/__init__.py | |||||
+++ lib/ansible/template/__init__.py | |||||
@@ -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 | |||||
@@ -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 | |||||
@@ -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 | |||||
@@ -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): | |||||
@@ -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}}') | |||||
@@ -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: | |||||
@@ -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? | |||||
@@ -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) | |||||
@@ -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: | |||||
@@ -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) | |||||
@@ -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) | |||||
@@ -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): |