diff options
author | Matt Martz <matt@sivel.net> | 2021-09-29 11:53:40 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-29 11:53:40 -0500 |
commit | 2cdc3834c94328b62d820542e68251e22014e0a8 (patch) | |
tree | 3a5074c77091b5b16ff2263445696df1fdd56baa | |
parent | a00c61719b825c21c629d25244715c82716548e3 (diff) | |
download | ansible-2cdc3834c94328b62d820542e68251e22014e0a8.tar.gz |
[stable-2.10] Don't show params when there is an issue with `set_option(s)` (#75805) (#75809)
(cherry picked from commit 79e9dae)
Co-authored-by: Matt Martz <matt@sivel.net>
-rw-r--r-- | changelogs/fragments/avoid-set_options-leak.yaml | 5 | ||||
-rwxr-xr-x | lib/ansible/cli/scripts/ansible_connection_cli_stub.py | 12 | ||||
-rw-r--r-- | lib/ansible/module_utils/connection.py | 5 | ||||
-rw-r--r-- | test/units/module_utils/test_connection.py | 22 |
4 files changed, 42 insertions, 2 deletions
diff --git a/changelogs/fragments/avoid-set_options-leak.yaml b/changelogs/fragments/avoid-set_options-leak.yaml new file mode 100644 index 0000000000..9680f444e6 --- /dev/null +++ b/changelogs/fragments/avoid-set_options-leak.yaml @@ -0,0 +1,5 @@ +--- +security_fixes: + - Do not include params in exception when a call to ``set_options`` fails. + Additionally, block the exception that is returned from being displayed to stdout. + (CVE-2021-3620) diff --git a/lib/ansible/cli/scripts/ansible_connection_cli_stub.py b/lib/ansible/cli/scripts/ansible_connection_cli_stub.py index d701f15696..08c36d6ec4 100755 --- a/lib/ansible/cli/scripts/ansible_connection_cli_stub.py +++ b/lib/ansible/cli/scripts/ansible_connection_cli_stub.py @@ -100,7 +100,11 @@ class ConnectionProcess(object): self.play_context.private_key_file = os.path.join(self.original_path, self.play_context.private_key_file) self.connection = connection_loader.get(self.play_context.connection, self.play_context, '/dev/null', task_uuid=self._task_uuid, ansible_playbook_pid=self._ansible_playbook_pid) - self.connection.set_options(var_options=variables) + try: + self.connection.set_options(var_options=variables) + except ConnectionError as exc: + messages.append(('debug', to_text(exc))) + raise ConnectionError('Unable to decode JSON from response set_options. See the debug log for more information.') self.connection._socket_path = self.socket_path self.srv.register(self.connection) @@ -302,7 +306,11 @@ def main(): else: messages.append(('vvvv', 'found existing local domain socket, using it!')) conn = Connection(socket_path) - conn.set_options(var_options=variables) + try: + conn.set_options(var_options=variables) + except ConnectionError as exc: + messages.append(('debug', to_text(exc))) + raise ConnectionError('Unable to decode JSON from response set_options. See the debug log for more information.') pc_data = to_text(init_data) try: conn.update_play_context(pc_data) diff --git a/lib/ansible/module_utils/connection.py b/lib/ansible/module_utils/connection.py index a76fdb6bcc..fd0b134087 100644 --- a/lib/ansible/module_utils/connection.py +++ b/lib/ansible/module_utils/connection.py @@ -163,6 +163,11 @@ class Connection(object): try: response = json.loads(out) except ValueError: + # set_option(s) has sensitive info, and the details are unlikely to matter anyway + if name.startswith("set_option"): + raise ConnectionError( + "Unable to decode JSON from response to {0}. Received '{1}'.".format(name, out) + ) params = [repr(arg) for arg in args] + ['{0}={1!r}'.format(k, v) for k, v in iteritems(kwargs)] params = ', '.join(params) raise ConnectionError( diff --git a/test/units/module_utils/test_connection.py b/test/units/module_utils/test_connection.py new file mode 100644 index 0000000000..bd0285b3a7 --- /dev/null +++ b/test/units/module_utils/test_connection.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Matt Martz <matt@sivel.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +from ansible.module_utils import connection + +import pytest + + +def test_set_options_credential_exposure(): + def send(data): + return '{' + + c = connection.Connection(connection.__file__) + c.send = send + with pytest.raises(connection.ConnectionError) as excinfo: + c._exec_jsonrpc('set_options', become_pass='password') + + assert 'password' not in str(excinfo.value) |