diff --git a/lib/matplotlib/backends/backend_pgf.py b/lib/matplotlib/backends/backend_pgf.py index 48b6e8ac152c..2d2e24c3286c 100644 --- a/lib/matplotlib/backends/backend_pgf.py +++ b/lib/matplotlib/backends/backend_pgf.py @@ -281,7 +281,7 @@ def _setup_latex_process(self, *, expect_reply=True): # it. try: self.latex = subprocess.Popen( - [mpl.rcParams["pgf.texsystem"], "-halt-on-error"], + [mpl.rcParams["pgf.texsystem"], "-halt-on-error", "-no-shell-escape"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, encoding="utf-8", cwd=self.tmpdir) except FileNotFoundError as err: @@ -848,7 +848,7 @@ def print_pdf(self, fname_or_fh, *, metadata=None, **kwargs): texcommand = mpl.rcParams["pgf.texsystem"] cbook._check_and_log_subprocess( [texcommand, "-interaction=nonstopmode", "-halt-on-error", - "figure.tex"], _log, cwd=tmpdir) + "-no-shell-escape", "figure.tex"], _log, cwd=tmpdir) with ((tmppath / "figure.pdf").open("rb") as orig, cbook.open_file_cm(fname_or_fh, "wb") as dest): shutil.copyfileobj(orig, dest) # copy file contents to target @@ -965,7 +965,7 @@ def _run_latex(self): tex_source.write_bytes(self._file.getvalue()) cbook._check_and_log_subprocess( [texcommand, "-interaction=nonstopmode", "-halt-on-error", - tex_source], + "-no-shell-escape", tex_source], _log, cwd=tmpdir) shutil.move(tex_source.with_suffix(".pdf"), self._output_name) diff --git a/lib/matplotlib/backends/backend_ps.py b/lib/matplotlib/backends/backend_ps.py index 66164d4d270e..b7fbbf59d778 100644 --- a/lib/matplotlib/backends/backend_ps.py +++ b/lib/matplotlib/backends/backend_ps.py @@ -1256,8 +1256,9 @@ def _convert_psfrags(tmppath, psfrags, paper_width, paper_height, orientation): with TemporaryDirectory() as tmpdir: psfile = os.path.join(tmpdir, "tmp.ps") + # -R1 is a security flag used to prevent shell command execution cbook._check_and_log_subprocess( - ['dvips', '-q', '-R0', '-o', psfile, dvifile], _log) + ['dvips', '-q', '-R1', '-o', psfile, dvifile], _log) shutil.move(psfile, tmppath) # check if the dvips created a ps in landscape paper. Somehow, @@ -1301,7 +1302,7 @@ def gs_distill(tmpfile, eps=False, ptype='letter', bbox=None, rotated=False): cbook._check_and_log_subprocess( [mpl._get_executable_info("gs").executable, - "-dBATCH", "-dNOPAUSE", "-r%d" % dpi, "-sDEVICE=ps2write", + "-dBATCH", "-dNOPAUSE", "-dSAFER", "-r%d" % dpi, "-sDEVICE=ps2write", *paper_option, f"-sOutputFile={psfile}", tmpfile], _log) @@ -1345,6 +1346,7 @@ def xpdf_distill(tmpfile, eps=False, ptype='letter', bbox=None, rotated=False): # happy (https://ghostscript.com/doc/9.56.1/Use.htm#MS_Windows). cbook._check_and_log_subprocess( ["ps2pdf", + "-dSAFER", "-dAutoFilterColorImages#false", "-dAutoFilterGrayImages#false", "-sAutoRotatePages#None", diff --git a/lib/matplotlib/testing/__init__.py b/lib/matplotlib/testing/__init__.py index a838a6b09b32..febe28ae4185 100644 --- a/lib/matplotlib/testing/__init__.py +++ b/lib/matplotlib/testing/__init__.py @@ -196,7 +196,8 @@ def _check_for_pgf(texsystem): """, encoding="utf-8") try: subprocess.check_call( - [texsystem, "-halt-on-error", str(tex_path)], cwd=tmpdir, + [texsystem, "-halt-on-error", "-no-shell-escape", + str(tex_path)], cwd=tmpdir, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) except (OSError, subprocess.CalledProcessError): return False diff --git a/lib/matplotlib/tests/test_dviread.py b/lib/matplotlib/tests/test_dviread.py index 33fe9bb150d2..8c2ab203d17f 100644 --- a/lib/matplotlib/tests/test_dviread.py +++ b/lib/matplotlib/tests/test_dviread.py @@ -69,9 +69,9 @@ def test_dviread(tmp_path, engine, monkeypatch): shutil.copy(dirpath / "test.tex", tmp_path) shutil.copy(cbook._get_data_path("fonts/ttf/DejaVuSans.ttf"), tmp_path) cmd, fmt = { - "pdflatex": (["latex"], "dvi"), - "xelatex": (["xelatex", "-no-pdf"], "xdv"), - "lualatex": (["lualatex", "-output-format=dvi"], "dvi"), + "pdflatex": (["latex", "-no-shell-escape"], "dvi"), + "xelatex": (["xelatex", "-no-pdf", "-no-shell-escape"], "xdv"), + "lualatex": (["lualatex", "-output-format=dvi", "-no-shell-escape"], "dvi"), }[engine] if shutil.which(cmd[0]) is None: pytest.skip(f"{cmd[0]} is not available") @@ -119,7 +119,8 @@ def test_dviread_pk(tmp_path): \end{document} """) subprocess_run_for_testing( - ["latex", "test.tex"], cwd=tmp_path, check=True, capture_output=True) + ["latex", "-no-shell-escape", "test.tex"], + cwd=tmp_path, check=True, capture_output=True) with dr.Dvi(tmp_path / "test.dvi", None) as dvi: pages = [*dvi] data = [ diff --git a/lib/matplotlib/texmanager.py b/lib/matplotlib/texmanager.py index 35651a94aa85..58263088531a 100644 --- a/lib/matplotlib/texmanager.py +++ b/lib/matplotlib/texmanager.py @@ -299,8 +299,8 @@ def make_dvi(cls, tex, fontsize): Path(tmpdir, "file.tex").write_text( cls._get_tex_source(tex, fontsize), encoding='utf-8') cls._run_checked_subprocess( - ["latex", "-interaction=nonstopmode", "--halt-on-error", - "file.tex"], tex, cwd=tmpdir) + ["latex", "-interaction=nonstopmode", "-halt-on-error", + "-no-shell-escape", "file.tex"], tex, cwd=tmpdir) Path(tmpdir, "file.dvi").replace(dvipath) # Also move the tex source to the main cache directory, but # only for backcompat.