[syslog-ng]Re: Bug #161915

Balazs Scheidler bazsi@balabit.hu
Fri, 4 Oct 2002 10:54:59 +0200


On Thu, Oct 03, 2002 at 04:09:27PM -0700, Brian Thomas wrote:
> On Thu, Oct 03, 2002 at 12:54:41PM +0200, Balazs Scheidler wrote:
> > Hi,
> > 
> > Thanks for the information you provided.
> > 
> > The problem is that the programs do not send \n at the end of line while
> > syslog-ng expects one for STREAM oriented sources. (such as unix-stream),
> 
> This seems like a bug in the packages like cron, I would think. If using
> a stream source I'd think the daemon would be expected to provide
> \n's?

libc should do that. there's nothing saying that syslog() calls should be
made with a string terminated with NLs. 

> 
> > 
> > Earlier versions of syslog-ng took a message as a full message in the
> > following cases:
> > 1) either NL or NUL was found in the incoming stream
> > 2) after a single read and the source is datagram oriented (UDP or unix-dgram)
> > 3) after the incoming buffer is full (specified via log_msg_size())
> > 
> > For stream oriented sources either 1) or 3) must be true. The strace you
> > sent me indicates that some programs do not terminate their messages by
> > '\n'.
> > 
> > Checking out the libc sources shows that libc automatically terminates
> > messages by NL if LOG_PERROR is set, and also adds a \0 at the end of the
> > line if STREAM sockets are used. So both syslog-ng and libc behaviour seems
> > to be correct. Something must be wrong anyway as the strace didn't show
> > terminating NUL characters.
> > 
> > I assumed that you are using unix-stream sources, but this assumption
> > should be true as syslog-ng issues read() instead of recvfrom().
> 
> I should have provided my syslog-ng.conf. Here's the sources line:
> 
> source src { unix-dgram("/dev/log"); internal(); file("/proc/kmsg"
> log_prefix("kernel: ")); udp(); };
> 
> So no, I'm not using streams, I'm using sockets. And this is
> interesting, because this was the default .conf that was installed, and
> from looking at the man page I'd think that should be
> unix-socket("/dev/log"), right?

hmm... unix-dgram sources should call recvfrom and not read. I verified this
and they do indeed use recvfrom. (I've just found a bug in the kernel,
it returns bogus sockaddrs from recvfrom on SOCK_DGRAM sockets)

I workaround in libol is now available at the end of this message. I've also
attached the kernel patch that should fix the problem.

> > As syslog-ng reads no terminating NUL characters, I think this should be a
> > libc issue. stream sockets should always have line terminations, as it is
> > not guaranteed by the kernel that a single write will be read by single read
> > calls.
> > 
> > I don't know where to submit this bug, to the libc people, or to the cron
> > people?
> 
> Assuming that my confusion about unix-dgram vs. unix-stream is just me
> being confused, and that I'm using streams even when I specify
> unix-dgram, than I would think this is a cron issue. It seems like
> they're being sloppy in their logging.

can you check lsof -p <syslogng pid>

just to see what fd 3 is ?

If it is really a unix-dgram socket, it should not be read by read()
syslog-ng should have used recvfrom() instead. On my testbox it correctly
used recvfrom.

PS: please Cc syslog-ng@lists.balabit.hu in followups.

Kernel patch, which fixes the unix domain socket issue (against 2.4.18):
--- af_unix.c~	Mon Feb 25 20:38:16 2002
+++ af_unix.c	Fri Oct  4 09:46:26 2002
@@ -1392,6 +1392,9 @@
 		       sk->protinfo.af_unix.addr->name,
 		       sk->protinfo.af_unix.addr->len);
 	}
+	else {
+		((struct sockaddr *) msg->msg_name)->sa_family = AF_UNIX;
+	}
 }
 
 static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg, int size,

Libol patch, which works around the problem above:

diff -u -r1.28 io.c
--- io.c	16 Sep 2002 08:23:22 -0000	1.28
+++ io.c	4 Oct 2002 08:53:41 -0000
@@ -368,7 +368,16 @@
 	}
 
 	for (;;) {
-		int res = recvfrom(closure->fd, buffer, length, 0, (struct sockaddr *) addr, (socklen_t *) addrlen);
+		int res;
+		
+		res = recvfrom(closure->fd, buffer, length, 0, (struct sockaddr *) addr, (socklen_t *) addrlen);
+
+		if (*addrlen == 2) {
+			/* HACK: this is a workaround of a Linux 2.2 & 2.4 bug,
+			 * it doesn't return anything sensible in sockaddr buf 
+			 */
+			((struct sockaddr *) addr)->sa_family = AF_UNIX;
+		}
 
 		if (res == 0) {
 			/* on SOCK_DGRAM protocols 0 returned bytes doesn't mean anything */

-- 
Bazsi
PGP info: KeyID 9AF8D0A9 Fingerprint CD27 CFB0 802C 0944 9CFD 804E C82C 8EB1