The ps_klist member of struct process can be accessed from interrupt
context as a result of signal sending. Currently, interrupts are not
blocked when ps_klist is modified, which allows race conditions.

The patch below guards ps_klist insertions and removals with splhigh().
The list should only be modified from process context.

Note that in practice the highest interrupt priority level where kqueue
can be used is IPL_SCHED. It is not safe to access the scheduler from
a higher level.

OK?

Index: kern/kern_event.c
===================================================================
RCS file: src/sys/kern/kern_event.c,v
retrieving revision 1.136
diff -u -p -r1.136 kern_event.c
--- kern/kern_event.c   12 Jun 2020 09:34:17 -0000      1.136
+++ kern/kern_event.c   13 Jun 2020 15:30:07 -0000
@@ -246,6 +246,7 @@ int
 filt_procattach(struct knote *kn)
 {
        struct process *pr;
+       int s;
 
        if ((curproc->p_p->ps_flags & PS_PLEDGE) &&
            (curproc->p_p->ps_pledge & PLEDGE_PROC) == 0)
@@ -275,7 +276,9 @@ filt_procattach(struct knote *kn)
        }
 
        /* XXX lock the proc here while adding to the list? */
+       s = splhigh();
        klist_insert(&pr->ps_klist, kn);
+       splx(s);
 
        return (0);
 }
@@ -292,12 +295,15 @@ void
 filt_procdetach(struct knote *kn)
 {
        struct process *pr = kn->kn_ptr.p_process;
+       int s;
 
        if (kn->kn_status & KN_DETACHED)
                return;
 
        /* XXX locking?  this might modify another process. */
+       s = splhigh();
        klist_remove(&pr->ps_klist, kn);
+       splx(s);
 }
 
 int
@@ -326,10 +332,10 @@ filt_proc(struct knote *kn, long hint)
 
                s = splhigh();
                kn->kn_status |= KN_DETACHED;
-               splx(s);
                kn->kn_flags |= (EV_EOF | EV_ONESHOT);
                kn->kn_data = W_EXITCODE(pr->ps_xexit, pr->ps_xsig);
                klist_remove(&pr->ps_klist, kn);
+               splx(s);
                return (1);
        }
 
Index: kern/kern_sig.c
===================================================================
RCS file: src/sys/kern/kern_sig.c,v
retrieving revision 1.256
diff -u -p -r1.256 kern_sig.c
--- kern/kern_sig.c     7 Apr 2020 13:27:51 -0000       1.256
+++ kern/kern_sig.c     13 Jun 2020 15:30:07 -0000
@@ -1803,6 +1803,7 @@ int
 filt_sigattach(struct knote *kn)
 {
        struct process *pr = curproc->p_p;
+       int s;
 
        if (kn->kn_id >= NSIG)
                return EINVAL;
@@ -1811,7 +1812,9 @@ filt_sigattach(struct knote *kn)
        kn->kn_flags |= EV_CLEAR;               /* automatically set */
 
        /* XXX lock the proc here while adding to the list? */
+       s = splhigh();
        klist_insert(&pr->ps_klist, kn);
+       splx(s);
 
        return (0);
 }
@@ -1820,8 +1823,11 @@ void
 filt_sigdetach(struct knote *kn)
 {
        struct process *pr = kn->kn_ptr.p_process;
+       int s;
 
+       s = splhigh();
        klist_remove(&pr->ps_klist, kn);
+       splx(s);
 }
 
 /*

Reply via email to