DragonFlyBSD Kernel Audit
DF-2778 / fix.diff
← back to finding ↓ download raw
Fix for DF-2778: clear mq_notify registrations at process exit (mqueue_proc_exit).

--- sys_mqueue.c	2026-09-01 04:01:55.500648734 +0000
+++ sys_mqueue.2778.only	2026-09-01 04:03:50.167194127 +0000
@@ -408,6 +408,29 @@
 }
 
 /*
+ * mqueue_proc_exit: called from exit1() after the exiting process's
+ * descriptors have been closed.  mq_close_fop() only runs when the LAST
+ * file reference drops, which may happen in a different process (fork)
+ * long after the registrant exited; clear any notification registrations
+ * that still point at the exiting process so mq_notify_proc can never
+ * dangle.
+ */
+void
+mqueue_proc_exit(struct proc *p)
+{
+	struct mqueue *mq;
+
+	lockmgr(&mqlist_mtx, LK_EXCLUSIVE);
+	LIST_FOREACH(mq, &mqueue_head, mq_list) {
+		lockmgr(&mq->mq_mtx, LK_EXCLUSIVE);
+		if (mq->mq_notify_proc == p)
+			mq->mq_notify_proc = NULL;
+		lockmgr(&mq->mq_mtx, LK_RELEASE);
+	}
+	lockmgr(&mqlist_mtx, LK_RELEASE);
+}
+
+/*
  * General mqueue system calls.
  */
 

--- kern_exit.c	2026-09-01 04:01:55.500648734 +0000
+++ kern_exit.c.new	2026-09-01 04:02:22.424307123 +0000
@@ -381,6 +381,13 @@
 	 */
 	fdfree(p, NULL);
 
+	/*
+	 * Clear POSIX mqueue notification registrations still targeting
+	 * this process (the registrant may have exited while a fork child
+	 * still holds the descriptor).
+	 */
+	mqueue_proc_exit(p);
+
 	if (p->p_leader->p_peers) {
 		q = p->p_leader;
 		while(q->p_peers != p)

--- mqueue.h	2026-09-01 04:01:55.504648683 +0000
+++ mqueue.h.new	2026-09-01 04:02:22.428307072 +0000
@@ -117,6 +117,7 @@
 
 /* Prototypes */
 void	mqueue_sysinit(void);
+void	mqueue_proc_exit(struct proc *);
 int	abstimeout2timo(struct timespec *, int *);
 int	mq_send1(struct lwp *, mqd_t, const char *, size_t, unsigned, struct timespec *);
 int	mq_receive1(struct lwp *, mqd_t, void *, size_t, unsigned *, struct timespec *,