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:
parent
7d51cac330
commit
5be0668fb0
4 changed files with 40 additions and 3 deletions
5
changelogs/fragments/62237-keep-unsafe-context.yml
Normal file
5
changelogs/fragments/62237-keep-unsafe-context.yml
Normal 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)
|
|
@ -28,7 +28,7 @@ from ansible.plugins.loader import become_loader, cliconf_loader, connection_loa
|
||||||
from ansible.template import Templar
|
from ansible.template import Templar
|
||||||
from ansible.utils.collection_loader import AnsibleCollectionLoader
|
from ansible.utils.collection_loader import AnsibleCollectionLoader
|
||||||
from ansible.utils.listify import listify_lookup_plugin_terms
|
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.vars.clean import namespace_facts, clean_facts
|
||||||
from ansible.utils.display import Display
|
from ansible.utils.display import Display
|
||||||
from ansible.utils.vars import combine_vars, isidentifier
|
from ansible.utils.vars import combine_vars, isidentifier
|
||||||
|
@ -152,7 +152,7 @@ class TaskExecutor:
|
||||||
|
|
||||||
def _clean_res(res, errors='surrogate_or_strict'):
|
def _clean_res(res, errors='surrogate_or_strict'):
|
||||||
if isinstance(res, binary_type):
|
if isinstance(res, binary_type):
|
||||||
return to_text(res, errors=errors)
|
return to_unsafe_text(res, errors=errors)
|
||||||
elif isinstance(res, dict):
|
elif isinstance(res, dict):
|
||||||
for k in res:
|
for k in res:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__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.common._collections_compat import Mapping, MutableSequence, Set
|
||||||
from ansible.module_utils.six import string_types, binary_type, text_type
|
from ansible.module_utils.six import string_types, binary_type, text_type
|
||||||
|
|
||||||
|
@ -126,3 +126,11 @@ def wrap_var(v):
|
||||||
v = AnsibleUnsafeText(v)
|
v = AnsibleUnsafeText(v)
|
||||||
|
|
||||||
return 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))
|
||||||
|
|
|
@ -27,6 +27,8 @@ from ansible.errors import AnsibleError
|
||||||
from ansible.executor.task_executor import TaskExecutor, remove_omit
|
from ansible.executor.task_executor import TaskExecutor, remove_omit
|
||||||
from ansible.plugins.loader import action_loader, lookup_loader
|
from ansible.plugins.loader import action_loader, lookup_loader
|
||||||
from ansible.parsing.yaml.objects import AnsibleUnicode
|
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
|
from units.mock.loader import DictDataLoader
|
||||||
|
|
||||||
|
@ -101,6 +103,28 @@ class TestTaskExecutor(unittest.TestCase):
|
||||||
res = te.run()
|
res = te.run()
|
||||||
self.assertIn("failed", res)
|
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):
|
def test_task_executor_get_loop_items(self):
|
||||||
fake_loader = DictDataLoader({})
|
fake_loader = DictDataLoader({})
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue