[slime-devel] SLIME security patch

Mark Wooding mdw at nsict.org
Sun May 1 01:26:27 UTC 2005


SLIME is very cool; thanks.

It's a shame it's not very secure, though.  Below is a patch which
addresses the two problems I've found:

  * /tmp file vulnerability.  In slime-swank-port-file, the code falls
    back to putting the temporary file used to communicate the port
    number in /tmp.  The filename contains the pid of the running Emacs
    process which is easy to guess.  In ANNOUNCE-SERVER-PORT, the
    server-port file is written :IF-EXISTS :OVERWRITE, which means that
    another user can put a symlink in /tmp/slime.PID pointing at one of
    your precious files and leave SLIME to trash it for you.  Not good.

    I just made it be :IF-EXISTS :ERROR which seems fine given that
    slime-inferior-connect deleted it if it was an ordinary file.

  * Any local user can connect.  I addressed this one quite simply.  If
    there is a file .slime-secret in the user's home directory, then
    SWANK will reject an connection unless the first sexp read through
    it is a string matching the first line of that file.  Similarly, the
    Emacs side will send the correct thing, if it can.  This neatly
    sidesteps all of the hard and system-specific questions about
    generating random numbers and file permissions that more complex
    solutions would involve, largely by leaving them up to the user.

    The downside is that this leaves the system insecure by default,
    which is still bad, but I care less.

    This fix isn't ideal: I suspect there will be problems from a
    mismatch between Emacs's idea of home directory (usually the HOME
    environment variable) and the Common Lisp system's
    USER-HOMEDIR-PATHNAME.  It seems right on Unix; I've no idea what
    it'll do on any other system.  Besides, `.slime-secret' seems a poor
    filename for Windows, even though it will work.  The difficulty here
    is making sure that Emacs and CL agree on which name to use.  I
    decided that, at least for now, a reliable but ugly name was a
    better choice.

My patch is against the code in the Debian 2:1.0.cvs-20050116 package; I
hope that's vaguely useful.  The change is quite simple, though.

diff -ru slime-1.0.cvs/slime.el slime-1.0.cvs+mdw/slime.el
--- slime-1.0.cvs/slime.el	2005-01-16 12:29:52.000000000 +0000
+++ slime-1.0.cvs+mdw/slime.el	2005-04-30 23:48:39.000000000 +0100
@@ -1480,6 +1480,21 @@
   "A list of valid coding systems. 
 Each element is of the form: (NAME MULTIBYTEP CL-NAME)")
 
+(defun slime-secret ()
+  "Finds the magic secret from the user's home directory.  Returns nil
+if the file doesn't exist or is empty; otherwise the first line of the
+file."
+  (condition-case err
+      (with-temp-buffer
+	(insert-file-contents "~/.slime-secret")
+	(goto-char (point-min))
+	(buffer-substring 1
+			  (let ((nl (search-forward "\n" nil t nil)))
+			    (if nl
+				(- nl 1)
+			      (point-max)))))
+    (file-error nil)))
+
 ;;; Interface
 (defun slime-net-connect (host port)
   "Establish a connection with a CL."
@@ -1496,6 +1511,8 @@
       (set-process-coding-system proc 
                                  slime-net-coding-system
                                  slime-net-coding-system))
+    (when-let (secret (slime-secret))
+      (slime-net-send secret proc))
     proc))
 
 (defun slime-make-net-buffer (name)
@@ -2421,6 +2438,8 @@
     (set-process-coding-system stream 
                                slime-net-coding-system 
                                slime-net-coding-system)
+    (when-let (secret (slime-secret))
+      (slime-net-send secret stream))
     stream))
 
 (defun slime-output-string (string)
diff -ru slime-1.0.cvs/swank.lisp slime-1.0.cvs+mdw/swank.lisp
--- slime-1.0.cvs/swank.lisp	2005-01-16 12:29:53.000000000 +0000
+++ slime-1.0.cvs+mdw/swank.lisp	2005-05-01 00:32:01.000000000 +0100
@@ -294,6 +294,24 @@
 (defvar *use-dedicated-output-stream* t)
 (defvar *communication-style* (preferred-communication-style))
 
+(defun slime-secret ()
+  "Finds the magic secret from the user's home directory.  Returns nil
+if the file doesn't exist; otherwise the first line of the file."
+  (with-open-file (in
+                   (merge-pathnames (user-homedir-pathname)
+                                    #+unix #p".slime-secret")
+                   :if-does-not-exist nil)
+    (and in (read-line in nil ""))))
+
+(defun accept-authenticated-connection (&rest args)
+  (let ((new (apply #'accept-connection args))
+        (secret (slime-secret)))
+    (when secret
+      (unless (string= (decode-message new) secret)
+        (close new)
+        (error "Incoming connection doesn't know the password.")))
+    new))
+
 (defun start-server (port-file &key (style *communication-style*)
                      dont-close (external-format *coding-system*))
   "Start the server and write the listen port number to PORT-FILE.
@@ -337,7 +355,8 @@
       port)))
 
 (defun serve-connection (socket style dont-close external-format)
-  (let ((client (accept-connection socket :external-format external-format)))
+  (let ((client (accept-authenticated-connection
+                   socket :external-format external-format)))
     (unless dont-close
       (close-socket socket))
     (let ((connection (create-connection client style external-format)))
@@ -352,7 +371,7 @@
 (defun announce-server-port (file port)
   (with-open-file (s file
                      :direction :output
-                     :if-exists :overwrite
+                     :if-exists :error
                      :if-does-not-exist :create)
     (format s "~S~%" port))
   (simple-announce-function port))
@@ -406,7 +425,8 @@
   (let* ((socket (create-socket *loopback-interface* 0))
          (port (local-port socket)))
     (encode-message `(:open-dedicated-output-stream ,port) socket-io)
-    (accept-connection socket :external-format external-format)))
+    (accept-authenticated-connection
+       socket :external-format external-format)))
 
 (defun handle-request (connection)
   "Read and process one request.  The processing is done in the extend

-- [mdw]



More information about the slime-devel mailing list