Package: sysklogd
Version: 1.4.1-16
Severity: grave
Justification: breaks the whole system

References:
  http://lkml.org/lkml/2005/3/26/37
  https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=103392
  http://lkml.org/lkml/2004/12/21/208
  http://lkml.org/lkml/2004/11/2/17

Syslogd can hang if domark() is called while the main loop is just
calling in the ctime() libc function. ctime() is not reentrant
and will make syslogd hang (with recent glibc and 2.6 kernels,
because glibc uses __libc_lock which uses a [fm]utex).

Because AF_UNIX SOCK_DGRAM sockets are blocking by default under
Linux, after a short while everything on the system that calls
syslog() will hang as well. Which means you can't login anymore,
and almost all other network services hang as well.
Also cron will fork every now and again and call syslog() so the
whole process table will fill up. The system is fubared.

The original syslogd protects itself from this by blocking SIGHUP
and SIGALRM in logmsg(), but that is under #ifndef SYSV.

The attached patch fixes this by adding POSIX sigprocmask calls
in logmsg(), as that is the simplest fix.

Non-bug related comments:

A better fix would be to just set a flag in domark() and check that
flag every so often in the mainloop and do the MARKing there.

Someone should take out all the #ifdef/#ifndef SYSV stuff and
replace it with POSIX routines so that this syslogd compiles
under all modern OSes. I think that it doesn't even compile
without #define SYSV anymore, anyway.

Mike.
--- sysklogd-1.4.1/syslogd.c.ORIG       2005-03-25 22:04:07.360493000 +0100
+++ sysklogd-1.4.1/syslogd.c    2005-03-26 13:28:17.650819246 +0100
@@ -1558,11 +1558,21 @@
        int fac, prilev, lognum;
        int msglen;
        char *timestamp;
+#ifdef linux
+       sigset_t mask, omask;
+#endif
 
        dprintf("logmsg: %s, flags %x, from %s, msg %s\n", textpri(pri), flags, 
from, msg);
 
-#ifndef SYSV
+#ifdef linux /* POSIX, really. */
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGHUP);
+       sigaddset(&mask, SIGALRM);
+       sigprocmask(SIG_BLOCK, &mask, &omask);
+#else
+#  ifndef SYSV
        omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
+#  endif
 #endif
 
        /*
@@ -1603,8 +1613,12 @@
                        (void) close(f->f_file);
                        f->f_file = -1;
                }
-#ifndef SYSV
+#ifdef linux
+               sigprocmask(SIG_SETMASK, &omask, NULL);
+#else
+#  ifndef SYSV
                (void) sigsetmask(omask);
+#  endif
 #endif
                return;
        }
@@ -1668,8 +1682,12 @@
                        }
                }
        }
-#ifndef SYSV
+#ifdef linux
+       sigprocmask(SIG_SETMASK, &omask, NULL);
+#else
+#  ifndef SYSV
        (void) sigsetmask(omask);
+#  endif
 #endif
 }
 #if FALSE

Reply via email to