deibyz has asked for the wisdom of the Perl Monks concerning the following question:

Wise Monks,

I'm working in a monitoring script that send messages to a monitoring server. This is working well, but now I have a little proble:

This script have to send an alarm when anything goes wrong with the monitored system, but also when anything goes wrong with himself, that is, it must send an alarm when it dies, or when it gets killed. The process of sending an alarm is appending a special message to a "special" "file"

I've accomplished that using some code like that:

local $SIG{'TERM'} = \&killalarm; local $SIG{'INT'} = \&killalarm; local $SIG{'__DIE__'} = \&diealarm; sub killalarm{ my $signal = shift; diealarm("Killed by signal $signal\n"); } sub diealarm{ my $params = shift; # some stuff, opening files, printing to files... }

But my problem is that I'm using an old perl version (5.005_03 built for sun4-solaris), and I can't change it. I know that there are some problems with signal handling in perl under before 5.7.x, and that it isn't recommended to do a lot of work in signal handlers. I've though on reformatting this code like that:

local $SIG{'TERM'} = \&killalarm; local $SIG{'INT'} = \&killalarm; local $SIG{'__DIE__'} = \&diealarm; sub killalarm{ my $signal = shift; die "Killed by signal $signal\n"; } sub diealarm{ my $params = shift; # a lot of stuff, opening files, printing to files... }

Notice that now I call "die" instead of "diealarm". Will this avoid the unsafe signals problem? Is there anyother workaround for the problem? I've searched the web and the Monastery, but keep being sure about the problems that my code can cause.

Thanks in advance for your cooperation and, as always, excuse my poor English.

Replies are listed 'Best First'.
Re: Unsafe signals?
by dave_the_m (Monsignor) on Feb 23, 2005 at 15:44 UTC
    There's no real way you can modify the code above to make it safe. About the only thing you can do in a signal handler without safe signals is to change the value of a pre-existing, pre-allocated flag, eg
    use vars '$flag'; $flag = 0; local $SIG{'TERM'} = sub { $flag = 1 } .... while (...) { ... die "got signal\n" if $flag; }
    But that's probably not what you want.

    The reason is that the signal could have been receieved at any point, such as in a malloc(), so any code in your handler that might trigger a call to malloc() isn't safe. Even my code isn't completely safe, but is perhaps, less unsafe.

    Dave.

      Michal Zalewski at BindView wrote a paper on exploiting signal handlers, http://www.bindview.com/Support/RAZOR/Papers/2001/signals.cfm

      dave_the_m is correct, you need to limit the functionality done in a signal handler as much as possible. Setting a flag is the probably the most accepted method for "safe" signal handlers.

      While your signal handlers are not perfect and can be used to hork your program quite badly, its nowhere near the worst signal handler I've ever seen. The "worst" signal handler I've come across was example:

      void ack() { env = getenv("DEBUG"); buf = malloc(256); strcpy(buf,env); syslog(buf); free(buf); longjmp FOO; free(buf); }
      a buffer overflow, print string vulnerability, a double free, and a longjmp. Take your pick for which you want to exploit :P
Re: Unsafe signals?
by Tanktalus (Canon) on Feb 23, 2005 at 17:46 UTC

    It may be easier to shuffle off alarming to a parent process:

    Monitor_Monitor => monitors Monitor => monitors RealWork => monitors parent

    I'm not really very good at this art thing. Anyway, we have a super parent monitoring your monitor. And your monitor monitoring both the subprocess it is looking after, and its parent process. Anything dies, other than itself, and you signal your alarm.

    Alternatively, throw your monitor into the inittab, set it to restart on failure, and then throw an alarm every time you start, just as a place to begin. This means that each time the system reboots, you'll get an alarm (which may not be a bad thing either - if this is a 24/7 server, then rebooting is a bad thing anyway). You'll of course want to drop root privileges immediately on start, but otherwise it's nothing special to be started this way.