posted 2024-05-06
The plotting facilities in Maxima (up to and including v5.47.0) use predictable paths under /tmp that lead to some well-known vulnerabilities. Among other things, an attacker on the same machine may be able to overwrite files that belong to the Maxima user, or inject malicious PostScript into his plots.
The temporary directory used by Maxima is determined in src/init-cl.lisp and, on UNIX systems, will typically be /tmp:
(defun default-tempdir ()
(maxima-parse-dirstring
(let
((tmpdir-windows (maxima-getenv "TEMP"))
(tmpdir-posix (maxima-getenv "TMPDIR"))
(tmpdir-nonstandard1 (maxima-getenv "TMP"))
(tmpdir-nonstandard2 (maxima-getenv "TEMPDIR")))
(cond
((and tmpdir-windows (string/= tmpdir-windows ""))
tmpdir-windows)
((and tmpdir-posix (string/= tmpdir-windows ""))
tmpdir-posix)
((and tmpdir-nonstandard1 (string/= tmpdir-nonstandard1 ""))
tmpdir-nonstandard1)
((and tmpdir-nonstandard2 (string/= tmpdir-nonstandard2 ""))
tmpdir-nonstandard2)
; A fallback for windows if everything else has failed
((string= *autoconf-windows* "true") "C:\\Windows\\temp")
; A fallback for the rest of the operating systems
(t "/tmp")
))))
Prior to commit 51704ccb, several plotting functions use predictable paths within this temporary directory. For example in src/gnuplot_def.lisp we see,
(eq (getf plot-options :gnuplot_term) '$ps)
...
(if (getf plot-options :gnuplot_out_file)
(setq out-file (getf plot-options :gnuplot_out_file))
(setq out-file "maxplot.ps")))
This sets the output filename to maxplot.ps. It is eventually concatenated onto Maxima's temporary directory in src/plot.lisp. When that temporary directory is /tmp, the end result is that an unsafe, predictable, world-writable path is used for the plot:
(%i1) plot2d(sin(x),[x,0,2*%pi],[gnuplot_term,ps]);
...
(%o1) [/tmp/maxout25041.gnuplot, /tmp/maxplot.ps]
The exploits available to a local attacker in this scenario are well-known. In addition, the example above lets the attacker inject malicious PostScript into the user's plot. PostScript is a Turing-complete language, so that is not an awesome situation.
Commit 51704ccb
adds randomness to the temporary file names, making them
near-impossible to guess. This solution isn't perfect because there
exist further corner cases handled by, say, mkstemp
. But
adding the randomness is a huge improvement and likely the best
return on investment given that Maxima is implemented in common lisp,
which does not have mkstemp
or anything like it.