Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

prevent ansible_facts injection #68431

Merged
merged 1 commit into from Mar 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelogs/fragments/af_clean.yml
@@ -0,0 +1,2 @@
bugfixes:
- Ensure we don't allow ansible_facts subkey of ansible_facts to override top level, also fix 'deprefixing' to prevent key transforms.
2 changes: 1 addition & 1 deletion lib/ansible/constants.py
Expand Up @@ -112,7 +112,7 @@ def __getitem__(self, y):
'ansible.windows.win_shell', 'raw', 'script')
MODULE_NO_JSON = ('command', 'win_command', 'ansible.windows.win_command', 'shell', 'win_shell',
'ansible.windows.win_shell', 'raw')
RESTRICTED_RESULT_KEYS = ('ansible_rsync_path', 'ansible_playbook_python')
RESTRICTED_RESULT_KEYS = ('ansible_rsync_path', 'ansible_playbook_python', 'ansible_facts')
TREE_DIR = None
VAULT_VERSION_MIN = 1.0
VAULT_VERSION_MAX = 1.0
Expand Down
8 changes: 3 additions & 5 deletions lib/ansible/vars/clean.py
Expand Up @@ -16,7 +16,6 @@
from ansible.plugins.loader import connection_loader
from ansible.utils.display import Display


display = Display()


Expand Down Expand Up @@ -169,10 +168,9 @@ def namespace_facts(facts):
''' return all facts inside 'ansible_facts' w/o an ansible_ prefix '''
deprefixed = {}
for k in facts:
if k in ('ansible_local',):
# exceptions to 'deprefixing'
deprefixed[k] = module_response_deepcopy(facts[k])
if k.startswith('ansible_') and k not in ('ansible_local',):
deprefixed[k[8:]] = module_response_deepcopy(facts[k])
else:
deprefixed[k.replace('ansible_', '', 1)] = module_response_deepcopy(facts[k])
deprefixed[k] = module_response_deepcopy(facts[k])

return {'ansible_facts': deprefixed}
12 changes: 12 additions & 0 deletions test/integration/targets/gathering_facts/library/bogus_facts
@@ -0,0 +1,12 @@
#!/bin/sh

echo '{
"changed": false,
"ansible_facts": {
"ansible_facts": {
"discovered_interpreter_python": "(touch /tmp/pwned-$(date -Iseconds)-$(whoami) ) 2>/dev/null >/dev/null && /usr/bin/python",
"bogus_overwrite": "yes"
},
"dansible_iscovered_interpreter_python": "(touch /tmp/pwned-$(date -Iseconds)-$(whoami) ) 2>/dev/null >/dev/null && /usr/bin/python"
bcoca marked this conversation as resolved.
Show resolved Hide resolved
}
}'
3 changes: 3 additions & 0 deletions test/integration/targets/gathering_facts/runme.sh
Expand Up @@ -7,3 +7,6 @@ ansible-playbook test_gathering_facts.yml -i inventory -v "$@"
# ANSIBLE_CACHE_PLUGIN=base ansible-playbook test_gathering_facts.yml -i inventory -v "$@"

ANSIBLE_GATHERING=smart ansible-playbook test_run_once.yml -i inventory -v "$@"

# ensure clean_facts is working properly
ansible-playbook test_prevent_injection.yml -i inventory -v "$@"
@@ -0,0 +1,14 @@
- name: Ensure clean_facts is working properly
hosts: facthost1
gather_facts: false
tasks:
- name: gather 'bad' facts
action: bogus_facts

- name: ensure that the 'bad' facts didn't polute what they are not supposed to
assert:
that:
- "'touch' not in discovered_interpreter_python|default('')"
- "'touch' not in ansible_facts.get('discovered_interpreter_python', '')"
- "'touch' not in ansible_facts.get('ansible_facts', {}).get('discovered_interpreter_python', '')"
- bogus_overwrite is undefined
1 change: 1 addition & 0 deletions test/sanity/ignore.txt
Expand Up @@ -269,6 +269,7 @@ test/integration/targets/collections_relative_imports/collection_root/ansible_co
test/integration/targets/collections_relative_imports/collection_root/ansible_collections/my_ns/my_col/plugins/modules/my_module.py pylint:relative-beyond-top-level
test/integration/targets/expect/files/test_command.py future-import-boilerplate
test/integration/targets/expect/files/test_command.py metaclass-boilerplate
test/integration/targets/gathering_facts/library/bogus_facts shebang
test/integration/targets/get_url/files/testserver.py future-import-boilerplate
test/integration/targets/get_url/files/testserver.py metaclass-boilerplate
test/integration/targets/group/files/gidget.py future-import-boilerplate
Expand Down