Safety And The Lisp Read Function

For all my blathering about security, here’s a potential exploit in Common Lisp that I never thought about. William Halliburton has a nice explanation of Lisp’s read function and the assoicated read-macro #.. When read sees the sequence #. it will evaluate the next Lisp object that it reads. For example, given the following inputs to read the corresponding object is returned as the result of the read:

(+ 1 (/ 8 4)) → (+ 1 (/ 8 4))
#.(+ 1 (/ 8 4)) → 3
(+ 1 #.(/ 8 4)) → (+ 1 2)

That’s pretty neat but as Halliburton points out it also poses a security threat because a user can use it to execute arbitrary code in a Lisp program that naively reads data from the user.

Follow the link for a more complete explanation of the #. read-macro, an example of using it for an exploit, and a simple safe-read function that prevents the problem.

If you’d like to play around with read and #. to see how they act and what they return, here’s a function that acts as a REPL without the evaluation that you can use.

(defun rpl ()
  "A REPL without the evaluate. Type (quit) to exit."
  (princ "rpl> ")
  (let ((obj (read)))
    (prin1 obj)
    (terpri)
    (unless (equal obj '(quit))
      (rpl))))
This entry was posted in Programming and tagged . Bookmark the permalink.