Fixing security bugs for CVE-2016-9587

This commit is contained in:
James Cammarata 2016-12-13 11:14:47 -06:00
commit a6fff93967
7 changed files with 129 additions and 47 deletions

View file

@ -30,7 +30,7 @@ import time
from abc import ABCMeta, abstractmethod
from ansible import constants as C
from ansible.compat.six import binary_type, text_type, iteritems, with_metaclass
from ansible.compat.six import binary_type, string_types, text_type, iteritems, with_metaclass
from ansible.compat.six.moves import shlex_quote
from ansible.errors import AnsibleError, AnsibleConnectionFailure
from ansible.executor.module_common import modify_module
@ -39,6 +39,7 @@ from ansible.module_utils.json_utils import _filter_non_json_lines
from ansible.parsing.utils.jsonify import jsonify
from ansible.playbook.play_context import MAGIC_VARIABLE_MAPPING
from ansible.release import __version__
from ansible.vars.unsafe_proxy import wrap_var
try:
@ -458,6 +459,8 @@ class ActionBase(with_metaclass(ABCMeta, object)):
# happens sometimes when it is a dir and not on bsd
if 'checksum' not in mystat['stat']:
mystat['stat']['checksum'] = ''
elif not isinstance(mystat['stat']['checksum'], string_types):
raise AnsibleError("Invalid checksum returned by stat: expected a string type but got %s" % type(mystat['stat']['checksum']))
return mystat['stat']
@ -677,6 +680,39 @@ class ActionBase(with_metaclass(ABCMeta, object)):
display.debug("done with _execute_module (%s, %s)" % (module_name, module_args))
return data
def _clean_returned_data(self, data):
remove_keys = set()
fact_keys = set(data.keys())
# first we add all of our magic variable names to the set of
# keys we want to remove from facts
for magic_var in MAGIC_VARIABLE_MAPPING:
remove_keys.update(fact_keys.intersection(MAGIC_VARIABLE_MAPPING[magic_var]))
# next we remove any connection plugin specific vars
for conn_path in self._shared_loader_obj.connection_loader.all(path_only=True):
try:
conn_name = os.path.splitext(os.path.basename(conn_path))[0]
re_key = re.compile('^ansible_%s_' % conn_name)
for fact_key in fact_keys:
if re_key.match(fact_key):
remove_keys.add(fact_key)
except AttributeError:
pass
# remove some KNOWN keys
for hard in ['ansible_rsync_path', 'ansible_playbook_python']:
if hard in fact_keys:
remove_keys.add(hard)
# finally, we search for interpreter keys to remove
re_interp = re.compile('^ansible_.*_interpreter$')
for fact_key in fact_keys:
if re_interp.match(fact_key):
remove_keys.add(fact_key)
# then we remove them (except for ssh host keys)
for r_key in remove_keys:
if not r_key.startswith('ansible_ssh_host_key_'):
del data[r_key]
def _parse_returned_data(self, res):
try:
filtered_output, warnings = _filter_non_json_lines(res.get('stdout', u''))
@ -685,37 +721,11 @@ class ActionBase(with_metaclass(ABCMeta, object)):
data = json.loads(filtered_output)
data['_ansible_parsed'] = True
if 'ansible_facts' in data and isinstance(data['ansible_facts'], dict):
remove_keys = set()
fact_keys = set(data['ansible_facts'].keys())
# first we add all of our magic variable names to the set of
# keys we want to remove from facts
for magic_var in MAGIC_VARIABLE_MAPPING:
remove_keys.update(fact_keys.intersection(MAGIC_VARIABLE_MAPPING[magic_var]))
# next we remove any connection plugin specific vars
for conn_path in self._shared_loader_obj.connection_loader.all(path_only=True):
try:
conn_name = os.path.splitext(os.path.basename(conn_path))[0]
re_key = re.compile('^ansible_%s_' % conn_name)
for fact_key in fact_keys:
if re_key.match(fact_key):
remove_keys.add(fact_key)
except AttributeError:
pass
# remove some KNOWN keys
for hard in ['ansible_rsync_path', 'ansible_playbook_python']:
if hard in fact_keys:
remove_keys.add(hard)
# finally, we search for interpreter keys to remove
re_interp = re.compile('^ansible_.*_interpreter$')
for fact_key in fact_keys:
if re_interp.match(fact_key):
remove_keys.add(fact_key)
# then we remove them (except for ssh host keys)
for r_key in remove_keys:
if not r_key.startswith('ansible_ssh_host_key_'):
del data['ansible_facts'][r_key]
self._clean_returned_data(data['ansible_facts'])
data['ansible_facts'] = wrap_var(data['ansible_facts'])
if 'add_host' in data and isinstance(data['add_host'].get('host_vars', None), dict):
self._clean_returned_data(data['add_host']['host_vars'])
data['add_host'] = wrap_var(data['add_host'])
except ValueError:
# not valid json, lets try to capture error
data = dict(failed=True, _ansible_parsed=False)