Hi,

There is a race in dosendsyslog() which resulted in a crash on a
5.9 system.  sosend(syslogf->f_data, ...) was called with a NULL
pointer.  So syslogf is not NULL, f_data is NULL and f_count is 1.

The file structure is ref counted, but the global variable syslogf
is not protected.  So it may change during sleep and dosendsyslog()
possibly uses a different socket at each access.

My crash happend during a reboot when init(8) is killing syslogd(8)
and some sort of super daemon tries to restart it constantly.
Although this design is questionable, it helps finding kernel bugs :-)

Solution is to access syslogf ony once, use a local copy, and do
the ref counting there.

ok?

bluhm

Index: kern/subr_log.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/kern/subr_log.c,v
retrieving revision 1.48
diff -u -p -r1.48 subr_log.c
--- kern/subr_log.c     23 Jun 2016 15:41:42 -0000      1.48
+++ kern/subr_log.c     24 Mar 2017 15:31:49 -0000
@@ -409,14 +409,17 @@ dosendsyslog(struct proc *p, const char 
        struct iovec *ktriov = NULL;
        int iovlen;
 #endif
+       struct file *fp;
        char pri[6], *kbuf;
        struct iovec aiov;
        struct uio auio;
        size_t i, len;
        int error;
 
-       if (syslogf)
-               FREF(syslogf);
+       /* Global variable syslogf may change during sleep, use local copy. */
+       fp = syslogf;
+       if (fp)
+               FREF(fp);
        else if (!ISSET(flags, LOG_CONS))
                return (ENOTCONN);
        else {
@@ -467,8 +470,8 @@ dosendsyslog(struct proc *p, const char 
 #endif
 
        len = auio.uio_resid;
-       if (syslogf) {
-               error = sosend(syslogf->f_data, NULL, &auio, NULL, NULL, 0);
+       if (fp) {
+               error = sosend(fp->f_data, NULL, &auio, NULL, NULL, 0);
                if (error == 0)
                        len -= auio.uio_resid;
        } else if (constty || cn_devvp) {
@@ -515,8 +518,8 @@ dosendsyslog(struct proc *p, const char 
                free(ktriov, M_TEMP, iovlen);
        }
 #endif
-       if (syslogf)
-               FRELE(syslogf, p);
+       if (fp)
+               FRELE(fp, p);
        else
                error = ENOTCONN;
        return (error);

Reply via email to