Ensure we don't erase unsafe context in TaskExecutor.run on bytes (#62287)

* Ensure we don't erase unsafe context in TaskExecutor.run on bytes. Fixes #62237

* Remove unused import

* Add missing import

* use args splatting for to_unsafe_text/bytes

* Add security issue to changelog

* fix yaml linting issue
This commit is contained in:
Matt Martz 2019-09-13 13:14:35 -05:00 committed by GitHub
parent 7d51cac330
commit 5be0668fb0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 40 additions and 3 deletions

View file

@ -0,0 +1,5 @@
bugfixes:
- >
**security issue** - TaskExecutor - Ensure we don't erase unsafe context in TaskExecutor.run on bytes.
Only present in 2.9.0beta1
(https://github.com/ansible/ansible/issues/62237)

View file

@ -28,7 +28,7 @@ from ansible.plugins.loader import become_loader, cliconf_loader, connection_loa
from ansible.template import Templar
from ansible.utils.collection_loader import AnsibleCollectionLoader
from ansible.utils.listify import listify_lookup_plugin_terms
from ansible.utils.unsafe_proxy import AnsibleUnsafe, wrap_var
from ansible.utils.unsafe_proxy import AnsibleUnsafe, to_unsafe_text, wrap_var
from ansible.vars.clean import namespace_facts, clean_facts
from ansible.utils.display import Display
from ansible.utils.vars import combine_vars, isidentifier
@ -152,7 +152,7 @@ class TaskExecutor:
def _clean_res(res, errors='surrogate_or_strict'):
if isinstance(res, binary_type):
return to_text(res, errors=errors)
return to_unsafe_text(res, errors=errors)
elif isinstance(res, dict):
for k in res:
try:

View file

@ -53,7 +53,7 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.module_utils._text import to_text
from ansible.module_utils._text import to_bytes, to_text
from ansible.module_utils.common._collections_compat import Mapping, MutableSequence, Set
from ansible.module_utils.six import string_types, binary_type, text_type
@ -126,3 +126,11 @@ def wrap_var(v):
v = AnsibleUnsafeText(v)
return v
def to_unsafe_bytes(*args, **kwargs):
return wrap_var(to_bytes(*args, **kwargs))
def to_unsafe_text(*args, **kwargs):
return wrap_var(to_text(*args, **kwargs))

View file

@ -27,6 +27,8 @@ from ansible.errors import AnsibleError
from ansible.executor.task_executor import TaskExecutor, remove_omit
from ansible.plugins.loader import action_loader, lookup_loader
from ansible.parsing.yaml.objects import AnsibleUnicode
from ansible.utils.unsafe_proxy import AnsibleUnsafeText, AnsibleUnsafeBytes
from ansible.module_utils.six import text_type
from units.mock.loader import DictDataLoader
@ -101,6 +103,28 @@ class TestTaskExecutor(unittest.TestCase):
res = te.run()
self.assertIn("failed", res)
def test_task_executor_run_clean_res(self):
te = TaskExecutor(None, MagicMock(), None, None, None, None, None, None)
te._get_loop_items = MagicMock(return_value=[1])
te._run_loop = MagicMock(
return_value=[
{
'unsafe_bytes': AnsibleUnsafeBytes(b'{{ $bar }}'),
'unsafe_text': AnsibleUnsafeText(u'{{ $bar }}'),
'bytes': b'bytes',
'text': u'text',
'int': 1,
}
]
)
res = te.run()
data = res['results'][0]
self.assertIsInstance(data['unsafe_bytes'], AnsibleUnsafeText)
self.assertIsInstance(data['unsafe_text'], AnsibleUnsafeText)
self.assertIsInstance(data['bytes'], text_type)
self.assertIsInstance(data['text'], text_type)
self.assertIsInstance(data['int'], int)
def test_task_executor_get_loop_items(self):
fake_loader = DictDataLoader({})