summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Cammarata <jimi@sngx.net>2017-05-08 10:37:10 -0500
committerJames Cammarata <jimi@sngx.net>2017-05-08 15:59:55 -0500
commitfd30f5328986f9e1da434474481f32bf918a600c (patch)
treebb98376d5ddc030dc004b4e076742dbb95d6bd45
parentd68a911141d53a410f65d934f082f9aad2d2da93 (diff)
downloadansible-fd30f5328986f9e1da434474481f32bf918a600c.tar.gz
Fixing security issue with lookup returns not tainting the jinja2 environment
CVE-2017-7481 Lookup returns wrap the result in unsafe, however when used through the standard templar engine, this does not result in the jinja2 environment being marked as unsafe as a whole. This means the lookup result looses the unsafe protection and may become simple unicode strings, which can result in bad things being re-templated. This also adds a global lookup param and cfg options for lookups to allow unsafe returns, so users can force the previous (insecure) behavior. (cherry picked from commit 72dfb1570d22ac519350a8c09e76c458789120ed) (cherry picked from commit fadccda7c7a2e8d0650f4dee8e3cea93cf17acfd)
-rw-r--r--docsite/rst/intro_configuration.rst28
-rw-r--r--examples/ansible.cfg6
-rw-r--r--lib/ansible/constants.py1
-rw-r--r--lib/ansible/template/__init__.py10
4 files changed, 43 insertions, 2 deletions
diff --git a/docsite/rst/intro_configuration.rst b/docsite/rst/intro_configuration.rst
index 8e98b5f3e5..2013686536 100644
--- a/docsite/rst/intro_configuration.rst
+++ b/docsite/rst/intro_configuration.rst
@@ -74,6 +74,34 @@ different locations::
Most users will not need to use this feature. See :doc:`developing_plugins` for more details.
+
+.. _allow_unsafe_lookups:
+
+allow_unsafe_lookups
+====================
+
+.. versionadded:: 2.2.3, 2.3.1
+
+When enabled, this option allows lookup plugins (whether used in variables as `{{lookup('foo')}}` or as a loop as `with_foo`) to return data that is **not** marked "unsafe". By default, such data is marked as unsafe to prevent the templating engine from evaluating any jinja2 templating language, as this could represent a security risk.
+
+This option is provided to allow for backwards-compatibility, however users should first consider adding `allow_unsafe=True` to any lookups which may be expected to contain data which may be run through the templating engine later. For example::
+
+ {{lookup('pipe', '/path/to/some/command', allow_unsafe=True)}}
+
+
+.. _allow_world_readable_tmpfiles:
+
+allow_world_readable_tmpfiles
+=============================
+
+.. versionadded:: 2.1
+This makes the temporary files created on the machine to be world readable and will issue a warning instead of failing the task.
+
+It is useful when becoming an unprivileged user::
+
+ allow_world_readable_tmpfiles=True
+
+
.. _ansible_managed:
ansible_managed
diff --git a/examples/ansible.cfg b/examples/ansible.cfg
index 22e558269f..6a9976f0b4 100644
--- a/examples/ansible.cfg
+++ b/examples/ansible.cfg
@@ -252,6 +252,12 @@
# set to 0 for unlimited (RAM may suffer!).
#max_diff_size = 1048576
+# When enabled, this option allows lookups (via variables like {{lookup('foo')}} or when used as
+# a loop with `with_foo`) to return data that is not marked "unsafe". This means the data may contain
+# jinja2 templating language which will be run through the templating engine.
+# ENABLING THIS COULD BE A SECURITY RISK
+#allow_unsafe_lookups = False
+
[privilege_escalation]
#become=True
#become_method=sudo
diff --git a/lib/ansible/constants.py b/lib/ansible/constants.py
index 0c4025ab27..1be7bda166 100644
--- a/lib/ansible/constants.py
+++ b/lib/ansible/constants.py
@@ -182,6 +182,7 @@ DEFAULT_LOG_PATH = get_config(p, DEFAULTS, 'log_path', 'ANSIB
DEFAULT_FORCE_HANDLERS = get_config(p, DEFAULTS, 'force_handlers', 'ANSIBLE_FORCE_HANDLERS', False, boolean=True)
DEFAULT_INVENTORY_IGNORE = get_config(p, DEFAULTS, 'inventory_ignore_extensions', 'ANSIBLE_INVENTORY_IGNORE', ["~", ".orig", ".bak", ".ini", ".cfg", ".retry", ".pyc", ".pyo"], islist=True)
DEFAULT_VAR_COMPRESSION_LEVEL = get_config(p, DEFAULTS, 'var_compression_level', 'ANSIBLE_VAR_COMPRESSION_LEVEL', 0, integer=True)
+DEFAULT_ALLOW_UNSAFE_LOOKUPS = get_config(p, DEFAULTS, 'allow_unsafe_lookups', None, False, boolean=True)
# static includes
DEFAULT_TASK_INCLUDES_STATIC = get_config(p, DEFAULTS, 'task_includes_static', 'ANSIBLE_TASK_INCLUDES_STATIC', False, boolean=True)
diff --git a/lib/ansible/template/__init__.py b/lib/ansible/template/__init__.py
index 88934e179a..fd07ccbfea 100644
--- a/lib/ansible/template/__init__.py
+++ b/lib/ansible/template/__init__.py
@@ -213,6 +213,9 @@ class Templar:
loader=FileSystemLoader(self._basedir),
)
+ # the current rendering context under which the templar class is working
+ self.cur_context = None
+
self.SINGLE_VAR = re.compile(r"^%s\s*(\w*)\s*%s$" % (self.environment.variable_start_string, self.environment.variable_end_string))
self.block_start = self.environment.block_start_string
@@ -482,6 +485,7 @@ class Templar:
if instance is not None:
wantlist = kwargs.pop('wantlist', False)
+ allow_unsafe = kwargs.pop('allow_unsafe', C.DEFAULT_ALLOW_UNSAFE_LOOKUPS)
from ansible.utils.listify import listify_lookup_plugin_terms
loop_terms = listify_lookup_plugin_terms(terms=args, templar=self, loader=self._loader, fail_on_undefined=True, convert_bare=False)
@@ -495,7 +499,7 @@ class Templar:
raise AnsibleError("An unhandled exception occurred while running the lookup plugin '%s'. Error was a %s, original message: %s" % (name, type(e), e))
ran = None
- if ran:
+ if ran and not allow_unsafe:
from ansible.vars.unsafe_proxy import UnsafeProxy, wrap_var
if wantlist:
ran = wrap_var(ran)
@@ -508,6 +512,8 @@ class Templar:
else:
ran = wrap_var(ran)
+ if self.cur_context:
+ self.cur_context.unsafe = True
return ran
else:
raise AnsibleError("lookup plugin (%s) not found" % name)
@@ -566,7 +572,7 @@ class Templar:
jvars = AnsibleJ2Vars(self, t.globals)
- new_context = t.new_context(jvars, shared=True)
+ self.cur_context = new_context = t.new_context(jvars, shared=True)
rf = t.root_render_func(new_context)
try: