Mailscanner on Solaris 9 *not* protected from "zip of death"

D.M.Chapman D.M.Chapman at UKC.AC.UK
Thu Nov 28 10:33:51 GMT 2002


Ok, I have been doing some digging following my recent email about
mailscanner failing to detect a Denial of Service attack and I may have
turned up a fairly serious issue with solaris 9. Bewarned, this is long :-)

Executive Summary:

  If you are running mailscanner on Solaris 9 and you are using the Sun
  supplied version of perl then you are probably *not* protected against
  a "zip of death" denial of service attack. We certainly were not :-(


Gory details:

After we were attacked I (wrongly :-) assumed that the version of
mailscanner we were running had a bug that failed to timeout a virus
scan that was taking forever. Following confirmation that the latest
version (I'm talking v3 here - we use Exim) had protection built in
I upgraded the problematic machine yesterday. No problems with the
upgrade all looked good. Sent it a zip of death and it died :-(

Symptoms are that it detects the first timeout but then when it tests
each message seperately it never returns. You will see:

   Commercial scanner sophos timed out!
   Denial Of Service attack detected!

logged (I suspect that this is an issue with all virus scanners - not
just sophos) but you never get the:

  Commercial scanner sophos timed out!
  Denial Of Service attack is in message <msg_id>

bit. Looking at the processes mailscanner is stuck in a read waiting
for the scanner to return something while the scanner is stuck trying
to unzip a file that is ununzippable (is that a word?:-).

Checking the code suggests that for some reason mailscanner is never
getting the second SIGALRM signal for some reason. A truss on the
running process suggests the same...

Test code (test.pl):
---------8<--------8<--------

sub test {
  eval {
      local $SIG{ALRM} = sub { die "Timed Out" };
      alarm 2;
      while(<STDIN>) {
      }
   }
};


print "going once...\n";
&test;
print "going twice...\n";
&test;
print "gone.\n"

---------8<--------8<--------


As I understand it (correct me if not!) this should run and stick in the
read from STDIN until the ALRM signal causes it to drop out of the eval
block. If I'm correct then I would expect this to output three lines of
text with a 2 second delay between them. Running it on the machine that
failed to detect the DOS and it hangs after the second message. Running
it on a machine that did detect the DOS and it works as I would expect.

Much trussing and head scratching later it appears that the issue is the
version of perl that is installed on solaris 9 as standard. It isn't the
actual version that is the issue (I happened to have the same release
on a sol9 box) but the particular binary that is /usr/bin/perl.

This morning I have installed another version of perl onto my sol9
machine and my test program works. Testing mailscanner shows that it
now detects a DOS correctly...

If you are running Mailscanner on Solaris 9 (maybe other releases as
well I guess) then you might want to check this out!

Truss output from the sun version:

truss /usr/bin/perl test.pl
[snip]
read(3, " s u b   t e s t   {\n  ".., 8192)     = 215
brk(0x00030438)                                 = 0
brk(0x00032438)                                 = 0
brk(0x00032438)                                 = 0
brk(0x00034438)                                 = 0
read(3, 0x0002DFBC, 8192)                       = 0
llseek(3, 0, SEEK_CUR)                          = 215
close(3)                                        = 0
ioctl(1, TCGETA, 0xFFBFF7F4)                    = 0
fstat64(1, 0xFFBFF710)                          = 0
going once...
write(1, " g o i n g   o n c e . .".., 14)      = 14
sigaction(SIGALRM, 0x00000000, 0xFFBFF948)      = 0
sigaction(SIGALRM, 0xFFBFF8A0, 0xFFBFF920)      = 0
sigaction(SIGALRM, 0xFFBFF908, 0xFFBFF988)      = 0
alarm(2)                                        = 0
ioctl(0, TCGETA, 0xFFBFF8BC)                    = 0
fstat64(0, 0xFFBFF7D8)                          = 0
read(0, 0xFF0C144C, 1024)       (sleeping...)
    Received signal #14, SIGALRM, in read() [caught]
read(0, 0xFF0C144C, 1024)                       Err#91 ERESTART
sigaction(SIGALRM, 0xFFBFF088, 0xFFBFF108)      = 0
going twice...
write(1, " g o i n g   t w i c e .".., 15)      = 15
sigaction(SIGALRM, 0xFFBFF8A0, 0xFFBFF920)      = 0
sigaction(SIGALRM, 0xFFBFF908, 0xFFBFF988)      = 0
alarm(2)                                        = 0
read(0, 0xFF0C144C, 1024)       (sleeping...)

A read that carries on for ever,,,

Truss output from a new version (from sunfreeware.com):

truss /usr/local/bin/perl test.pl
[snip]

read(3, " s u b   t e s t   {\n  ".., 8192)     = 215
brk(0x00122C40)                                 = 0
brk(0x00124C40)                                 = 0
brk(0x00124C40)                                 = 0
brk(0x00126C40)                                 = 0
read(3, 0x001200CC, 8192)                       = 0
llseek(3, 0, SEEK_CUR)                          = 215
close(3)                                        = 0
getcontext(0xFFBFF9C8)
ioctl(1, TCGETA, 0xFFBFF6BC)                    = 0
fstat64(1, 0xFFBFF5D8)                          = 0
going once...
write(1, " g o i n g   o n c e . .".., 14)      = 14
sigaction(SIGALRM, 0x00000000, 0xFFBFF840)      = 0
sigaction(SIGALRM, 0xFFBFF7A0, 0xFFBFF820)      = 0
sigaction(SIGALRM, 0xFFBFF888, 0xFFBFF908)      = 0
alarm(2)                                        = 0
ioctl(0, TCGETA, 0xFFBFD62C)                    = 0
fstat64(0, 0xFFBFD548)                          = 0
read(0, 0xFF24144C, 1024)       (sleeping...)
    Received signal #14, SIGALRM, in read() [caught]
read(0, 0xFF24144C, 1024)                       Err#4 EINTR
setcontext(0xFFBFD480)
getcontext(0xFFBFF6C8)
getcontext(0xFFBFF478)
setcontext(0xFFBFF478)
sigfillset(0xFF240708)                          = 0
sigprocmask(SIG_UNBLOCK, 0xFFBFFA20, 0x00000000) = 0
sigaction(SIGALRM, 0xFFBFF5A8, 0xFFBFF628)      = 0
getcontext(0xFFBFF6F0)
setcontext(0xFFBFF6F0)
going twice...
write(1, " g o i n g   t w i c e .".., 15)      = 15
sigaction(SIGALRM, 0xFFBFF7A0, 0xFFBFF820)      = 0
sigaction(SIGALRM, 0xFFBFF888, 0xFFBFF908)      = 0
alarm(2)                                        = 0
read(0, 0xFF24144C, 1024)       (sleeping...)
    Received signal #14, SIGALRM, in read() [caught]
read(0, 0xFF24144C, 1024)                       Err#4 EINTR
setcontext(0xFFBFD480)
getcontext(0xFFBFF6C8)
getcontext(0xFFBFF478)
setcontext(0xFFBFF478)
sigprocmask(SIG_UNBLOCK, 0xFFBFFA20, 0x00000000) = 0
sigaction(SIGALRM, 0xFFBFF5A8, 0xFFBFF628)      = 0
getcontext(0xFFBFF6F0)
setcontext(0xFFBFF6F0)
gone.
write(1, " g o n e .\n", 6)                     = 6
getcontext(0xFFBFF878)
setcontext(0xFFBFF878)
getcontext(0xFFBFF9C8)
_exit(0)


The broken version of perl doesn't seem to bother with any of the
{set,get}context calls. Dunno if this is Suns fault, perls fault or
something more subtle.

Anyway, hope this helps someone avoid the frustrating afternoon that
I have yesterday!

Cheers,

Darren - needs a coffee now!



More information about the MailScanner mailing list