pkgsrc-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
pkg/60710: math/calc: writes to predictable names in /tmp
>Number: 60710
>Category: pkg
>Synopsis: math/calc: writes to predictable names in /tmp
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: pkg-manager
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Thu Sep 10 22:00:00 +0000 2026
>Originator: Showta Ishizaki
>Release: NetBSD 11.0, pkgsrc CVS as of 2026-09-11
>Organization:
>Environment:
System: NetBSD 11.0 amd64
Architecture: x86_64
Machine: amd64
>Description:
math/calc writes the data and command files it feeds to gnuplot into
/tmp, under names that can be worked out in advance.
calc-graph.el:35 (defvar calc-gnuplot-tempfile "/tmp/calc")
calc-graph.el:859 (make-temp-name (concat calc-gnuplot-tempfile ...))
calc-graph.el:490 (write-region tempbuftop (point-max) filename ...)
calc-graph.el:503 (write-region (point-min) (point-max) filename ...)
make-temp-name only invents a name; it does not create the file. Anyone
with write access to /tmp can put a symlink at the name calc is about to
use, and the write follows it. Three call sites take a name this way --
calc-temp-file-name is called at :363, :437 and :502 -- and each is
followed by write-region.
No CVE was ever filed for this. The package is from 1993 and predates
the practice; NVD has nothing for calc, and pkgsrc's own
pkg-vulnerabilities does not list it either. It is however the same
shape as two that pkgsrc did patch in 2008:
CVE-2008-1694 emacs's lib-src/vcdiff, rev1=/tmp/geta$$
-> rev1=`mktemp /tmp/geta.XXXXXXXX`
editors/emacs20/patches/patch-ce
CVE-2008-2142 fast-lock's cache directories, '("." "~/.emacs-flc")
-> '("~/.emacs-flc")
editors/emacs20/patches/patch-cc
The first moved to creating the file atomically; the second moved out
of the shared directory. calc seems to want both, because two of the
Lisps it accepts have no way to create the file atomically.
make-temp-file creates the file as it names it, so nothing can get in
between, but it arrived in Emacs 21.1. math/calc accepts emacs20 as
well (EMACS_VERSIONS_ACCEPTED= emacs21 emacs21nox emacs20 xemacs215
xemacs215nox xemacs214 xemacs214nox), and Emacs 20 has no such
primitive in Lisp, and neither has XEmacs 21.4. So the patch uses
make-temp-file where it exists, and also moves the files out of /tmp
into ~/.calc-tmp, created 0700 first, which is what protects the two
that have no such primitive. Measured on the four Lisps the package
accepts:
make-temp-file make-temp-name
Emacs 20.7 no yes
Emacs 21.4 yes yes
XEmacs 21.4.25 no yes
XEmacs 21.5.36 yes yes
Moving them there brings out a second defect, in two places. The
temporary file name reaches a shell twice, and neither site quotes it:
calc-graph-show-tty
"-c" (format "cat %s >/dev/tty; rm %s" output output)
calc-graph-plot, which calc-graph-print calls with printing set,
through calc-gnuplot-command "!" -- gnuplot's own shell escape
(format command (or tempoutfile calc-gnuplot-print-output))
where command is calc-gnuplot-print-command, "lp %s" by default
While the name was /tmp/calc... it could not hold anything the shell
would look at. A path under the user's home can, and a home directory
with a space in it breaks both commands. The patch quotes both.
shell-quote-argument and set-file-modes are in all four of the above.
The other three places the name reaches gnuplot -- "load" at :504 and
"set output" at :373 and :945 -- already wrap it with prin1-to-string,
which is what gnuplot wants, so they are left alone.
The location is user-visible, so PKGREVISION goes up.
>How-To-Repeat:
The code path is visible without running anything:
$ grep -n 'tempfile\|make-temp-name\|write-region' \
work/calc-2.02f/calc-graph.el
calc-gnuplot-tempfile is "/tmp/calc" at :35; calc-temp-file-name at
:854 hands that prefix to make-temp-name at :859; and the names it
returns are written with write-region at :490 and :503. The suffix
make-temp-name adds is derived from the pid and a counter, so it is
guessable rather than random.
Plotting -- M-x calc, a vector, then g f -- creates those files while
gnuplot is being fed. Anyone who puts a symlink at one of the names
before calc gets there has calc write through it, as the user running
Emacs.
>Fix:
The diff below is against CVS as of 2026-09-11 (math/calc/Makefile
rev 1.30, distinfo rev 1.8). It adds patches/patch-calc-graph.el,
puts its checksum in distinfo, and takes PKGREVISION to 5. patch -p0
from the top of the pkgsrc tree applies all three.
Checked on NetBSD 11.0/amd64. The distfile from the GNU mirror
matches distinfo (SHA512 and size); the tree's patch-aa and patch-ab
apply to it; and this patch then applies as well. Building the
extracted tree with the distribution's own "make compile" gives 42
.elc files and exit 0, both before and after the patch, on all four
Lisps the package accepts:
Emacs 20.7 Emacs 21.4 XEmacs 21.4.25 XEmacs 21.5.36
The only difference in the build output is the one new function name
in the autoload list.
Not tested: plotting through gnuplot itself. The defect and the fix
are both in how the file name is chosen and quoted, which is what was
measured.
If ~/.calc-tmp is not the location you would pick, or you would rather
see this split into the quoting part and the temporary-file part,
please say so -- I am happy to rework it.
Index: math/calc/Makefile
===================================================================
RCS file: /cvsroot/pkgsrc/math/calc/Makefile,v
retrieving revision 1.30
diff -u -u -r1.30 Makefile
--- math/calc/Makefile 14 May 2022 22:25:39 -0000 1.30
+++ math/calc/Makefile 5 Sep 2026 03:56:43 -0000
@@ -2,7 +2,7 @@
DISTNAME= calc-2.02f
PKGNAME= ${EMACS_PKGNAME_PREFIX}${DISTNAME}
-PKGREVISION= 4
+PKGREVISION= 5
CATEGORIES= math
MASTER_SITES= ${MASTER_SITE_GNU:=calc/}
Index: math/calc/distinfo
===================================================================
RCS file: /cvsroot/pkgsrc/math/calc/distinfo,v
retrieving revision 1.8
diff -u -u -r1.8 distinfo
--- math/calc/distinfo 26 Oct 2021 10:55:36 -0000 1.8
+++ math/calc/distinfo 5 Sep 2026 03:56:43 -0000
@@ -5,3 +5,4 @@
Size (calc-2.02f.tar.gz) = 831865 bytes
SHA1 (patch-aa) = 2096bcc555989638f25f3e845e065a62d505b274
SHA1 (patch-ab) = f8634afae8f7236bcf2e4c232e5cd60d5500e0cb
+SHA1 (patch-calc-graph.el) = cb518733ec8ea6ae8fccbddb7d56bbe42d30c151
Index: math/calc/patches/patch-calc-graph.el
===================================================================
RCS file: math/calc/patches/patch-calc-graph.el
diff -N math/calc/patches/patch-calc-graph.el
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ math/calc/patches/patch-calc-graph.el 5 Sep 2026 00:00:00 -0000
@@ -0,0 +1,128 @@
+$NetBSD$
+
+Calc writes the data and command files it feeds to gnuplot into /tmp, under
+names that can be worked out in advance.
+
+ (defvar calc-gnuplot-tempfile "/tmp/calc")
+
+ calc-temp-file-name -> (make-temp-name "/tmp/calcA...")
+ write-region ... filename
+
+make-temp-name only invents a name; it does not create the file. Anyone with
+write access to /tmp can put a symlink at the name Calc is about to use, and
+the write follows it. Three call sites do this (calc-graph.el:363, :437 and
+:502), each followed by write-region.
+
+No CVE was ever filed for this -- the package predates the practice -- but it
+is the same shape as CVE-2008-1694 (emacs's vcdiff) and CVE-2008-2142
+(fast-lock), which pkgsrc patched in editors/emacs20 and emacs21 in 2008.
+
+The first kind of change is to how the name is chosen. make-temp-file
+creates the file as it names it, so nothing can get in between; it is used
+where it exists. Emacs 20.7 and XEmacs 21.4 have no such primitive, so the
+files are moved out of the shared directory altogether, into ~/.calc-tmp
+made 0700 first. editors/emacs20's fast-lock patch takes the same way out,
+dropping "." from the cache directories.
+
+The second kind follows from that. The temporary file name reaches a shell
+in two places, and neither quotes it. While the name was /tmp/calc... it
+could not contain anything the shell would look at; a path under the user's
+home can.
+
+ calc-graph-show-tty
+ "-c" (format "cat %s >/dev/tty; rm %s" output output)
+
+ calc-graph-plot, which calc-graph-print calls with printing set,
+ through calc-gnuplot-command "!" -- gnuplot's own shell escape
+ (format command (or tempoutfile calc-gnuplot-print-output))
+ where command is calc-gnuplot-print-command, "lp %s" by default
+
+The other three places the name reaches gnuplot -- "load" at :504 and "set
+output" at :373 and :945 -- already wrap it with prin1-to-string, which is
+what gnuplot wants, so they are left alone.
+
+shell-quote-argument and set-file-modes are in Emacs 20.7 and 21.4 and in
+XEmacs 21.4.25 and 21.5.36, which are the Lisps this package accepts.
+
+--- calc-graph.el.orig
++++ calc-graph.el
+@@ -32,7 +32,12 @@
+ ;;; Graphics
+
+ ;;; Note that some of the following initial values also occur in calc.el.
+-(defvar calc-gnuplot-tempfile "/tmp/calc")
++(defvar calc-gnuplot-tempfile
++ (expand-file-name "calc" (file-name-as-directory
++ (expand-file-name ".calc-tmp" "~")))
++ "Prefix for the temporary files Calc writes for gnuplot.
++This used to be under /tmp, where the names are predictable and anyone can
++create them first. Keep them in a directory of the user's own instead.")
+
+ (defvar calc-gnuplot-default-device "default")
+ (defvar calc-gnuplot-default-output "STDOUT")
+@@ -516,10 +521,16 @@
+ 'calc-graph-show-tty)))))
+ (if command
+ (if (stringp command)
++ ;; command is a user variable holding a shell command with
++ ;; a %s in it ("lp %s" by default), and calc-gnuplot-command
++ ;; hands it to gnuplot as "!", which is gnuplot's own shell
++ ;; escape. The name filled in is the temporary file, so it
++ ;; needs the same quoting as calc-graph-show-tty.
+ (calc-gnuplot-command
+ "!" (format command
+- (or tempoutfile
+- calc-gnuplot-print-output)))
++ (shell-quote-argument
++ (or tempoutfile
++ calc-gnuplot-print-output))))
+ (if (symbolp command)
+ (funcall command output)
+ (eval command)))))))))
+@@ -851,12 +862,26 @@
+ (setq blank t)))))
+ )
+
++(defun calc-make-temp-file (prefix)
++ "Return the name of a new temporary file starting with PREFIX.
++make-temp-file creates the file as it names it, so nobody can get in
++between; it arrived in Emacs 21.1. Without it the best that can be done
++is to make the directory first, owned by the user and not readable by
++anyone else, and take a name inside it."
++ (let ((dir (file-name-directory prefix)))
++ (or (file-directory-p dir)
++ (progn (make-directory dir t)
++ (set-file-modes dir 448)))) ; 0700
++ (if (fboundp 'make-temp-file)
++ (make-temp-file prefix)
++ (make-temp-name prefix)))
++
+ (defun calc-temp-file-name (num)
+ (while (<= (length calc-graph-file-cache) (1+ num))
+ (setq calc-graph-file-cache (nconc calc-graph-file-cache (list nil))))
+ (car (or (nth (1+ num) calc-graph-file-cache)
+ (setcar (nthcdr (1+ num) calc-graph-file-cache)
+- (list (make-temp-name
++ (list (calc-make-temp-file
+ (concat calc-gnuplot-tempfile
+ (if (<= num 0)
+ (char-to-string (- ?A num))
+@@ -883,9 +908,15 @@
+ (defun calc-graph-show-tty (output)
+ "Default calc-gnuplot-plot-command for \"tty\" output mode.
+ This is useful for tek40xx and other graphics-terminal types."
+- (call-process-region 1 1 shell-file-name
+- nil calc-gnuplot-buffer nil
+- "-c" (format "cat %s >/dev/tty; rm %s" output output))
++ ;; output is a file name, and with "auto" or "tty" output it is the
++ ;; temporary file calc-temp-file-name just made. It is pasted into a
++ ;; shell command, so it has to be quoted: under /tmp it never contained
++ ;; anything the shell would look at, but a path under the user's home
++ ;; can.
++ (let ((q (shell-quote-argument output)))
++ (call-process-region 1 1 shell-file-name
++ nil calc-gnuplot-buffer nil
++ "-c" (format "cat %s >/dev/tty; rm %s" q q)))
+ )
+
+ (defun calc-graph-show-dumb (&optional output)
Home |
Main Index |
Thread Index |
Old Index