Disable rsh synchronize rsync_opts

This change prevents executor host command execution through a
malicious rsh synchronize rsync_opts.

Fixes bug #2006526

Change-Id: I3cd17ca91410394f164d8ea7cd91a1ea5890f998
This commit is contained in:
Tristan Cacqueray
2019-09-10 23:41:28 +00:00
parent e43bec54d5
commit e4f3f48fef
6 changed files with 57 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
---
security:
- |
The synchronize rsh rsync_opts is now prohibited for security reasons
as it could be used to circumvent executor host command execution
restrictions.

View File

@@ -16,6 +16,8 @@
mode: pull
src: "{{ destdir.path }}/"
verify_host: true
environment:
OK: "we can use custom env"
- name: Validate push
stat:
@@ -39,6 +41,8 @@
dest: "{{ destdir.path }}/pull/"
mode: push
src: "{{ zuul.executor.log_root }}/push"
rsync_opts:
- "--safe-links"
verify_host: true
- name: Validate pull

View File

@@ -0,0 +1,8 @@
- hosts: all
tasks:
- synchronize:
rsync_opts:
- "--rsh={{ zuul.executor.log_root }}/oops"
src: "/proc/cmdline"
dest: "{{ zuul.executor.log_root }}/noop"
mode: pull

View File

@@ -0,0 +1,8 @@
- hosts: all
tasks:
- synchronize:
src: "/proc/cmdline"
dest: "{{ zuul.executor.log_root }}/noop"
mode: pull
environment:
RSYNC_RSH: "{{ zuul.executor.log_root }}/oops"

View File

@@ -20,6 +20,7 @@ from tests.base import AnsibleZuulTestCase, FIXTURE_DIR
ERROR_ACCESS_OUTSIDE = "Accessing files from outside the working dir"
ERROR_SYNC_TO_OUTSIDE = "Syncing files to outside the working dir"
ERROR_SYNC_FROM_OUTSIDE = "Syncing files from outside the working dir"
ERROR_SYNC_RSH = "Using custom synchronize rsh is prohibited"
class TestActionModules25(AnsibleZuulTestCase):
@@ -96,6 +97,10 @@ class TestActionModules25(AnsibleZuulTestCase):
self._run_job('assemble-bad-dir-with-symlink', 'FAILURE',
ERROR_ACCESS_OUTSIDE)
def test_synchronize_rsh_fail(self):
self._run_job('synchronize-rsh-bad', 'FAILURE', ERROR_SYNC_RSH)
self._run_job('synchronize-rsh-env-bad', 'FAILURE', ERROR_SYNC_RSH)
def test_command_module(self):
self._run_job('command-good', 'SUCCESS')

View File

@@ -18,6 +18,26 @@ from zuul.ansible import paths
synchronize = paths._import_ansible_action_plugin("synchronize")
def is_opt_prohibited(rsync_arg):
prohibited_opts = (
"--rsh",
"-e",
)
return any(filter(lambda opt: rsync_arg.startswith(opt), prohibited_opts))
def is_env_prohibited(env_keys):
prohibited_env = (
"RSYNC_RSH",
)
return any(filter(lambda env: env in prohibited_env, env_keys))
def is_prohibited(rsync_opts, environment):
return (any(filter(is_opt_prohibited, list(map(str.strip, rsync_opts)))) or
any(filter(is_env_prohibited, list(map(dict.keys, environment)))))
class ActionModule(synchronize.ActionModule):
def run(self, tmp=None, task_vars=None):
@@ -40,6 +60,12 @@ class ActionModule(synchronize.ActionModule):
self._task.args['rsync_opts'] = []
if '--safe-links' not in self._task.args['rsync_opts']:
self._task.args['rsync_opts'].append('--safe-links')
if is_prohibited(
self._task.args.get('rsync_opts', []),
self._task.environment if self._task.environment else {}):
return dict(
failed=True,
msg="Using custom synchronize rsh is prohibited")
if mode == 'push' and not paths._is_safe_path(
source, allow_trusted=True):