Module Name:    src
Committed By:   riastradh
Date:           Wed Jun 29 22:10:43 UTC 2022

Modified Files:
        src/sys/kern: kern_ktrace.c kern_sleepq.c
        src/sys/sys: ktrace.h

Log Message:
ktrace(9): Fix mutex detection in ktrcsw.

On _entry_ to sleepq_block, l->l_syncobj is set so that ktrcsw
(ktr_csw) has the opportunity to detect whether it's a mutex or
rwlock.  It is critical to avoid ktealloc when we're sleeping on a
mutex because we may be in softint context where ktealloc is
forbidden.

But after mi_switch, on _exit_ from sleepq_block, l->l_syncobj may
have been changed back to &sched_syncobj or something by
sleepq_remove, and so ktrcsw can no longer rely on l->l_syncobj to
determine whether we _were_ sleeping on a mutex or not.

Instead, save the syncobj in sleepq_block and pass it through as an
argument to ktrcsw.

Reported-by: syzbot+414edba9d161b7502...@syzkaller.appspotmail.com
Reported-by: syzbot+4425c97ac717b1249...@syzkaller.appspotmail.com
Reported-by: syzbot+5812565b926ee8eb5...@syzkaller.appspotmail.com
Reported-by: syzbot+8b9d7b066c32dbcdc...@syzkaller.appspotmail.com
Reported-by: syzbot+909a8e743c967d97f...@syzkaller.appspotmail.com
Reported-by: syzbot+e2a34bb5509bea0bb...@syzkaller.appspotmail.com
Reported-by: syzbot+faaea3aad6c9d0829...@syzkaller.appspotmail.com


To generate a diff of this commit:
cvs rdiff -u -r1.180 -r1.181 src/sys/kern/kern_ktrace.c
cvs rdiff -u -r1.71 -r1.72 src/sys/kern/kern_sleepq.c
cvs rdiff -u -r1.67 -r1.68 src/sys/sys/ktrace.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/kern_ktrace.c
diff -u src/sys/kern/kern_ktrace.c:1.180 src/sys/kern/kern_ktrace.c:1.181
--- src/sys/kern/kern_ktrace.c:1.180	Mon Jun 27 03:56:37 2022
+++ src/sys/kern/kern_ktrace.c	Wed Jun 29 22:10:43 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_ktrace.c,v 1.180 2022/06/27 03:56:37 riastradh Exp $	*/
+/*	$NetBSD: kern_ktrace.c,v 1.181 2022/06/29 22:10:43 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2006, 2007, 2008, 2020 The NetBSD Foundation, Inc.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_ktrace.c,v 1.180 2022/06/27 03:56:37 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_ktrace.c,v 1.181 2022/06/29 22:10:43 riastradh Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -76,6 +76,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_ktrace.
 #include <sys/ioctl.h>
 #include <sys/callout.h>
 #include <sys/kauth.h>
+#include <sys/cpu.h>
 
 #include <sys/mount.h>
 #include <sys/syscallargs.h>
@@ -807,7 +808,7 @@ ktr_psig(int sig, sig_t action, const si
 }
 
 void
-ktr_csw(int out, int user)
+ktr_csw(int out, int user, const struct syncobj *syncobj)
 {
 	lwp_t *l = curlwp;
 	struct proc *p = l->l_proc;
@@ -819,10 +820,14 @@ ktr_csw(int out, int user)
 
 	/*
 	 * Don't record context switches resulting from blocking on
-	 * locks; it's too easy to get duff results.
+	 * locks; the results are not useful, and the mutex may be in a
+	 * softint, which would lead us to ktealloc in softint context,
+	 * which is forbidden.
 	 */
-	if (l->l_syncobj == &mutex_syncobj || l->l_syncobj == &rw_syncobj)
+	if (syncobj == &mutex_syncobj || syncobj == &rw_syncobj)
 		return;
+	KASSERT(!cpu_intr_p());
+	KASSERT(!cpu_softintr_p());
 
 	/*
 	 * We can't sleep if we're already going to sleep (if original

Index: src/sys/kern/kern_sleepq.c
diff -u src/sys/kern/kern_sleepq.c:1.71 src/sys/kern/kern_sleepq.c:1.72
--- src/sys/kern/kern_sleepq.c:1.71	Fri Apr  8 10:17:55 2022
+++ src/sys/kern/kern_sleepq.c	Wed Jun 29 22:10:43 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_sleepq.c,v 1.71 2022/04/08 10:17:55 andvar Exp $	*/
+/*	$NetBSD: kern_sleepq.c,v 1.72 2022/06/29 22:10:43 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2006, 2007, 2008, 2009, 2019, 2020 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_sleepq.c,v 1.71 2022/04/08 10:17:55 andvar Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_sleepq.c,v 1.72 2022/06/29 22:10:43 riastradh Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -309,8 +309,9 @@ sleepq_block(int timo, bool catch_p)
 	lwp_t *l = curlwp;
 	bool early = false;
 	int biglocks = l->l_biglocks;
+	struct syncobj *syncobj = l->l_syncobj;
 
-	ktrcsw(1, 0);
+	ktrcsw(1, 0, syncobj);
 
 	/*
 	 * If sleeping interruptably, check for pending signals, exits or
@@ -397,7 +398,7 @@ sleepq_block(int timo, bool catch_p)
 		}
 	}
 
-	ktrcsw(0, 0);
+	ktrcsw(0, 0, syncobj);
 	if (__predict_false(biglocks != 0)) {
 		KERNEL_LOCK(biglocks, NULL);
 	}

Index: src/sys/sys/ktrace.h
diff -u src/sys/sys/ktrace.h:1.67 src/sys/sys/ktrace.h:1.68
--- src/sys/sys/ktrace.h:1.67	Tue Sep 14 22:01:40 2021
+++ src/sys/sys/ktrace.h	Wed Jun 29 22:10:43 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: ktrace.h,v 1.67 2021/09/14 22:01:40 christos Exp $	*/
+/*	$NetBSD: ktrace.h,v 1.68 2022/06/29 22:10:43 riastradh Exp $	*/
 
 /*
  * Copyright (c) 1988, 1993
@@ -297,6 +297,8 @@ __END_DECLS
 
 #else
 
+struct syncobj;
+
 void ktrinit(void);
 void ktrderef(struct proc *);
 void ktradref(struct proc *);
@@ -307,7 +309,7 @@ extern int ktrace_on;
 int ktruser(const char *, void *, size_t, int);
 bool ktr_point(int);
 
-void ktr_csw(int, int);
+void ktr_csw(int, int, const struct syncobj *);
 void ktr_emul(void);
 void ktr_geniov(int, enum uio_rw, struct iovec *, size_t, int);
 void ktr_genio(int, enum uio_rw, const void *, size_t, int);
@@ -349,10 +351,10 @@ ktrpoint(int fac)
 }
 
 static __inline void
-ktrcsw(int a, int b)
+ktrcsw(int a, int b, const struct syncobj *c)
 {
 	if (__predict_false(ktrace_on))
-		ktr_csw(a, b);
+		ktr_csw(a, b, c);
 }
 
 static __inline void

Reply via email to