[Ecls-list] More thoughts on signals, stack overflows, etc

Waldek Hebisch hebisch at math.uni.wroc.pl
Mon Oct 6 22:34:19 UTC 2008


Juan Jose Garcia-Ripoll wrote:
[ Charset UTF-8 unsupported, converting... ]
> 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.
> 

I think we should look at real-world issues: why standards forbid
longjmp?  The Cert text while formal has good point: there is code
which is not asynchronous-safe.  Now, if you look at examples
probably the simplest is C library 'printf': 'printf' has to access
stdio buffers and its execution depends on state of buffer variables.
AFAIK glibc 'printf' actually locks stdio to avoid interference
with other treads, so if you jump out of printf stdout will
remain locked, hence unusable.

Now this example shows that separate thread really does not solve
any problem: critical data structures typically are shared by
all threads, so if one thread messes them up the other threads
will stop working too.

OTOH this suggests another tactic: wrap each problematic call.  The
wrapper will set thread local "in uniteruptible call" flag.  Signal
handler seeing this flag will just append relevant data to pending
interrupts list and return normally.  On return the wrapper will
execute all interrupts on pending interrupts list.  Note that
this will work only for some signals: if you have fatal error
inside C library then you can not really continue execution.  However
the only way to avoid problems with error recovery inside C library is
to avoid using C library (or pass only arguments which can not cause
unrecoverable error).

When speaking about stack overflow: if stack overflow happens inside
'printf' handler _can not_ print diagnostic (assuming that handler
is using printf, of course one can use direct system calls to
print messages about fatal errors), the best handler can do is
to enlarge stack, hoping that 'printf' will finish and print error
message _after_ printf retured.

-- 
                              Waldek Hebisch
hebisch at math.uni.wroc.pl 




More information about the ecl-devel mailing list