From efbd11d492a9f6fa2307c13b1fcc9acb5b24119c Mon Sep 17 00:00:00 2001 From: Paul Harris Date: Mon, 22 Apr 2024 12:57:58 +0800 Subject: [PATCH 1/3] Use a clean, whitelisted environment with Popen (#16118) Do not allow the user's shell environment to leak into the build environment. Instead, create a clean environment with just white-listed environment keys. --- conans/util/runners.py | 57 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/conans/util/runners.py b/conans/util/runners.py index 434bee38ed5..1fe3438e662 100644 --- a/conans/util/runners.py +++ b/conans/util/runners.py @@ -1,4 +1,5 @@ import os +import platform import subprocess import sys import tempfile @@ -32,6 +33,55 @@ def pyinstaller_bundle_env_cleaned(): yield +# Windows (and possibly other platforms) should have a clean environment, +# unpolluted by anything in the user's environment. +# Anything except the bare minimum should be added to the environment through +# conan's environment mechanisms. +# This whitelist could potentially be slimmed down further. +def _env_for_Popen(): + newenv = None + if platform.system() == 'Windows': + whitelist_env_keys = [ + 'ALLUSERSPROFILE', + 'APPDATA', + 'CommonProgramFiles', + 'CommonProgramFiles(x86)', + 'CommonProgramW6432', + 'COMPUTERNAME', + 'ComSpec', + 'DriverData', + 'HOMEDRIVE', + 'HOMEPATH', + 'LOCALAPPDATA', + 'LOGONSERVER', + 'NUMBER_OF_PROCESSORS', + 'OS', + 'PATHEXT', + 'PROCESSOR_ARCHITECTURE', + 'PROCESSOR_IDENTIFIER', + 'PROCESSOR_LEVEL', + 'PROCESSOR_REVISION', + 'ProgramData', + 'ProgramFiles', + 'ProgramFiles(x86)', + 'ProgramW6432', + 'PUBLIC', + 'SESSIONNAME', + 'SystemDrive', + 'SystemRoot', + 'TEMP', + 'TMP', + 'USERDOMAIN', + 'USERDOMAIN_ROAMINGPROFILE', + 'USERNAME', + 'USERPROFILE', + 'windir' + ] + newenv = { key: os.environ[key] for key in whitelist_env_keys } + newenv['Path'] = 'C:\\WINDOWS\\system32;C:\\WINDOWS' + return newenv + + def conan_run(command, stdout=None, stderr=None, cwd=None, shell=True): """ @param shell: @@ -48,7 +98,7 @@ def conan_run(command, stdout=None, stderr=None, cwd=None, shell=True): with pyinstaller_bundle_env_cleaned(): try: - proc = subprocess.Popen(command, shell=shell, stdout=out, stderr=err, cwd=cwd) + proc = subprocess.Popen(command, shell=shell, stdout=out, stderr=err, cwd=cwd, env=_env_for_Popen()) except Exception as e: raise ConanException("Error while running cmd\nError: %s" % (str(e))) @@ -65,7 +115,8 @@ def conan_run(command, stdout=None, stderr=None, cwd=None, shell=True): def detect_runner(command): # Running detect.py automatic detection of profile proc = subprocess.Popen(command, shell=True, bufsize=1, universal_newlines=True, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + env=_env_for_Popen()) output_buffer = [] while True: @@ -88,7 +139,7 @@ def check_output_runner(cmd, stderr=None, ignore_error=False): # We don't want stderr to print warnings that will mess the pristine outputs stderr = stderr or subprocess.PIPE command = '{} > "{}"'.format(cmd, tmp_file) - process = subprocess.Popen(command, shell=True, stderr=stderr) + process = subprocess.Popen(command, shell=True, stderr=stderr, env=_env_for_Popen()) stdout, stderr = process.communicate() if process.returncode and not ignore_error: From 6cbccdae441c64dfdafb1bef08c7c278d5299396 Mon Sep 17 00:00:00 2001 From: Paul Harris Date: Mon, 22 Apr 2024 15:34:53 +0800 Subject: [PATCH 2/3] Also include conan's python path in env's PATH --- conans/util/runners.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/conans/util/runners.py b/conans/util/runners.py index 1fe3438e662..405a503ebcb 100644 --- a/conans/util/runners.py +++ b/conans/util/runners.py @@ -78,7 +78,11 @@ def _env_for_Popen(): 'windir' ] newenv = { key: os.environ[key] for key in whitelist_env_keys } - newenv['Path'] = 'C:\\WINDOWS\\system32;C:\\WINDOWS' + # Also get the path to conan's python, as some packages assume access to python + # eg dav1d + # This will also give access to ninja.exe and whatever else is installed in the devenv + python_path = os.path.dirname(sys.executable) + newenv['PATH'] = f'C:\\WINDOWS\\system32;C:\\WINDOWS;{python_path}' return newenv From 5fe4cc9393497cf66dc00bd53137362b66fbd1a0 Mon Sep 17 00:00:00 2001 From: Paul Harris Date: Tue, 23 Apr 2024 15:53:09 +0800 Subject: [PATCH 3/3] Further hacks to test the idea --- conan/cli/cli.py | 50 ++++++++++++++++++++++++++++++++++ conans/util/runners.py | 61 +++--------------------------------------- 2 files changed, 53 insertions(+), 58 deletions(-) diff --git a/conan/cli/cli.py b/conan/cli/cli.py index a9a420c5838..ddd8a253398 100644 --- a/conan/cli/cli.py +++ b/conan/cli/cli.py @@ -242,6 +242,54 @@ def _warn_python_version(): ConanOutput().warning("Python 3.6 is end-of-life since 2021. " "Conan future versions will drop support for it, " "please upgrade Python", warn_tag="deprecated") +def _clear_env(): + if True: # if platform.system() == 'Windows': + whitelist_env_keys = [ + 'ALLUSERSPROFILE', + 'APPDATA', + 'COMMONPROGRAMFILES(X86)', + 'COMMONPROGRAMFILES', + 'COMMONPROGRAMW6432', + 'COMPUTERNAME', + 'COMSPEC', + 'DRIVERDATA', + 'HOMEDRIVE', + 'HOMEPATH', + 'LOCALAPPDATA', + 'LOGONSERVER', + 'NUMBER_OF_PROCESSORS', + 'OS', + 'PATHEXT', + 'PROCESSOR_ARCHITECTURE', + 'PROCESSOR_IDENTIFIER', + 'PROCESSOR_LEVEL', + 'PROCESSOR_REVISION', + 'PROGRAMDATA', + 'PROGRAMFILES(X86)', + 'PROGRAMFILES', + 'PROGRAMW6432', + 'PSMODULEPATH', + 'PUBLIC', + 'SESSIONNAME', + 'SYSTEMDRIVE', + 'SYSTEMROOT', + 'SYSTEMROOT', + 'TEMP', + 'TMP', + 'USERDOMAIN', + 'USERDOMAIN_ROAMINGPROFILE', + 'USERNAME', + 'USERPROFILE', + 'WINDIR', + ] + for key in list(os.environ.keys()): + if key not in whitelist_env_keys: + del os.environ[key] + # Also get the path to conan's python, as some packages assume access to python + # eg dav1d + # This will also give access to ninja.exe and whatever else is installed in the devenv + python_path = os.path.dirname(sys.executable) + os.environ['PATH'] = f'C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0;{python_path}' def main(args): @@ -285,6 +333,8 @@ def ctrl_break_handler(_, __): if sys.platform == 'win32': signal.signal(signal.SIGBREAK, ctrl_break_handler) + _clear_env() + cli = Cli(conan_api) error = SUCCESS try: diff --git a/conans/util/runners.py b/conans/util/runners.py index 405a503ebcb..434bee38ed5 100644 --- a/conans/util/runners.py +++ b/conans/util/runners.py @@ -1,5 +1,4 @@ import os -import platform import subprocess import sys import tempfile @@ -33,59 +32,6 @@ def pyinstaller_bundle_env_cleaned(): yield -# Windows (and possibly other platforms) should have a clean environment, -# unpolluted by anything in the user's environment. -# Anything except the bare minimum should be added to the environment through -# conan's environment mechanisms. -# This whitelist could potentially be slimmed down further. -def _env_for_Popen(): - newenv = None - if platform.system() == 'Windows': - whitelist_env_keys = [ - 'ALLUSERSPROFILE', - 'APPDATA', - 'CommonProgramFiles', - 'CommonProgramFiles(x86)', - 'CommonProgramW6432', - 'COMPUTERNAME', - 'ComSpec', - 'DriverData', - 'HOMEDRIVE', - 'HOMEPATH', - 'LOCALAPPDATA', - 'LOGONSERVER', - 'NUMBER_OF_PROCESSORS', - 'OS', - 'PATHEXT', - 'PROCESSOR_ARCHITECTURE', - 'PROCESSOR_IDENTIFIER', - 'PROCESSOR_LEVEL', - 'PROCESSOR_REVISION', - 'ProgramData', - 'ProgramFiles', - 'ProgramFiles(x86)', - 'ProgramW6432', - 'PUBLIC', - 'SESSIONNAME', - 'SystemDrive', - 'SystemRoot', - 'TEMP', - 'TMP', - 'USERDOMAIN', - 'USERDOMAIN_ROAMINGPROFILE', - 'USERNAME', - 'USERPROFILE', - 'windir' - ] - newenv = { key: os.environ[key] for key in whitelist_env_keys } - # Also get the path to conan's python, as some packages assume access to python - # eg dav1d - # This will also give access to ninja.exe and whatever else is installed in the devenv - python_path = os.path.dirname(sys.executable) - newenv['PATH'] = f'C:\\WINDOWS\\system32;C:\\WINDOWS;{python_path}' - return newenv - - def conan_run(command, stdout=None, stderr=None, cwd=None, shell=True): """ @param shell: @@ -102,7 +48,7 @@ def conan_run(command, stdout=None, stderr=None, cwd=None, shell=True): with pyinstaller_bundle_env_cleaned(): try: - proc = subprocess.Popen(command, shell=shell, stdout=out, stderr=err, cwd=cwd, env=_env_for_Popen()) + proc = subprocess.Popen(command, shell=shell, stdout=out, stderr=err, cwd=cwd) except Exception as e: raise ConanException("Error while running cmd\nError: %s" % (str(e))) @@ -119,8 +65,7 @@ def conan_run(command, stdout=None, stderr=None, cwd=None, shell=True): def detect_runner(command): # Running detect.py automatic detection of profile proc = subprocess.Popen(command, shell=True, bufsize=1, universal_newlines=True, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - env=_env_for_Popen()) + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) output_buffer = [] while True: @@ -143,7 +88,7 @@ def check_output_runner(cmd, stderr=None, ignore_error=False): # We don't want stderr to print warnings that will mess the pristine outputs stderr = stderr or subprocess.PIPE command = '{} > "{}"'.format(cmd, tmp_file) - process = subprocess.Popen(command, shell=True, stderr=stderr, env=_env_for_Popen()) + process = subprocess.Popen(command, shell=True, stderr=stderr) stdout, stderr = process.communicate() if process.returncode and not ignore_error: