diff options
author | James Cammarata <jimi@sngx.net> | 2017-05-08 10:37:10 -0500 |
---|---|---|
committer | James Cammarata <jimi@sngx.net> | 2017-05-08 15:59:55 -0500 |
commit | fd30f5328986f9e1da434474481f32bf918a600c (patch) | |
tree | bb98376d5ddc030dc004b4e076742dbb95d6bd45 | |
parent | d68a911141d53a410f65d934f082f9aad2d2da93 (diff) | |
download | ansible-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.rst | 28 | ||||
-rw-r--r-- | examples/ansible.cfg | 6 | ||||
-rw-r--r-- | lib/ansible/constants.py | 1 | ||||
-rw-r--r-- | lib/ansible/template/__init__.py | 10 |
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: |