[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bin/72366: syslog overflow fix

>Number:         72366
>Category:       bin
>Synopsis:       syslog overflow fix
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Tue Oct 05 22:00:48 GMT 2004
>Originator:     Chris Gabe
>Release:        FreeBSD 5.3 (or later)
Borderware Technologies Inc
System: FreeBSD 5.3

	When data is sent rapidly, locally, using syslog, some lines get quietly lost.
	Create a program that just syslogs argv[2] in a loop of (atoi(argv[1])) count to /var/log/messages
	Run a few copies with arguments 10000000 aaaaaaaaaaaaaaaaaa so syslog is extremely busy.
	Then invoke with arguments 1000 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
	Count how many lines get to the file, using grep bbbb messages | wc.  They won't all get there every time.

	OpenBSD 3.2 had a fix in two parts.  The main one is below, in libc, lib/libc/gen/syslog.c.
	Beware that it's the second send() attempt that is changed, not the one just like
    it a few lines above:

    if (send(LogFile, tbuf, cnt, 0) >= 0)
     * If the send() failed, the odds are syslogd was restarted.
     * Make one (only) attempt to reconnect to /dev/log.

<       if (send(LogFile, tbuf, cnt, 0) >= 0)
<               return;
>       do {    
>               usleep(1); 
>               if (send(LogFile, tbuf, cnt, 0) >= 0)
>                       return;
>       } while (errno == ENOBUFS);

Unless syslogd is really being misused, this results in no discernable performance
difference, in our experience.

The second part is not mandatory but often avoids sleeping in the above code.
It is in syslogd, usr.sbin/syslogd/syslogd.c main(),

<       socklen_t len;
>       socklen_t len, slen;
479a480,487 (beware these numbers are quite different in 5.3)
    for (i = 0; i < nfunix; i++) {
        memset(&sunx, 0, sizeof(sunx));
        sunx.sun_family = AF_UNIX;
        (void)strlcpy(sunx.sun_path, funixn[i], sizeof(sunx.sun_path));
        funix[i] = socket(AF_UNIX, SOCK_DGRAM, 0);
        if (funix[i] < 0 ||
            bind(funix[i], (struct sockaddr *)&sunx,
             SUN_LEN(&sunx)) < 0 ||
            chmod(funixn[i], 0666) < 0) {
            (void)snprintf(line, sizeof line,
                    "cannot create %s", funixn[i]);
            dprintf("cannot create %s (%d)\n", funixn[i], errno);
            if (i == 0)
>       if (getsockopt(funix[i], SOL_SOCKET, SO_RCVBUF, &len,
>               &slen) == 0) {
>           len *= 2;
>           (void)setsockopt(funix[i], SOL_SOCKET, SO_RCVBUF, &len,
>                   slen);
>       }