Do not crash in witness code if interrupt fires early.
authorbluhm <bluhm@openbsd.org>
Wed, 25 Sep 2024 18:24:13 +0000 (18:24 +0000)
committerbluhm <bluhm@openbsd.org>
Wed, 25 Sep 2024 18:24:13 +0000 (18:24 +0000)
It can happen that an interrupt handler is called immediately on a
secondary CPU when it is spun up during boot.  At that moment no
process is schduled yet, so curproc is NULL.  To prevent a crash
when p->p_sleeplocks is dereferenced, skip witness check in this
case.

OK visa@

sys/kern/subr_witness.c

index 9f09190..7110414 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: subr_witness.c,v 1.53 2024/06/03 14:34:19 claudio Exp $       */
+/*     $OpenBSD: subr_witness.c,v 1.54 2024/09/25 18:24:13 bluhm Exp $ */
 
 /*-
  * Copyright (c) 2008 Isilon Systems, Inc.
@@ -766,7 +766,6 @@ witness_checkorder(struct lock_object *lock, int flags,
        struct lock_list_entry *lock_list, *lle;
        struct lock_instance *lock1, *lock2, *plock;
        struct lock_class *class, *iclass;
-       struct proc *p;
        struct witness *w, *w1;
        int i, j, s;
 
@@ -792,9 +791,9 @@ witness_checkorder(struct lock_object *lock, int flags,
                w = lock->lo_witness =
                    enroll(lock->lo_type, lock->lo_name, class);
 
-       p = curproc;
-
        if (class->lc_flags & LC_SLEEPLOCK) {
+               struct proc *p;
+
                /*
                 * Since spin locks include a critical section, this check
                 * implicitly enforces a lock order of all sleep locks before
@@ -811,6 +810,9 @@ witness_checkorder(struct lock_object *lock, int flags,
                 * If this is the first lock acquired then just return as
                 * no order checking is needed.
                 */
+               p = curproc;
+               if (p == NULL)
+                       return;
                lock_list = p->p_sleeplocks;
                if (lock_list == NULL || lock_list->ll_count == 0)
                        return;
@@ -1097,7 +1099,6 @@ witness_lock(struct lock_object *lock, int flags)
 {
        struct lock_list_entry **lock_list, *lle;
        struct lock_instance *instance;
-       struct proc *p;
        struct witness *w;
        int s;
 
@@ -1110,12 +1111,15 @@ witness_lock(struct lock_object *lock, int flags)
                w = lock->lo_witness =
                    enroll(lock->lo_type, lock->lo_name, LOCK_CLASS(lock));
 
-       p = curproc;
-
        /* Determine lock list for this lock. */
-       if (LOCK_CLASS(lock)->lc_flags & LC_SLEEPLOCK)
+       if (LOCK_CLASS(lock)->lc_flags & LC_SLEEPLOCK) {
+               struct proc *p;
+
+               p = curproc;
+               if (p == NULL)
+                       return;
                lock_list = &p->p_sleeplocks;
-       else
+       else
                lock_list = &witness_cpu[cpu_number()].wc_spinlocks;
 
        s = splhigh();
@@ -1243,20 +1247,23 @@ witness_unlock(struct lock_object *lock, int flags)
        struct lock_list_entry **lock_list, *lle;
        struct lock_instance *instance;
        struct lock_class *class;
-       struct proc *p;
        int i, j;
        int s;
 
        if (witness_cold || lock->lo_witness == NULL ||
            panicstr != NULL || db_active)
                return;
-       p = curproc;
        class = LOCK_CLASS(lock);
 
        /* Find lock instance associated with this lock. */
-       if (class->lc_flags & LC_SLEEPLOCK)
+       if (class->lc_flags & LC_SLEEPLOCK) {
+               struct proc *p;
+
+               p = curproc;
+               if (p == NULL)
+                       return;
                lock_list = &p->p_sleeplocks;
-       else
+       else
                lock_list = &witness_cpu[cpu_number()].wc_spinlocks;
 
        s = splhigh();