git: 5cc1d199412e - main - realtimer_expire: avoid proc lock recursion when called from itimer_proc_continue()

Konstantin Belousov kib at FreeBSD.org
Wed Apr 14 07:59:13 UTC 2021


The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=5cc1d199412ead0b4c234e21e881a31ef893a4f0

commit 5cc1d199412ead0b4c234e21e881a31ef893a4f0
Author:     Konstantin Belousov <kib at FreeBSD.org>
AuthorDate: 2021-04-13 13:47:24 +0000
Commit:     Konstantin Belousov <kib at FreeBSD.org>
CommitDate: 2021-04-14 07:53:19 +0000

    realtimer_expire: avoid proc lock recursion when called from itimer_proc_continue()
    
    It is fine to drop the process lock there, process cannot exit until its
    timers are cleared.
    
    Found by:       syzkaller
    Reported and reviewed by:       markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D29746
---
 sys/kern/kern_time.c | 24 +++++++++++++++++-------
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c
index d3b19111b0f3..ab22ac4a1697 100644
--- a/sys/kern/kern_time.c
+++ b/sys/kern/kern_time.c
@@ -105,6 +105,7 @@ static int	realtimer_settime(struct itimer *, int,
 static int	realtimer_delete(struct itimer *);
 static void	realtimer_clocktime(clockid_t, struct timespec *);
 static void	realtimer_expire(void *);
+static void	realtimer_expire_l(struct itimer *it, bool proc_locked);
 
 static int	register_posix_clock(int, const struct kclock *);
 static void	itimer_fire(struct itimer *it);
@@ -919,7 +920,7 @@ itimer_proc_continue(struct proc *p)
 				if ((it->it_flags & ITF_PSTOPPED) != 0) {
 					it->it_flags &= ~ITF_PSTOPPED;
 					if ((it->it_flags & ITF_DELETING) == 0)
-						realtimer_expire(it);
+						realtimer_expire_l(it, true);
 				}
 				ITIMER_UNLOCK(it);
 			}
@@ -1663,18 +1664,14 @@ itimespecfix(struct timespec *ts)
 	.tv_nsec = (ns) % 1000000000		\
 }
 
-/* Timeout callback for realtime timer */
 static void
-realtimer_expire(void *arg)
+realtimer_expire_l(struct itimer *it, bool proc_locked)
 {
 	struct timespec cts, ts;
 	struct timeval tv;
-	struct itimer *it;
 	struct proc *p;
 	uint64_t interval, now, overruns, value;
 
-	it = (struct itimer *)arg;
-
 	realtimer_clocktime(it->it_clockid, &cts);
 	/* Only fire if time is reached. */
 	if (timespeccmp(&cts, &it->it_time.it_value, >=)) {
@@ -1708,8 +1705,9 @@ realtimer_expire(void *arg)
 			/* single shot timer ? */
 			timespecclear(&it->it_time.it_value);
 		}
+
+		p = it->it_proc;
 		if (timespecisset(&it->it_time.it_value)) {
-			p = it->it_proc;
 			if (P_SHOULDSTOP(p) || P_KILLED(p)) {
 				it->it_flags |= ITF_PSTOPPED;
 			} else {
@@ -1719,9 +1717,14 @@ realtimer_expire(void *arg)
 				    realtimer_expire, it);
 			}
 		}
+
 		itimer_enter(it);
 		ITIMER_UNLOCK(it);
+		if (proc_locked)
+			PROC_UNLOCK(p);
 		itimer_fire(it);
+		if (proc_locked)
+			PROC_LOCK(p);
 		ITIMER_LOCK(it);
 		itimer_leave(it);
 	} else if (timespecisset(&it->it_time.it_value)) {
@@ -1738,6 +1741,13 @@ realtimer_expire(void *arg)
 	}
 }
 
+/* Timeout callback for realtime timer */
+static void
+realtimer_expire(void *arg)
+{
+	realtimer_expire_l(arg, false);
+}
+
 static void
 itimer_fire(struct itimer *it)
 {


More information about the dev-commits-src-all mailing list