Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP1:GA
aws-efs-utils
CVE-2022-46174.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File CVE-2022-46174.patch of Package aws-efs-utils
Summary: This removes all potential concurrency issues during tls port selection and ensures that concurrent mounts will never select the same port. Patch for https://github.com/aws/efs-utils/commit/f3a8f88167d55caa2f78aeb72d4dc1987a9ed62d Index: efs-utils-1.7/src/mount_efs/__init__.py =================================================================== --- efs-utils-1.7.orig/src/mount_efs/__init__.py +++ efs-utils-1.7/src/mount_efs/__init__.py @@ -169,7 +169,7 @@ def get_tls_port_range(config): return lower_bound, upper_bound -def choose_tls_port(config): +def choose_tls_port(config, state_file_dir): lower_bound, upper_bound = get_tls_port_range(config) tls_ports = list(range(lower_bound, upper_bound)) @@ -183,10 +183,17 @@ def choose_tls_port(config): sock = socket.socket() for tls_port in ports_to_try: + mount = find_existing_mount_using_tls_port(state_file_dir, tls_port) + if mount: + logging.debug( + "Skip binding TLS port %s as it is already assigned to %s", + tls_port, + mount, + ) + continue try: sock.bind(('localhost', tls_port)) - sock.close() - return tls_port + return sock except socket.error: continue @@ -422,23 +429,52 @@ def bootstrap_tls(config, init_system, d if not os.path.exists(state_file_dir): create_state_file_dir(config, state_file_dir) - tls_port = choose_tls_port(config) - options['tlsport'] = tls_port - verify_level = int(options.get('verify', DEFAULT_STUNNEL_VERIFY_LEVEL)) - options['verify'] = verify_level - - stunnel_config_file = write_stunnel_config_file(config, state_file_dir, fs_id, mountpoint, tls_port, dns_name, verify_level) + tls_port_sock = choose_tls_port(config, state_file_dir) + tls_port = get_tls_port_from_sock(tls_port_sock) - tunnel_args = ['/usr/sbin/stunnel', stunnel_config_file] + try: + options['tlsport'] = tls_port + verify_level = int(options.get('verify', DEFAULT_STUNNEL_VERIFY_LEVEL)) + options['verify'] = verify_level + + stunnel_config_file = write_stunnel_config_file(config, state_file_dir, fs_id, mountpoint, tls_port, dns_name, verify_level) + + tunnel_args = ['/usr/sbin/stunnel', stunnel_config_file] + + temp_tls_state_file = write_tls_tunnel_state_file( + fs_id, + mountpoint, + tls_port, + -1, + tunnel_args, + [stunnel_config_file], + state_file_dir + ) + finally: + logging.debug("Closing socket used to choose TLS port %s.", tls_port) + tls_port_sock.close() - # launch the tunnel in a process group so if it has any child processes, they can be killed easily by the mount watchdog + # launch the tunnel in a process group so if it has any child processes, + # they can be killed easily by the mount watchdog logging.info('Starting TLS tunnel: "%s"', ' '.join(tunnel_args)) tunnel_proc = subprocess.Popen( - tunnel_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=os.setsid, close_fds=True) + tunnel_args, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + preexec_fn=os.setsid, + close_fds=True + ) logging.info('Started TLS tunnel, pid: %d', tunnel_proc.pid) - temp_tls_state_file = write_tls_tunnel_state_file(fs_id, mountpoint, tls_port, tunnel_proc.pid, tunnel_args, - [stunnel_config_file], state_file_dir) + temp_tls_state_file = write_tls_tunnel_state_file( + fs_id, + mountpoint, + tls_port, + tunnel_proc.pid, + tunnel_args, + [stunnel_config_file], + state_file_dir + ) try: yield tunnel_proc @@ -677,6 +713,26 @@ def check_unsupported_options(options): del options[unsupported_option] +def find_existing_mount_using_tls_port(state_file_dir, tls_port): + if not os.path.exists(state_file_dir): + logging.debug( + "State file dir %s does not exist, assuming no existing mount using tls port %s", + state_file_dir, + tls_port, + ) + return None + + for fname in os.listdir(state_file_dir): + if fname.endswith(".%s" % tls_port): + return fname + + return None + + +def get_tls_port_from_sock(tls_port_sock): + return tls_port_sock.getsockname()[1] + + def main(): parse_arguments_early_exit() Index: efs-utils-1.7/test/mount_efs_test/test_bootstrap_tls.py =================================================================== --- efs-utils-1.7.orig/test/mount_efs_test/test_bootstrap_tls.py +++ efs-utils-1.7/test/mount_efs_test/test_bootstrap_tls.py @@ -30,9 +30,11 @@ MOCK_CONFIG = MagicMock() @pytest.fixture(autouse=True) def setup(mocker): + sock = MagicMock() + sock.getsocketname.return_value = ['', DEFAULT_TLS_PORT] mocker.patch('mount_efs.start_watchdog') mocker.patch('mount_efs.get_tls_port_range', return_value=(DEFAULT_TLS_PORT, DEFAULT_TLS_PORT + 10)) - mocker.patch('mount_efs.choose_tls_port', return_value=DEFAULT_TLS_PORT) + mocker.patch('mount_efs.choose_tls_port', return_value=sock) mocker.patch('mount_efs.write_tls_tunnel_state_file') mocker.patch('mount_efs.write_stunnel_config_file', return_value=EXPECTED_STUNNEL_CONFIG_FILE) mocker.patch('os.rename') Index: efs-utils-1.7/test/mount_efs_test/test_choose_tls_port.py =================================================================== --- efs-utils-1.7.orig/test/mount_efs_test/test_choose_tls_port.py +++ efs-utils-1.7/test/mount_efs_test/test_choose_tls_port.py @@ -26,34 +26,40 @@ def _get_config(): return config -def test_choose_tls_port_first_try(mocker): - mocker.patch('socket.socket', return_value=MagicMock()) +def test_choose_tls_port_first_try(mocker, tmpdir): + sock_mock = MagicMock() + sock_mock.getsocketname.return_value = ['', 20049] + mocker.patch('socket.socket', return_value=sock_mock) - tls_port = mount_efs.choose_tls_port(_get_config()) + state_file_dir = str(tmpdir) + sock = mount_efs.choose_tls_port(_get_config(), state_file_dir) - assert DEFAULT_TLS_PORT_RANGE_LOW <= tls_port <= DEFAULT_TLS_PORT_RANGE_HIGH + assert DEFAULT_TLS_PORT_RANGE_LOW <= sock.getsocketname()[1] <= DEFAULT_TLS_PORT_RANGE_HIGH -def test_choose_tls_port_second_try(mocker): +def test_choose_tls_port_second_try(mocker, tmpdir): bad_sock = MagicMock() bad_sock.bind.side_effect = [socket.error, None] + bad_sock.getsocketname.return_value = ['', 20050] mocker.patch('socket.socket', return_value=bad_sock) + state_file_dir = str(tmpdir) - tls_port = mount_efs.choose_tls_port(_get_config()) + sock = mount_efs.choose_tls_port(_get_config(), state_file_dir) - assert DEFAULT_TLS_PORT_RANGE_LOW <= tls_port <= DEFAULT_TLS_PORT_RANGE_HIGH + assert DEFAULT_TLS_PORT_RANGE_LOW <= sock.getsocketname()[1] <= DEFAULT_TLS_PORT_RANGE_HIGH assert 2 == bad_sock.bind.call_count -def test_choose_tls_port_never_succeeds(mocker, capsys): +def test_choose_tls_port_never_succeeds(mocker, capsys, tmpdir): bad_sock = MagicMock() bad_sock.bind.side_effect = socket.error() mocker.patch('socket.socket', return_value=bad_sock) + state_file_dir = str(tmpdir) with pytest.raises(SystemExit) as ex: - mount_efs.choose_tls_port(_get_config()) + mount_efs.choose_tls_port(_get_config(), state_file_dir) assert 0 != ex.value.code @@ -61,3 +67,4 @@ def test_choose_tls_port_never_succeeds( assert 'Failed to locate an available port' in err assert DEFAULT_TLS_PORT_RANGE_HIGH - DEFAULT_TLS_PORT_RANGE_LOW == bad_sock.bind.call_count +
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor