It’s so conventional that he de-listed the article but keeps it published and available by URL
> By promoting themselves from data to code, hijackers on September 11th promoted box-cutters into 400,000 lb. incendiary bombs
Published September 2001
The code/data rhetoric is not exclusively an earmark of Lisp. A primary concern in security are situations in which what is intended to be data allows for a surprising malicious use whereby it effectively becomes a way to program behaviors into the software which processes the data.
For instance, Winamp being exploited by loading a specially crafted MP3 playlist file is an instance of data becoming code; no Lisp in sight. Code being a flipside of data, in the context of security, is simply the consequence of the Von Neumann model.
Graham is arguing for compartments; exactly why we use containers and such. The main idea is that the passenger cabin should be sandboxed away from the cockpit, which isn't earth-shattering.
Where he mentions Lisp is this:
> The defense that does work is to keep code and data in separate places. Then there is no way to compromise code by playing tricks with data. Garbage-collected languages like Perl and Lisp do this, and as a result are immune from buffer overflow attacks.
This point seems bungled. Garbage collection is no panacea. Bugs in a garbage collected run-time can expose applications to exploitable attacks. The advantage in Perl and Lisp is that the application programmer is not writing low-level buffer manipulation routines from scratch. That stuff is in the language run time, where we debug the low-level implementation code once, and have thousands of applications use the debugged thing. If a hole is found, we fix it once, and close the issue in thousands of apps once they upgrade to the new run-time.
Garbage collected languages do not necessarily keep code and data in separate places. Moreover, non-garbage-collected languages do that. The C language can easily be implemented in a conforming manner such that the data areas (automatic storage (a.k.a. stack) and dynamic (malloc) are not executable. C keeps code and data separate. Functions are not objects. In some C implementations, like certain DSP chips, functions are in a separate space; you cannot cast a function pointer to char * and access the function image, because the resulting pointer will be interpreted in a different memory area. Of course, C data can contain pointers to functions, which can be redirected if overwritten.
Lisp data can also contain function pointers: e.g. a closure object with a pointer to code and to an environment. If that is stored in a heap somewhere where an array is also stored, and the run-time has a bug which allows array overrun, it could perhaps be exploited.
i want to give pg a lot of credit for clear thinking here, but of course if he'd suggested locking cockpit doors in august 02001 instead of september, that would have been significantly more impressive
your original summary of https://paulgraham.com/hijack.html was not correct