From 05f159a152f9c4a65685556080f1a655dca41b7c Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Tue, 25 Apr 2023 10:18:45 -0400 Subject: [PATCH] Fixed Windows-specific crash when multiple threads are used (#152). --- PACKAGING.md | 6 +++--- src/ssh_audit/ssh_audit.py | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/PACKAGING.md b/PACKAGING.md index 9d50532..655bfb4 100644 --- a/PACKAGING.md +++ b/PACKAGING.md @@ -2,12 +2,12 @@ An executable can only be made on a Windows host because the PyInstaller tool (https://www.pyinstaller.org/) does not support cross-compilation. -1.) Install Python v3.9.x from https://www.python.org/. To make life easier, check the option to add Python to the PATH environment variable. +1.) Install Python v3.11.x from https://www.python.org/. To make life easier, check the option to add Python to the PATH environment variable. -2.) Using pip, install pyinstaller and colorama: +2.) Using pip, install pyinstaller, colorama, and idna: ``` - pip install pyinstaller colorama + pip install -U pyinstaller colorama idna ``` 3.) Install Cygwin (https://www.cygwin.com/). diff --git a/src/ssh_audit/ssh_audit.py b/src/ssh_audit/ssh_audit.py index bc86153..bc6099b 100755 --- a/src/ssh_audit/ssh_audit.py +++ b/src/ssh_audit/ssh_audit.py @@ -61,6 +61,9 @@ from ssh_audit.ssh_socket import SSH_Socket from ssh_audit.utils import Utils from ssh_audit.versionvulnerabilitydb import VersionVulnerabilityDB + +no_idna_workaround = False + # Only import colorama under Windows. Other OSes can natively handle terminal colors. if sys.platform == 'win32': try: @@ -69,6 +72,14 @@ if sys.platform == 'win32': except ImportError: pass + # This is a workaround for a Python bug that causes a crash on Windows when multiple threads are used (see https://github.com/python/cpython/issues/73474). Importing the idna module and using it in a no-op seems to fix the issue. Otherwise, if idna isn't available at run-time, force single threaded scans. + try: + import idna # noqa: F401 + + ''.encode('idna') + except ImportError: + no_idna_workaround = True + def usage(uout: OutputBuffer, err: Optional[str] = None) -> None: retval = exitcodes.GOOD @@ -753,8 +764,15 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[. aconf.policy_file = a elif o in ('-T', '--targets'): aconf.target_file = a + + # If we're on Windows, and we can't use the idna workaround, force only one thread to be used (otherwise a crash would occur). + if no_idna_workaround: + print("\nWARNING: the idna module was not found on this system, thus only single-threaded scanning will be done (this is a workaround for this Windows-specific crash: https://github.com/python/cpython/issues/73474). Multi-threaded scanning can be enabled by installing the idna module (pip install idna).\n") + aconf.threads = 1 elif o == '--threads': aconf.threads = int(a) + if no_idna_workaround: + aconf.threads = 1 elif o in ('-L', '--list-policies'): aconf.list_policies = True elif o == '--lookup':