[Ecls-list] More thoughts on signals, stack overflows, etc
Juan Jose Garcia-Ripoll
juanjose.garciaripoll at googlemail.com
Mon Oct 6 21:23:37 UTC 2008
A recommended read for any C programmer :-)
https://www.securecoding.cert.org/confluence/display/seccode/SIG30-C.+Call+only+asynchronous-safe+functions+within+signal+handlers
https://www.securecoding.cert.org/confluence/display/seccode/SIG32-C.+Do+not+call+longjmp()+from+inside+a+signal+handler
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1318.htm
From current code, seems all lisp implementations suffer from this
problem: they invoke lisp code from the interrupt handlers, while this
is strictly forbidden by the C standards. This may be the source of
vulnerabilities, as described before. Furthermore, calling longjmp()
from inside the signal handler is also an undocumented use, which may
or may not work, depending on which version of C, POSIX or ISO and
year, we read.
Geo Carncross suggested a nice idea, which is to create a thread that
watches our lisp process. It will wait until a signal is delivered to
some lisp thread. The lisp thread will wake up the watchdog thread
which will then run any code we wish, using the environment of the
original interrupted thread. If we add this to the list of solutions
which I had in mind, these are the alternatives:
- We forbid calling longjmp from the signal handler. Then ECL has to
a) Defer harmless signals wating for a safe place to call them.
b) Abort on complicated signals.
- We allow longjmp and change the way signals are handled. When the
program receives a signal, it will _always_ jump to a handler point
established before the code that caused the signal. Speaking in a
lispy way, we allow HANDLER-CASE but not HANDLER-BIND.
- We implement the watchdog thread. This time we allow HANDLER-BIND,
which is excuted on a different thread.
- Continue as now but explicitely tell the user that the signal
handler is restricted to a subset of lisp functions.
- Continue as now and ignore real-world issues.
The first model is _very_ expensive. It will allow us to insert checks
for signals at many different places, including loops that call no
functions. I would not like having to implement it. It is also unclear
whether longjmp is really forbidden. Some compilers and libraries,
including IBM's, Sun's and the C89 standard, allow longjmp from the
outermost signal handler, but not if a signal is caused within the
signal handler.
The second model is a good and cheap compromise. We would only lose
the ability to break into functions and debug them. A partial solution
would be to allow some forensic: i.e., make a copy of the frame and
binding stacks, as well as the lexical environments.
The third model is nice and does not seem completely unportable and
there are some problems. 1) POSIX specifies that the signal handler is
forbidden to call C functions, but it does not say anything about
other threads. In particular, a thread might have left some mutexes
locked which prevents other threads from writing to files, etc. 2) We
need to use threads. 3) This may interfere with applications ECL is
embeeded in. 4) It is not clear what to do when a second signal
arrives.
The fourth model is a nice short term compromise that would be
equivalent to the first and the second, but placing the burden on the
user.
Juanjo
--
Instituto de Física Fundamental, CSIC
c/ Serrano, 113b, Madrid 28009 (Spain)
http://juanjose.garciaripoll.googlepages.com
More information about the ecl-devel
mailing list