Package: syslog-ng
Version: 2.0rc3-1
Severity: important
Tags: patch

(This is the same problem reported against syslog-ng in Gentoo at
https://bugs.gentoo.org/show_bug.cgi?id=154465 -- this contains
a patch which fixes the problem with a similar approach to that
taken in sysklogd.)

When syslog-ng writes to a tty under Linux, for example as a
result of a usertty directive, the write syscall to
/dev/ttyN can ocassionally block indefinitely.  One
situation when this occurs is when the user has set XOFF
(perhaps with Ctrl-S or Scroll Lock).

Aside from the fact that this obvious prevents any further
log messages from being written, /dev/log's buffer
eventually fills up causing other programs to block writing
to /dev/log.  In extremis, this can render a machine
inaccesible when ssh, etc., all block preventing access.


Reproducible: Always

Steps to Reproduce:

1. Check that there is a usertty("*") directive for (say) kern.emerg logs
2. Ensure syslog-ng is running
3. On console, press Scroll Lock
4. Log something, e.g. logger -p kern.emerg 'Foo'.
5. Repeat #4 many times; eventually it will hang trying to log


-- System Information:
Debian Release: testing/unstable
  APT prefers unstable
  APT policy: (500, 'unstable'), (500, 'stable')
Architecture: i386 (i686)
Shell:  /bin/sh linked to /bin/bash
Kernel: Linux 2.6.15.2-3
Locale: LANG=C, LC_CTYPE=C (charmap=ANSI_X3.4-1968)

Versions of packages syslog-ng depends on:
ii  libc6                        2.3.6.ds1-4 GNU C Library: Shared libraries
ii  util-linux                   2.12r-11    Miscellaneous system utilities

Versions of packages syslog-ng recommends:
ii  logrotate                     3.7.1-3    Log rotation utility

-- no debconf information
--- src/afuser.c.orig	2006-11-08 12:36:11.886371656 +0000
+++ src/afuser.c	2006-11-08 13:13:32.133802280 +0000
@@ -27,6 +27,8 @@
 #include <string.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <signal.h>
+#include <setjmp.h>
 
 typedef struct _AFUserDestDriver
 {
@@ -46,6 +48,14 @@
   return TRUE;
 }
 
+static sigjmp_buf jmp;
+
+static void alarmproc()
+{
+  signal(SIGALRM, alarmproc);
+  siglongjmp(jmp, 1);
+}
+
 static void
 afuser_dd_queue(LogPipe *s, LogMessage *msg, gint path_flags)
 {
@@ -77,7 +87,15 @@
           fd = open(line, O_NOCTTY | O_APPEND | O_WRONLY);
           if (fd != -1) 
             {
-              write(fd, buf, strlen(buf));
+              if (sigsetjmp(jmp, 1) == 0)
+                {
+                  signal(SIGALRM, alarmproc);
+                  alarm(15);
+                  write(fd, buf, strlen(buf));
+                }
+
+              alarm(0);
+              signal(SIGALRM, SIG_DFL);
               close(fd);
             }
         }

Reply via email to