From 36cebad4c0df355c245821b72c5bfe7b0b095087 Mon Sep 17 00:00:00 2001 From: Alex Vandiver Date: Tue, 7 Dec 2021 20:55:17 +0000 Subject: [PATCH] CVE-2021-43799: During upgrades, restart rabbitmq if necessary. Check if it is listening on a public interface on port 25672, and if so shut it down so it can pick up the new configuration. --- scripts/lib/upgrade-zulip-stage-2 | 21 +++++++++++++++++++++ scripts/lib/zulip_tools.py | 18 ++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/scripts/lib/upgrade-zulip-stage-2 b/scripts/lib/upgrade-zulip-stage-2 index 4c11212a1b..05a5710060 100755 --- a/scripts/lib/upgrade-zulip-stage-2 +++ b/scripts/lib/upgrade-zulip-stage-2 @@ -31,6 +31,7 @@ from scripts.lib.zulip_tools import ( get_config, get_config_file, get_tornado_ports, + listening_publicly, parse_os_release, su_to_zulip, ) @@ -101,6 +102,21 @@ tornado_processes = len(get_tornado_ports(config_file)) IS_SERVER_UP = True +# Check if rabbitmq port 25672 is listening on anything except 127.0.0.1 +rabbitmq_dist_listen = listening_publicly(25672) +if args.skip_puppet and rabbitmq_dist_listen: + logging.error( + "RabbitMQ is publicly-accessible on %s; this is a security vulnerability!", + ", ".join(rabbitmq_dist_listen), + ) + logging.error( + "To fix the above security issue, re-run the upgrade without --skip-puppet " + "(which may be set in /etc/zulip/zulip.conf), in order to restart the " + "necessary services. Running zulip-puppet-apply by itself is not sufficient." + ) + sys.exit(1) + + def shutdown_server() -> None: global IS_SERVER_UP @@ -275,6 +291,11 @@ if (not args.skip_puppet or migrations_needed) and IS_SERVER_UP: # state. shutdown_server() +if rabbitmq_dist_listen: + shutdown_server() + logging.info("Shutting down rabbitmq to adjust its ports...") + subprocess.check_call(["/usr/sbin/service", "rabbitmq-server", "stop"]) + # Adjust Puppet class names for the manifest renames in the 4.0 release class_renames = { "zulip::app_frontend": "zulip::profile::app_frontend", diff --git a/scripts/lib/zulip_tools.py b/scripts/lib/zulip_tools.py index 5811141c82..18f8d1359e 100755 --- a/scripts/lib/zulip_tools.py +++ b/scripts/lib/zulip_tools.py @@ -625,6 +625,24 @@ def deport(netloc: str) -> str: return "[" + r.hostname + "]" if ":" in r.hostname else r.hostname +def listening_publicly(port: int) -> List[str]: + filter = f"sport = :{port} and not src 127.0.0.1:{port} and not src [::1]:{port}" + # Parse lines that look like this: + # tcp LISTEN 0 128 0.0.0.0:25672 0.0.0.0:* + lines = ( + subprocess.check_output( + ["/bin/ss", "-Hnl", filter], + universal_newlines=True, + # Hosts with IPv6 disabled will get "RTNETLINK answers: Invalid + # argument"; eat stderr to hide that + stderr=subprocess.DEVNULL, + ) + .strip() + .splitlines() + ) + return [line.split()[4] for line in lines] + + if __name__ == "__main__": cmd = sys.argv[1] if cmd == "make_deploy_path":