NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/60436: kqueue(2): random kernel null pointer deref in EVFILT_PROC NOTE_TRACK



>Number:         60436
>Category:       kern
>Synopsis:       kqueue(2): random kernel null pointer deref in EVFILT_PROC NOTE_TRACK
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Jul 10 14:20:00 +0000 2026
>Originator:     Taylor R Campbell
>Release:        current, 11, 10
>Organization:
Go Fork Yourself, Inc.
>Environment:
>Description:

uvm_fault(0xffff9d171e3dbc80, 0x0, 2) -> e
fatal page fault in supervisor mode
trap type 6 code 0x2 rip 0xffffffff80e30191 cs 0x8 rflags 0x10246 cr2 0xb0 ilevel 0 rsp 0xffffc512650a0e08
curlwp 0xffff9d171d137400 pid 9969.9969 lowest kstack 0xffffc5126509c2c0
panic: trap
cpu6: Begin traceback...
vpanic() at netbsd:vpanic+0x189
panic() at netbsd:panic+0x3c
trap() at netbsd:trap+0xb35
--- trap (number 6) ---
_mutex_init() at netbsd:_mutex_init+0x33
knote_proc_fork() at netbsd:knote_proc_fork+0xa4
fork1() at netbsd:fork1+0x696
sys_fork() at netbsd:sys_fork+0x29
syscall() at netbsd:syscall+0x9d
--- syscall (number 2) ---
netbsd:syscall+0x9d:
cpu6: End traceback...

    144 static inline struct knote *
    145 knote_alloc(bool sleepok)
    146 {
    147 	struct knote_impl *ki;
    148 
    149 	ki = kmem_zalloc(sizeof(*ki), sleepok ? KM_SLEEP : KM_NOSLEEP);
 => 150 	mutex_init(&ki->ki_foplock, MUTEX_DEFAULT, IPL_NONE);
    151 
    152 	return KIMPL_TO_KNOTE(ki);
    153 }

https://nxr.netbsd.org/xref/src/sys/kern/kern_event.c?r=1.152#144
>How-To-Repeat:
cd /usr/tests/kernel/queue && atf-run t_proc2
>Fix:
1. Stop-gap fix:

	ki = kmem_zalloc(sizeof(*ki), sleepok ? KM_SLEEP : KM_NOSLEEP);
+	if (ki == NULL)
+		return NULL;
	mutex_init(&ki->ki_foplock, MUTEX_DEFAULT, IPL_NONE);

2. Why do we use KM_NOSLEEP at all here?  Why should this randomly fail
   when the system is swapping?  Why doesn't the one caller,
   knote_proc_fork_track, just have its caller allocate storage up
   front before any spin locks are held or knotes are in flux?

   1039 static int __noinline
   1040 knote_proc_fork_track(struct proc *p1, struct proc *p2, struct knote *okn)
   1041 {
   1042 	struct kqueue *kq = okn->kn_kq;
   1043 
   1044 	KASSERT(mutex_owned(&kq->kq_lock));
   1045 	KASSERT(mutex_owned(p1->p_lock));
...
   1053 	if (!kn_enter_flux(okn)) {
   1054 		return 0;
   1055 	}
...
   1102 	knchild = knote_alloc(false);
   1103 	kntrack = knote_alloc(false);
   1104 	if (__predict_false(knchild == NULL || kntrack == NULL)) {
   1105 		error = SET_ERROR(ENOMEM);
   1106 		goto out;
   1107 	}
...
   1199 	if (kn_leave_flux(okn)) {
   1200 		KQ_FLUX_WAKEUP(kq);
   1201 	}
   1202 
   1203 	return error;
   1204 }
...
   1204 }
   1205 
   1206 void
   1207 knote_proc_fork(struct proc *p1, struct proc *p2)
   1208 {
   1209 	struct knote *kn;
   1210 	struct kqueue *kq;
   1211 	uint32_t fflags;
   1212 
   1213 	mutex_enter(p1->p_lock);
...
   1234 		mutex_spin_enter(&kq->kq_lock);
   1235 		kn->kn_fflags |= (kn->kn_sfflags & NOTE_FORK);
   1236 		if (__predict_false(kn->kn_sfflags & NOTE_TRACK)) {
   1237 			/*
   1238 			 * This will drop kq_lock and p_lock and
   1239 			 * re-acquire them before it returns.
   1240 			 */
   1241 			if (knote_proc_fork_track(p1, p2, kn)) {
   1242 				kn->kn_fflags |= NOTE_TRACKERR;
   1243 			}

https://nxr.netbsd.org/xref/src/sys/kern/kern_event.c?r=1.152#1039




Home | Main Index | Thread Index | Old Index