aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2021-04-13 14:25:11 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2021-04-14 07:53:28 +0000
commit75c5cf7a720f5a73f17aff60adbc4a7b2fa86f84 (patch)
tree20b4f9508188f600cd00c8b09a4b0a21230a203d /sys
parent5cc1d199412ead0b4c234e21e881a31ef893a4f0 (diff)
downloadsrc-75c5cf7a720f5a73f17aff60adbc4a7b2fa86f84.tar.gz
src-75c5cf7a720f5a73f17aff60adbc4a7b2fa86f84.zip
filt_timerexpire: avoid process lock recursion
Found by: syzkaller Reported and reviewed by: markj Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D29746
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/kern_event.c22
1 files changed, 15 insertions, 7 deletions
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index 31b091e20984..45d505fca757 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -161,6 +161,7 @@ static void filt_procdetach(struct knote *kn);
static int filt_proc(struct knote *kn, long hint);
static int filt_fileattach(struct knote *kn);
static void filt_timerexpire(void *knx);
+static void filt_timerexpire_l(struct knote *kn, bool proc_locked);
static int filt_timerattach(struct knote *kn);
static void filt_timerdetach(struct knote *kn);
static void filt_timerstart(struct knote *kn, sbintime_t to);
@@ -706,21 +707,19 @@ kqtimer_proc_continue(struct proc *p)
TAILQ_FOREACH_SAFE(kc, &p->p_kqtim_stop, link, kc1) {
TAILQ_REMOVE(&p->p_kqtim_stop, kc, link);
if (kc->next <= now)
- filt_timerexpire(kc->kn);
+ filt_timerexpire_l(kc->kn, true);
else
kqtimer_sched_callout(kc);
}
}
static void
-filt_timerexpire(void *knx)
+filt_timerexpire_l(struct knote *kn, bool proc_locked)
{
- struct knote *kn;
struct kq_timer_cb_data *kc;
struct proc *p;
sbintime_t now;
- kn = knx;
kc = kn->kn_ptr.p_v;
if ((kn->kn_flags & EV_ONESHOT) != 0 || kc->to == 0) {
@@ -742,17 +741,26 @@ filt_timerexpire(void *knx)
*/
p = kc->p;
if (P_SHOULDSTOP(p) || P_KILLED(p)) {
- PROC_LOCK(p);
+ if (!proc_locked)
+ PROC_LOCK(p);
if (P_SHOULDSTOP(p) || P_KILLED(p)) {
TAILQ_INSERT_TAIL(&p->p_kqtim_stop, kc, link);
- PROC_UNLOCK(p);
+ if (!proc_locked)
+ PROC_UNLOCK(p);
return;
}
- PROC_UNLOCK(p);
+ if (!proc_locked)
+ PROC_UNLOCK(p);
}
kqtimer_sched_callout(kc);
}
+static void
+filt_timerexpire(void *knx)
+{
+ filt_timerexpire_l(knx, false);
+}
+
/*
* data contains amount of time to sleep
*/