diff options
author | Mark Johnston <markj@FreeBSD.org> | 2018-11-28 18:06:16 +0000 |
---|---|---|
committer | Mark Johnston <markj@FreeBSD.org> | 2018-11-28 18:06:16 +0000 |
commit | 3a2ceb530c5d8c5b0e9c3a74a2cdc9d4cb2e3dd7 (patch) | |
tree | 1f035353316e90fc858027c27b5a3f2842b8d846 | |
parent | c8a5b4f24be644bd936bb3d2181d6a69abd9502e (diff) |
MFstable/12 r341082:
Ensure that knotes do not get registered when KQ_CLOSING is set.
PR: 228858
Approved by: re (gjb)
Notes
Notes:
svn path=/releng/12.0/; revision=341159
-rw-r--r-- | sys/kern/kern_event.c | 28 |
1 files changed, 19 insertions, 9 deletions
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index b29f1bb86c01..94d0fcd0b261 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -1463,8 +1463,11 @@ findkn: break; } } else { - if ((kev->flags & EV_ADD) == EV_ADD) - kqueue_expand(kq, fops, kev->ident, waitok); + if ((kev->flags & EV_ADD) == EV_ADD) { + error = kqueue_expand(kq, fops, kev->ident, waitok); + if (error != 0) + goto done; + } KQ_LOCK(kq); @@ -1700,12 +1703,12 @@ kqueue_expand(struct kqueue *kq, struct filterops *fops, uintptr_t ident, { struct klist *list, *tmp_knhash, *to_free; u_long tmp_knhashmask; - int size; - int fd; + int error, fd, size; int mflag = waitok ? M_WAITOK : M_NOWAIT; KQ_NOTOWNED(kq); + error = 0; to_free = NULL; if (fops->f_isfd) { fd = ident; @@ -1717,9 +1720,11 @@ kqueue_expand(struct kqueue *kq, struct filterops *fops, uintptr_t ident, if (list == NULL) return ENOMEM; KQ_LOCK(kq); - if (kq->kq_knlistsize > fd) { + if ((kq->kq_state & KQ_CLOSING) != 0) { + to_free = list; + error = EBADF; + } else if (kq->kq_knlistsize > fd) { to_free = list; - list = NULL; } else { if (kq->kq_knlist != NULL) { bcopy(kq->kq_knlist, list, @@ -1740,9 +1745,12 @@ kqueue_expand(struct kqueue *kq, struct filterops *fops, uintptr_t ident, tmp_knhash = hashinit(KN_HASHSIZE, M_KQUEUE, &tmp_knhashmask); if (tmp_knhash == NULL) - return ENOMEM; + return (ENOMEM); KQ_LOCK(kq); - if (kq->kq_knhashmask == 0) { + if ((kq->kq_state & KQ_CLOSING) != 0) { + to_free = tmp_knhash; + error = EBADF; + } else if (kq->kq_knhashmask == 0) { kq->kq_knhash = tmp_knhash; kq->kq_knhashmask = tmp_knhashmask; } else { @@ -1754,7 +1762,7 @@ kqueue_expand(struct kqueue *kq, struct filterops *fops, uintptr_t ident, free(to_free, M_KQUEUE); KQ_NOTOWNED(kq); - return 0; + return (error); } static void @@ -2605,6 +2613,8 @@ knote_attach(struct knote *kn, struct kqueue *kq) KASSERT(kn_in_flux(kn), ("knote %p not marked influx", kn)); KQ_OWNED(kq); + if ((kq->kq_state & KQ_CLOSING) != 0) + return (EBADF); if (kn->kn_fop->f_isfd) { if (kn->kn_id >= kq->kq_knlistsize) return (ENOMEM); |