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