diff --git a/CVE-2022-3697.patch b/CVE-2022-3697.patch new file mode 100644 index 0000000000000000000000000000000000000000..f2f0bef4e629c91cf748b7437ec7960c1a1e263b --- /dev/null +++ b/CVE-2022-3697.patch @@ -0,0 +1,329 @@ +From: =?utf-8?q?Bastien_Roucari=C3=A8s?= +Date: Sun, 24 Dec 2023 11:59:07 +0000 +Subject: CVE-2022-3697: ec2_instance - validate options on tower_callback + +A flaw was found in Ansible in the amazon.aws collection when using the +tower_callback parameter from the amazon.aws.ec2_instance module. +This flaw allows an attacker to take advantage of this issue as +the module is handling the parameter insecurely, leading to the password leaking in the logs + +https://salsa.debian.org/python-team/packages/ansible/-/blob/debian/2.7.7+dfsg-1+deb10u2/debian/patches/0029-CVE-2022-3697-ec2_instance-validate-options-on-tower.patch?ref_type=tags +origin: https://patch-diff.githubusercontent.com/raw/ansible-collections/amazon.aws/pull/1207.patch +bug: https://github.com/ansible-collections/amazon.aws/pull/1199 +bug-redhat: https://bugzilla.redhat.com/show_bug.cgi?id=2137664 + +--- + .../20221021-ec2_instance-tower_callback.yml | 5 + + lib/ansible/module_utils/aws/tower.py | 83 ++++++++++++++ + .../modules/cloud/amazon/ec2_instance.py | 104 +++++++----------- + test/units/module_utils/aws/test_tower.py | 40 +++++++ + 4 files changed, 167 insertions(+), 65 deletions(-) + create mode 100644 changelogs/fragments/20221021-ec2_instance-tower_callback.yml + create mode 100644 lib/ansible/module_utils/aws/tower.py + create mode 100644 test/units/module_utils/aws/test_tower.py + +diff --git a/changelogs/fragments/20221021-ec2_instance-tower_callback.yml b/changelogs/fragments/20221021-ec2_instance-tower_callback.yml +new file mode 100644 +index 0000000..ae96114 +--- /dev/null ++++ b/changelogs/fragments/20221021-ec2_instance-tower_callback.yml +@@ -0,0 +1,5 @@ ++minor_changes: ++- ec2_instance - refacter ``tower_callback`` code to handle parameter validation as part of the argument specification (https://github.com/ansible-collections/amazon.aws/pull/1199). ++- ec2_instance - the ``tower_callback`` parameter has been renamed to ``aap_callback``, ``tower_callback`` remains as an alias. This change should have no observable effect for users outside the module documentation (https://github.com/ansible-collections/amazon.aws/pull/1199). ++security_fixes: ++- ec2_instance - fixes leak of password into logs when using ``tower_callback.windows=True`` and ``tower_callback.set_password`` (https://github.com/ansible-collections/amazon.aws/pull/1199). +diff --git a/lib/ansible/module_utils/aws/tower.py b/lib/ansible/module_utils/aws/tower.py +new file mode 100644 +index 0000000..dd7d973 +--- /dev/null ++++ b/lib/ansible/module_utils/aws/tower.py +@@ -0,0 +1,83 @@ ++# Copyright: Ansible Project ++# 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 ++ ++import string ++import textwrap ++ ++from ansible.module_utils._text import to_native ++from ansible.module_utils.six.moves.urllib import parse as urlparse ++ ++ ++def _windows_callback_script(passwd=None): ++ script_url = 'https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1' ++ if passwd is not None: ++ passwd = passwd.replace("'", "''") ++ script_tpl = """\ ++ ++ $admin = [adsi]('WinNT://./administrator, user') ++ $admin.PSBase.Invoke('SetPassword', '${PASS}') ++ Invoke-Expression ((New-Object System.Net.Webclient).DownloadString('${SCRIPT}')) ++ ++ """ ++ else: ++ script_tpl = """\ ++ ++ $admin = [adsi]('WinNT://./administrator, user') ++ Invoke-Expression ((New-Object System.Net.Webclient).DownloadString('${SCRIPT}')) ++ ++ """ ++ ++ tpl = string.Template(textwrap.dedent(script_tpl)) ++ return tpl.safe_substitute(PASS=passwd, SCRIPT=script_url) ++ ++ ++def _linux_callback_script(tower_address, template_id, host_config_key): ++ template_id = urlparse.quote(template_id) ++ tower_address = urlparse.quote(tower_address) ++ host_config_key = host_config_key.replace("'", "'\"'\"'") ++ ++ script_tpl = """\ ++ #!/bin/bash ++ set -x ++ ++ retry_attempts=10 ++ attempt=0 ++ while [[ $attempt -lt $retry_attempts ]] ++ do ++ status_code=$(curl --max-time 10 -v -k -s -i \ ++ --data 'host_config_key=${host_config_key}' \ ++ 'https://${tower_address}/api/v2/job_templates/${template_id}/callback/' \ ++ | head -n 1 \ ++ | awk '{print $2}') ++ if [[ $status_code == 404 ]] ++ then ++ status_code=$(curl --max-time 10 -v -k -s -i \ ++ --data 'host_config_key=${host_config_key}' \ ++ 'https://${tower_address}/api/v1/job_templates/${template_id}/callback/' \ ++ | head -n 1 \ ++ | awk '{print $2}') ++ # fall back to using V1 API for Tower 3.1 and below, since v2 API will always 404 ++ fi ++ if [[ $status_code == 201 ]] ++ then ++ exit 0 ++ fi ++ attempt=$(( attempt + 1 )) ++ echo "$${status_code} received... retrying in 1 minute. (Attempt $${attempt})" ++ sleep 60 ++ done ++ exit 1 ++ """ ++ tpl = string.Template(textwrap.dedent(script_tpl)) ++ return tpl.safe_substitute(tower_address=tower_address, ++ template_id=template_id, ++ host_config_key=host_config_key) ++ ++ ++def tower_callback_script(tower_address, job_template_id, host_config_key, windows, passwd): ++ if windows: ++ return to_native(_windows_callback_script(passwd=passwd)) ++ return _linux_callback_script(tower_address, job_template_id, host_config_key) +diff --git a/lib/ansible/modules/cloud/amazon/ec2_instance.py b/lib/ansible/modules/cloud/amazon/ec2_instance.py +index 3d376bc..68aaced 100644 +--- a/lib/ansible/modules/cloud/amazon/ec2_instance.py ++++ b/lib/ansible/modules/cloud/amazon/ec2_instance.py +@@ -45,13 +45,16 @@ options: + user_data: + description: + - Opaque blob of data which is made available to the ec2 instance +- tower_callback: ++ aap_callback: + description: +- - Preconfigured user-data to enable an instance to perform a Tower callback. ++ - Preconfigured user-data to enable an instance to perform an Ansible Automation Platform ++ callback (Linux only). ++ - For Windows instances, to enable remote access via Ansible set I(windows) to C(true), and ++ optionally set an admin password. ++ - If using I(windows) and I(set_password), callback ton Ansible Automation Platform will not ++ be performed but the instance will be ready to receive winrm connections from Ansible. + - Requires parameters I(tower_callback.tower_address), I(tower_callback.job_template_id), and I(tower_callback.host_config_key). + - Mutually exclusive with I(user_data). +- - For Windows instances, to enable remote access via Ansible set I(tower_callback.windows) to true, and optionally set an admin password. +- - If using 'windows' and 'set_password', callback to Tower will not be performed but the instance will be ready to receive winrm connections from Ansible. + tags: + description: + - A hash/dictionary of tags to add to the new instance or to add/remove from an existing one. +@@ -613,60 +616,10 @@ from ansible.module_utils.ec2 import (boto3_conn, + camel_dict_to_snake_dict) + + from ansible.module_utils.aws.core import AnsibleAWSModule ++from ansible.module_utils.aws.tower import tower_callback_script + + module = None + +- +-def tower_callback_script(tower_conf, windows=False, passwd=None): +- script_url = 'https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1' +- if windows and passwd is not None: +- script_tpl = """ +- $admin = [adsi]("WinNT://./administrator, user") +- $admin.PSBase.Invoke("SetPassword", "{PASS}") +- Invoke-Expression ((New-Object System.Net.Webclient).DownloadString('{SCRIPT}')) +- +- """ +- return to_native(textwrap.dedent(script_tpl).format(PASS=passwd, SCRIPT=script_url)) +- elif windows and passwd is None: +- script_tpl = """ +- $admin = [adsi]("WinNT://./administrator, user") +- Invoke-Expression ((New-Object System.Net.Webclient).DownloadString('{SCRIPT}')) +- +- """ +- return to_native(textwrap.dedent(script_tpl).format(PASS=passwd, SCRIPT=script_url)) +- elif not windows: +- for p in ['tower_address', 'job_template_id', 'host_config_key']: +- if p not in tower_conf: +- module.fail_json(msg="Incomplete tower_callback configuration. tower_callback.{0} not set.".format(p)) +- +- tpl = string.Template(textwrap.dedent("""#!/bin/bash +- set -x +- +- retry_attempts=10 +- attempt=0 +- while [[ $attempt -lt $retry_attempts ]] +- do +- status_code=`curl --max-time 10 -v -k -s -i \ +- --data "host_config_key=${host_config_key}" \ +- https://${tower_address}/api/v1/job_templates/${template_id}/callback/ \ +- | head -n 1 \ +- | awk '{print $2}'` +- if [[ $status_code == 201 ]] +- then +- exit 0 +- fi +- attempt=$(( attempt + 1 )) +- echo "$${status_code} received... retrying in 1 minute. (Attempt $${attempt})" +- sleep 60 +- done +- exit 1 +- """)) +- return tpl.safe_substitute(tower_address=tower_conf['tower_address'], +- template_id=tower_conf['job_template_id'], +- host_config_key=tower_conf['host_config_key']) +- raise NotImplementedError("Only windows with remote-prep or non-windows with tower job callback supported so far.") +- +- + @AWSRetry.jittered_backoff() + def manage_tags(match, new_tags, purge_tags, ec2): + changed = False +@@ -885,6 +838,21 @@ def discover_security_groups(group, groups, parent_vpc_id=None, subnet_id=None, + return list(dict((g['GroupId'], g) for g in found_groups).values()) + + ++def build_userdata(params): ++ if params.get('user_data') is not None: ++ return {'UserData': to_native(params.get('user_data'))} ++ if params.get('aap_callback'): ++ userdata = tower_callback_script( ++ tower_address=params.get('aap_callback').get('tower_address'), ++ job_template_id=params.get('aap_callback').get('job_template_id'), ++ host_config_key=params.get('aap_callback').get('host_config_key'), ++ windows=params.get('aap_callback').get('windows'), ++ passwd=params.get('aap_callback').get('set_passwd'), ++ ) ++ return {'UserData': userdata} ++ return {} ++ ++ + def build_top_level_options(params): + spec = {} + if params.get('image_id'): +@@ -901,14 +869,8 @@ def build_top_level_options(params): + + if params.get('key_name') is not None: + spec['KeyName'] = params.get('key_name') +- if params.get('user_data') is not None: +- spec['UserData'] = to_native(params.get('user_data')) +- elif params.get('tower_callback') is not None: +- spec['UserData'] = tower_callback_script( +- tower_conf=params.get('tower_callback'), +- windows=params.get('tower_callback').get('windows', False), +- passwd=params.get('tower_callback').get('set_password'), +- ) ++ ++ spec.update(build_userdata(params)) + + if params.get('launch_template') is not None: + spec['LaunchTemplate'] = {} +@@ -1331,7 +1293,19 @@ def main(): + image_id=dict(type='str'), + instance_type=dict(default='t2.micro', type='str'), + user_data=dict(type='str'), +- tower_callback=dict(type='dict'), ++ aap_callback=dict( ++ type='dict', aliases=['tower_callback'], ++ required_if=[ ++ ('windows', False, ('tower_address', 'job_template_id', 'host_config_key',), False), ++ ], ++ options=dict( ++ windows=dict(type='bool', default=False), ++ set_password=dict(type='str', no_log=True), ++ tower_address=dict(type='str'), ++ job_template_id=dict(type='str'), ++ host_config_key=dict(type='str', no_log=True), ++ ), ++ ), + ebs_optimized=dict(type='bool'), + vpc_subnet_id=dict(type='str', aliases=['subnet_id']), + availability_zone=dict(type='str'), +@@ -1360,7 +1334,7 @@ def main(): + mutually_exclusive=[ + ['security_groups', 'security_group'], + ['availability_zone', 'vpc_subnet_id'], +- ['tower_callback', 'user_data'], ++ ['aap_callback', 'user_data'], + ['image_id', 'image'], + ], + supports_check_mode=True +diff --git a/test/units/module_utils/aws/test_tower.py b/test/units/module_utils/aws/test_tower.py +new file mode 100644 +index 0000000..527423b +--- /dev/null ++++ b/test/units/module_utils/aws/test_tower.py +@@ -0,0 +1,40 @@ ++# (c) 2022 Red Hat Inc. ++# ++# This file is part of Ansible ++# 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 ++ ++# import pytest ++ ++import ansible.module_utils.aws.tower as utils_tower ++ ++WINDOWS_DOWNLOAD = "Invoke-Expression ((New-Object System.Net.Webclient).DownloadString(" \ ++ "'https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1'))" ++EXAMPLE_PASSWORD = 'MY_EXAMPLE_PASSWORD' ++WINDOWS_INVOKE = "$admin.PSBase.Invoke('SetPassword', 'MY_EXAMPLE_PASSWORD'" ++ ++EXAMPLE_TOWER = "tower.example.com" ++EXAMPLE_TEMPLATE = 'My Template' ++EXAMPLE_KEY = '123EXAMPLE123' ++LINUX_TRIGGER_V1 = 'https://tower.example.com/api/v1/job_templates/My%20Template/callback/' ++LINUX_TRIGGER_V2 = 'https://tower.example.com/api/v2/job_templates/My%20Template/callback/' ++ ++ ++def test_windows_callback_no_password(): ++ user_data = utils_tower._windows_callback_script() ++ assert WINDOWS_DOWNLOAD in user_data ++ assert 'SetPassword' not in user_data ++ ++ ++def test_windows_callback_password(): ++ user_data = utils_tower._windows_callback_script(EXAMPLE_PASSWORD) ++ assert WINDOWS_DOWNLOAD in user_data ++ assert WINDOWS_INVOKE in user_data ++ ++ ++def test_linux_callback_with_name(): ++ user_data = utils_tower._linux_callback_script(EXAMPLE_TOWER, EXAMPLE_TEMPLATE, EXAMPLE_KEY) ++ assert LINUX_TRIGGER_V1 in user_data ++ assert LINUX_TRIGGER_V2 in user_data +-- +2.33.0 + diff --git a/CVE-2023-5115.patch b/CVE-2023-5115.patch new file mode 100644 index 0000000000000000000000000000000000000000..a1de81cbd1ca82e91a1b57d18131685e179c8660 --- /dev/null +++ b/CVE-2023-5115.patch @@ -0,0 +1,219 @@ +From: Matt Martz +Date: Tue, 26 Sep 2023 11:32:19 -0500 +Subject: CVE-2023-5115 Prevent roles from using symlinks to overwrite files + outside of the installation directory (#81780) + +* Sanitize linkname during role installs + +* Add tests + +* add clog frag. +(cherry picked from commit ddf0311c63287e2d5334770377350c1e0cbfff28) +origin: https://github.com/sivel/ansible/commit/638f5988f32eb9ec3f931d5544c2294e0631154d.patch +https://salsa.debian.org/python-team/packages/ansible/-/blob/debian/2.7.7+dfsg-1+deb10u2/debian/patches/0030-CVE-2023-5115-Prevent-roles-from-using-symlinks-to-o.patch?ref_type=tags + +[debian backport] add to no_native import +--- + changelogs/fragments/cve-2023-5115.yml | 3 ++ + lib/ansible/galaxy/role.py | 37 +++++++++++++++--- + .../targets/ansible-galaxy-role/aliases | 3 ++ + .../files/create-role-archive.py | 45 ++++++++++++++++++++++ + .../targets/ansible-galaxy-role/meta/main.yml | 0 + .../ansible-galaxy-role/tasks/dir-traversal.yml | 44 +++++++++++++++++++++ + .../targets/ansible-galaxy-role/tasks/main.yml | 4 ++ + 7 files changed, 130 insertions(+), 6 deletions(-) + create mode 100644 changelogs/fragments/cve-2023-5115.yml + create mode 100644 test/integration/targets/ansible-galaxy-role/aliases + create mode 100755 test/integration/targets/ansible-galaxy-role/files/create-role-archive.py + create mode 100644 test/integration/targets/ansible-galaxy-role/meta/main.yml + create mode 100644 test/integration/targets/ansible-galaxy-role/tasks/dir-traversal.yml + create mode 100644 test/integration/targets/ansible-galaxy-role/tasks/main.yml + +diff --git a/changelogs/fragments/cve-2023-5115.yml b/changelogs/fragments/cve-2023-5115.yml +new file mode 100644 +index 0000000..69e0ddb +--- /dev/null ++++ b/changelogs/fragments/cve-2023-5115.yml +@@ -0,0 +1,3 @@ ++security_fixes: ++- ansible-galaxy - Prevent roles from using symlinks to overwrite ++ files outside of the installation directory (CVE-2023-5115) +diff --git a/lib/ansible/galaxy/role.py b/lib/ansible/galaxy/role.py +index 24075bf..2cca4c4 100644 +--- a/lib/ansible/galaxy/role.py ++++ b/lib/ansible/galaxy/role.py +@@ -33,6 +33,7 @@ from shutil import rmtree + + from ansible.errors import AnsibleError + from ansible.module_utils.urls import open_url ++from ansible.module_utils._text import to_native + from ansible.playbook.role.requirement import RoleRequirement + from ansible.galaxy.api import GalaxyAPI + +@@ -316,12 +317,36 @@ class GalaxyRole(object): + # bits that might be in the file for security purposes + # and drop any containing directory, as mentioned above + if member.isreg() or member.issym(): +- parts = member.name.replace(archive_parent_dir, "", 1).split(os.sep) +- final_parts = [] +- for part in parts: +- if part != '..' and '~' not in part and '$' not in part: +- final_parts.append(part) +- member.name = os.path.join(*final_parts) ++ for attr in ('name', 'linkname'): ++ attr_value = getattr(member, attr, None) ++ if not attr_value: ++ continue ++ n_attr_value = to_native(attr_value) ++ n_archive_parent_dir = to_native(archive_parent_dir) ++ n_parts = n_attr_value.replace(n_archive_parent_dir, "", 1).split(os.sep) ++ n_final_parts = [] ++ for n_part in n_parts: ++ # TODO if the condition triggers it produces a broken installation. ++ # It will create the parent directory as an empty file and will ++ # explode if the directory contains valid files. ++ # Leaving this as is since the whole module needs a rewrite. ++ # ++ # Check if we have any files with illegal names, ++ # and display a warning if so. This could help users ++ # to debug a broken installation. ++ if not n_part: ++ continue ++ if n_part == '..': ++ display.warning(f"Illegal filename '{n_part}': '..' is not allowed") ++ continue ++ if n_part.startswith('~'): ++ display.warning(f"Illegal filename '{n_part}': names cannot start with '~'") ++ continue ++ if '$' in n_part: ++ display.warning(f"Illegal filename '{n_part}': names cannot contain '$'") ++ continue ++ n_final_parts.append(n_part) ++ setattr(member, attr, os.path.join(*n_final_parts)) + role_tar_file.extract(member, self.path) + + # write out the install info file for later use +diff --git a/test/integration/targets/ansible-galaxy-role/aliases b/test/integration/targets/ansible-galaxy-role/aliases +new file mode 100644 +index 0000000..bf63a1d +--- /dev/null ++++ b/test/integration/targets/ansible-galaxy-role/aliases +@@ -0,0 +1,3 @@ ++destructive ++shippable/posix/group3 ++needs/target/setup_remote_tmp_dir +\ No newline at end of file +diff --git a/test/integration/targets/ansible-galaxy-role/files/create-role-archive.py b/test/integration/targets/ansible-galaxy-role/files/create-role-archive.py +new file mode 100755 +index 0000000..cfd908c +--- /dev/null ++++ b/test/integration/targets/ansible-galaxy-role/files/create-role-archive.py +@@ -0,0 +1,45 @@ ++#!/usr/bin/env python ++"""Create a role archive which overwrites an arbitrary file.""" ++ ++import argparse ++import pathlib ++import tarfile ++import tempfile ++ ++ ++def main() -> None: ++ parser = argparse.ArgumentParser(description=__doc__) ++ parser.add_argument('archive', type=pathlib.Path, help='archive to create') ++ parser.add_argument('content', type=pathlib.Path, help='content to write') ++ parser.add_argument('target', type=pathlib.Path, help='file to overwrite') ++ ++ args = parser.parse_args() ++ ++ create_archive(args.archive, args.content, args.target) ++ ++ ++def create_archive(archive_path: pathlib.Path, content_path: pathlib.Path, target_path: pathlib.Path) -> None: ++ with ( ++ tarfile.open(name=archive_path, mode='w') as role_archive, ++ tempfile.TemporaryDirectory() as temp_dir_name, ++ ): ++ temp_dir_path = pathlib.Path(temp_dir_name) ++ ++ meta_main_path = temp_dir_path / 'meta' / 'main.yml' ++ meta_main_path.parent.mkdir() ++ meta_main_path.write_text('') ++ ++ symlink_path = temp_dir_path / 'symlink' ++ symlink_path.symlink_to(target_path) ++ ++ role_archive.add(meta_main_path) ++ role_archive.add(symlink_path) ++ ++ content_tarinfo = role_archive.gettarinfo(content_path, str(symlink_path)) ++ ++ with content_path.open('rb') as content_file: ++ role_archive.addfile(content_tarinfo, content_file) ++ ++ ++if __name__ == '__main__': ++ main() +diff --git a/test/integration/targets/ansible-galaxy-role/meta/main.yml b/test/integration/targets/ansible-galaxy-role/meta/main.yml +new file mode 100644 +index 0000000..e69de29 +diff --git a/test/integration/targets/ansible-galaxy-role/tasks/dir-traversal.yml b/test/integration/targets/ansible-galaxy-role/tasks/dir-traversal.yml +new file mode 100644 +index 0000000..c70e899 +--- /dev/null ++++ b/test/integration/targets/ansible-galaxy-role/tasks/dir-traversal.yml +@@ -0,0 +1,44 @@ ++- name: create test directories ++ file: ++ path: '{{ remote_tmp_dir }}/dir-traversal/{{ item }}' ++ state: directory ++ loop: ++ - source ++ - target ++ - roles ++ ++- name: create test content ++ copy: ++ dest: '{{ remote_tmp_dir }}/dir-traversal/source/content.txt' ++ content: | ++ some content to write ++ ++- name: build dangerous dir traversal role ++ script: ++ chdir: '{{ remote_tmp_dir }}/dir-traversal/source' ++ cmd: create-role-archive.py dangerous.tar content.txt {{ remote_tmp_dir }}/dir-traversal/target/target-file-to-overwrite.txt ++ executable: '{{ ansible_playbook_python }}' ++ ++- name: install dangerous role ++ command: ++ cmd: ansible-galaxy role install --roles-path '{{ remote_tmp_dir }}/dir-traversal/roles' dangerous.tar ++ chdir: '{{ remote_tmp_dir }}/dir-traversal/source' ++ ignore_errors: true ++ register: galaxy_install_dangerous ++ ++- name: check for overwritten file ++ stat: ++ path: '{{ remote_tmp_dir }}/dir-traversal/target/target-file-to-overwrite.txt' ++ register: dangerous_overwrite_stat ++ ++- name: get overwritten content ++ slurp: ++ path: '{{ remote_tmp_dir }}/dir-traversal/target/target-file-to-overwrite.txt' ++ register: dangerous_overwrite_content ++ when: dangerous_overwrite_stat.stat.exists ++ ++- assert: ++ that: ++ - dangerous_overwrite_content.content|default('')|b64decode == '' ++ - not dangerous_overwrite_stat.stat.exists ++ - galaxy_install_dangerous is failed +diff --git a/test/integration/targets/ansible-galaxy-role/tasks/main.yml b/test/integration/targets/ansible-galaxy-role/tasks/main.yml +new file mode 100644 +index 0000000..3deb8b5 +--- /dev/null ++++ b/test/integration/targets/ansible-galaxy-role/tasks/main.yml +@@ -0,0 +1,4 @@ ++- name: Install role from Galaxy (should not fail with AttributeError) ++ command: ansible-galaxy role install ansible.nope -vvvv --ignore-errors ++ ++- import_tasks: dir-traversal.yml diff --git a/ansible.spec b/ansible.spec index 149ccff647f5d26d9f7e92eaa4e0037446825cd0..e793b9b3edb787e53b7b30c3c74970289e6a436a 100644 --- a/ansible.spec +++ b/ansible.spec @@ -3,7 +3,7 @@ Name: ansible Summary: SSH-based configuration management, deployment, and task execution system Version: 2.5.5 -Release: 7 +Release: 8 License: Python-2.0 and MIT and GPL+ Url: http://ansible.com Source0: https://releases.ansible.com/ansible/%{name}-%{version}.tar.gz @@ -23,6 +23,8 @@ Patch114: CVE-2020-1735.patch Patch115: CVE-2019-3828.patch Patch116: ansible-2.5.5-openEuler-hostname.patch Patch117: CVE-2024-0690.patch +Patch118: CVE-2022-3697.patch +Patch119: CVE-2023-5115.patch BuildArch: noarch Provides: ansible-fireball = %{version}-%{release} Obsoletes: ansible-fireball < 1.2.4 @@ -91,6 +93,8 @@ This package installs extensive documentation for ansible %patch115 -p1 %patch116 -p1 %patch117 -p1 +%patch118 -p1 +%patch119 -p1 %if 0%{?with_python3} rm -rf %{py3dir} cp -a . %{py3dir} @@ -151,6 +155,9 @@ cp -pr docs/docsite/rst . %endif %changelog +* Sat Feb 08 2025 wangkai <13474090681@163.com> - 2.5.5-8 +- Fix CVE-2022-3697 CVE-2023-5115 + * Mon Feb 05 2024 wangkai <13474090681@163.com> - 2.5.5-7 - Fix CVE-2024-0690