Bugtraq mailing list archives

SunOS syslog.c replacement


From: matthew () cs adelaide edu au (Matthew Donaldson)
Date: Wed, 30 Aug 1995 16:54:29 +0930


Because the 4.4BSD solution to the syslog problem (using snprintf which
relies on stdio cleverness) I've hacked a NetBSD syslog.c to work under SunOS,
and made some grotty hacks to fix the problem (I think!).

What I've done is to allocate the two arrays which are used, aligned on page
boundaries, with sizes of two pages.  I taken away access to the second page
of each, so that attempts to write to that area will raise a seg. fault.
I then defined a SEGV handler which exits the function rather than crashing
the program.  This is a seriously grotty hack, but I have tested it (though
not extensively), it seems to work, and it is probably the simplest way of
fixing the problem given there is no snprintf.  I've included the code I
added to fix the bug between /*vvvv*/ and /*^^^^*/ comments.  I also changed
a few things to make it compile under SunOS.

The code is below.  I'd like to hear if anyone can see any problems with it.

                -Matthew

--------------------8<--------------------8<--------------------8<-------------
/*      $NetBSD: syslog.c,v 1.8 1995/04/11 02:57:52 cgd Exp $   */

/*
 * Copyright (c) 1983, 1988, 1993
 *      The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by the University of
 *      California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)syslog.c    8.4 (Berkeley) 3/18/94";
#else
static char rcsid[] = "$NetBSD: syslog.c,v 1.8 1995/04/11 02:57:52 cgd Exp $";
#endif
#endif /* LIBC_SCCS and not lint */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/syslog.h>
void vsyslog();
void openlog();
#include <sys/uio.h>
#include <netdb.h>

#include <errno.h>
#include <fcntl.h>
/*#include <paths.h>*/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <setjmp.h>
#include <signal.h>
#include <sys/mman.h>

#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif

#define Strlen(x) ((x) ? strlen(x) : 0)  /* *** */
#define _PATH_CONSOLE "/dev/console"
#define _PATH_LOG "/dev/log"

static char *strerror(errnum)
     int errnum;
{
 extern int sys_nerr;
 extern char *sys_errlist[];
 if (errnum < 0 || errnum >= sys_nerr)
  return NULL;
 return sys_errlist[errnum];
}


static int      LogFile = -1;           /* fd for log */
static int      connected;              /* have done connect */
static int      LogStat = 0;            /* status bits, set by openlog() */
static char *LogTag = NULL;     /* string to tag the entry with */
static int      LogFacility = LOG_USER; /* default facility code */
static int      LogMask = 0xff;         /* mask of priorities to be logged */
/*extern char   *__progname;            /* Program name, from crt0. */

/*
 * syslog, vsyslog --
 *      print message on log file; output is intended for syslogd(8).
 */
void
#if __STDC__
syslog(int pri, const char *fmt, ...)
#else
syslog(pri, fmt, va_alist)
        int pri;
        char *fmt;
        va_dcl
#endif
{
        va_list ap;

#if __STDC__
        va_start(ap, fmt);
#else
        va_start(ap);
#endif
        vsyslog(pri, fmt, ap);
        va_end(ap);
}


/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
static jmp_buf jmp_env;
static int oldmask;
static struct sigvec vec, ovec;
static char *tbuf, *fmt_cpy;

static void segv()
{
 longjmp(jmp_env, 1);
}

static void sl_cleanup()
{
 int sz= getpagesize();
 /* Put back the old signal handler */
 sigvec(SIGSEGV, &ovec, 0);
 /* Restore the signal mask */
 sigsetmask(oldmask);
 /* Put back the protections */
 mprotect(tbuf+sz, sz, PROT_READ | PROT_WRITE);
 mprotect(fmt_cpy+sz, sz, PROT_READ | PROT_WRITE);
 /* Free the buffers */
 free(tbuf);
 free(fmt_cpy);
 return;
}
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

void
vsyslog(pri, fmt, ap)
        int pri;
        register char *fmt;
        va_list ap;
{
        register int cnt;
        register char ch, *p, *t;
        time_t now;
        int fd, saved_errno;
        char *stdp;
        int sz= getpagesize();

#define INTERNALLOG     LOG_ERR|LOG_CONS|LOG_PID
        /* Check for invalid bits. */
        if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
                syslog(INTERNALLOG,
                    "syslog: unknown facility/priority: %x", pri);
                pri &= LOG_PRIMASK|LOG_FACMASK;
        }

        /* Check priority against setlogmask values. */
        /*
        if (!(LOG_MASK(LOG_PRI(pri)) & LogMask))
                return;*/
        if (!(LOG_MASK(pri & LOG_PRIMASK) & LogMask))
         return;

        saved_errno = errno;

        /* Set default facility if none specified. */
        if ((pri & LOG_FACMASK) == 0)
                pri |= LogFacility;

/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
        /* Remember our previous signal mask */
        oldmask= sigblock(0);

        /* Allocate buffers - two pages each, aligned on page boundaries */
        if (!(tbuf= (char*)memalign(sz, sz*2))) return;
        if (!(fmt_cpy= (char*)memalign(sz, sz*2))) return;

        /* Stop write access to the second page of the buffers */
        if (mprotect(tbuf+sz, sz, 0) == -1) {
                free(tbuf);
                free(fmt_cpy);
                return;
        }
        if (mprotect(fmt_cpy+sz, sz, 0) == -1) {
                mprotect(tbuf+sz, sz, PROT_READ | PROT_WRITE);
                free(tbuf);
                free(fmt_cpy);
                return;
        }

        /* Set up a segv handler */
        vec.sv_handler= segv;
        vec.sv_mask= 0;
        vec.sv_flags= 0;
        if (sigvec(SIGSEGV, &vec, &ovec) == -1) {
                mprotect(tbuf+sz, sz, PROT_READ | PROT_WRITE);
                mprotect(fmt_cpy+sz, sz, PROT_READ | PROT_WRITE);
                free(tbuf);
                free(fmt_cpy);
                return;
        }

        if (setjmp(jmp_env))
        {
         /* If we end up in here, we've received a seg fault */
         sl_cleanup();
         return;
        }
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

        /* Build the message. */
        (void)time(&now);
        p = tbuf + Strlen(sprintf(tbuf, "<%d>", pri));  /* *** */
        p += strftime(p, sizeof (tbuf) - (p - tbuf), "%h %e %T ",
            localtime(&now));
#ifdef LOG_PERROR
        if (LogStat & LOG_PERROR)
                stdp = p;
#endif
        if (LogTag == NULL)
                LogTag = "syslog";
        if (LogTag != NULL)
                p += Strlen(sprintf(p, "%s", LogTag));
        if (LogStat & LOG_PID)
                p += Strlen(sprintf(p, "[%d]", getpid()));
        if (LogTag != NULL) {
                *p++ = ':';
                *p++ = ' ';
        }

        /* Substitute error message for %m. */
        for (t = fmt_cpy; ch = *fmt; ++fmt)
                if (ch == '%' && fmt[1] == 'm') {
                        ++fmt;
                        t += Strlen(sprintf(t, "%s", strerror(saved_errno)));
                } else
                        *t++ = ch;
        *t = '\0';

        p += Strlen(vsprintf(p, fmt_cpy, ap));
        cnt = p - tbuf;

#ifdef LOG_PERROR
        /* Output to stderr if requested. */
        if (LogStat & LOG_PERROR) {
                struct iovec iov[2];
                register struct iovec *v = iov;

                v->iov_base = stdp;
                v->iov_len = cnt - (stdp - tbuf);
                ++v;
                v->iov_base = "\n";
                v->iov_len = 1;
                (void)writev(STDERR_FILENO, iov, 2);
        }
#endif

        /* Get connected, output the message to the local logger. */
        if (!connected)
                openlog(LogTag, LogStat | LOG_NDELAY, 0);
/*      printf("send(%d, %s, %d, 0)\n", LogFile, tbuf, cnt);*/
        if (send(LogFile, tbuf, cnt, 0) >= 0)
        { sl_cleanup(); return; }

        /*
         * Output the message to the console; don't worry about blocking,
         * if console blocks everything will.  Make sure the error reported
         * is the one from the syslogd failure.
         */
        if (LogStat & LOG_CONS &&
            (fd = open(_PATH_CONSOLE, O_WRONLY, 0)) >= 0) {
                (void)strcat(tbuf, "\r\n");
                cnt += 2;
                p = strchr(tbuf, '>') + 1;
                (void)write(fd, p, cnt - (p - tbuf));
                (void)close(fd);
        }
        sl_cleanup();
}

static struct sockaddr SyslogAddr;      /* AF_UNIX address of local logger */

void
openlog(ident, logstat, logfac)
        char *ident;
        int logstat, logfac;
{
        if (ident != NULL)
                LogTag = ident;
        LogStat = logstat;
        if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
                LogFacility = logfac;

        if (LogFile == -1) {
                SyslogAddr.sa_family = AF_UNIX;
                (void)strncpy(SyslogAddr.sa_data, _PATH_LOG,
                    sizeof(SyslogAddr.sa_data));
                if (LogStat & LOG_NDELAY) {
                        if ((LogFile = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
                                return;
                        (void)fcntl(LogFile, F_SETFD, 1);
                }
        }
        if (LogFile != -1 && !connected)
                if (connect(LogFile, &SyslogAddr, sizeof(SyslogAddr)) == -1) {
                        (void)close(LogFile);
                        LogFile = -1;
                } else
                        connected = 1;
}

void
closelog()
{
        (void)close(LogFile);
        LogFile = -1;
        connected = 0;
}

/* setlogmask -- set the log mask level */
int
setlogmask(pmask)
        int pmask;
{
        int omask;

        omask = LogMask;
        if (pmask != 0)
                LogMask = pmask;
        return (omask);
}
--------------------8<--------------------8<--------------------8<-------------

+--------------------------------------------------------------------------+
| Matthew Donaldson                     Email: matthew () cs adelaide edu au  |
| Computer Science Department           Phone: +61 8 303 5583          _   |
| University of Adelaide                Fax:   +61 8 303 4366   John  / \/ |
| South Australia 5005                  Telex: UNIVAD AA89141   3:16  \_/\ |
+--------------------------------------------------------------------------+



Current thread: