On Sun, Aug 16, 2020 at 11:39:31AM +0000, Visa Hankala wrote:
> The kernel message buffer is circular. This is not handled properly
> by filt_logread(). When the write index wraps, and becomes smaller than
> the read index, filt_logread() reports an incorrect number of available
> bytes. This has not affected the activation of the event, though,
> because the reported number is non-zero even in the incorrect case.
> 
> The error looks like the following with ktrace:
> 
>  60243 syslogd  STRU  struct kevent { ident=10, filter=EVFILT_READ, 
> flags=0x1<EV_ADD>, fflags=0<>, data=18446744073709551615, udata=0x34c7e21000 }

Here is an updated diff. It uses the same buffer length computation
for kn_data and FIONREAD. These interfaces, kevent(2) and ioctl(2),
should indicate the same number of available bytes after all. Also,
now the computation has the more compact form used by FIONREAD.

OK?

Index: kern/subr_log.c
===================================================================
RCS file: src/sys/kern/subr_log.c,v
retrieving revision 1.66
diff -u -p -r1.66 subr_log.c
--- kern/subr_log.c     7 Apr 2020 13:27:51 -0000       1.66
+++ kern/subr_log.c     17 Aug 2020 05:37:41 -0000
@@ -95,6 +95,7 @@ const struct filterops logread_filtops =
 
 int dosendsyslog(struct proc *, const char *, size_t, int, enum uio_seg);
 void logtick(void *);
+size_t msgbuf_getlen(struct msgbuf *);
 
 void
 initmsgbuf(caddr_t buf, size_t bufsize)
@@ -163,6 +163,20 @@ msgbuf_putchar(struct msgbuf *mbp, const
        splx(s);
 }
 
+size_t
+msgbuf_getlen(struct msgbuf *mbp)
+{
+       long len;
+       int s;
+
+       s = splhigh();
+       len = mbp->msg_bufx - mbp->msg_bufr;
+       if (len < 0)
+               len += mbp->msg_bufs;
+       splx(s);
+       return (len);
+}
+
 int
 logopen(dev_t dev, int flags, int mode, struct proc *p)
 {
@@ -297,14 +311,10 @@ filt_logrdetach(struct knote *kn)
 int
 filt_logread(struct knote *kn, long hint)
 {
-       struct  msgbuf *p = (struct  msgbuf *)kn->kn_hook;
-       int s, event = 0;
+       struct msgbuf *mbp = kn->kn_hook;
 
-       s = splhigh();
-       kn->kn_data = (int)(p->msg_bufx - p->msg_bufr);
-       event = (p->msg_bufx != p->msg_bufr);
-       splx(s);
-       return (event);
+       kn->kn_data = msgbuf_getlen(mbp);
+       return (kn->kn_data != 0);
 }
 
 void
@@ -357,19 +367,13 @@ int
 logioctl(dev_t dev, u_long com, caddr_t data, int flag, struct proc *p)
 {
        struct file *fp;
-       long l;
-       int error, s;
+       int error;
 
        switch (com) {
 
        /* return number of characters immediately available */
        case FIONREAD:
-               s = splhigh();
-               l = msgbufp->msg_bufx - msgbufp->msg_bufr;
-               splx(s);
-               if (l < 0)
-                       l += msgbufp->msg_bufs;
-               *(int *)data = l;
+               *(int *)data = (int)msgbuf_getlen(msgbufp);
                break;
 
        case FIONBIO:

Reply via email to