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))))