DragonFlyBSD Kernel Audit
DF-2781 / fix.diff
← back to finding ↓ download raw
Fix for DF-2781: system-wide queue cap (kern.mqueue.mq_max_queues=256), cap check placed after mq_mtx acquisition so the shared exit path releases a held lock.

--- sys/kern/sys_mqueue.c
+++ sys/kern/sys_mqueue.c
@@ -75,6 +75,9 @@
 static u_int			mq_def_maxmsg = 32;
 static u_int			mq_max_maxmsg = 16 * 32;
 
+static u_int			mq_max_queues = 256;
+static u_int			mq_total_queues;
+
 static struct lock		mqlist_mtx;
 static LIST_HEAD(, mqueue)	mqueue_head =
 	LIST_HEAD_INITIALIZER(mqueue_head);
@@ -394,6 +397,7 @@
 	 */
 	if (mq->mq_refcnt == 0 && (mq->mq_attrib.mq_flags & MQ_UNLINK)) {
 		LIST_REMOVE(mq, mq_list);
+		mq_total_queues--;
 		destroy = true;
 	} else
 		destroy = false;
@@ -582,7 +586,15 @@
 		/* Insert the queue to the list */
 		mq = mq_new;
 		lockmgr(&mq->mq_mtx, LK_EXCLUSIVE);
+
+		/* Check the system-wide queue count limit */
+		if (mq_total_queues >= mq_max_queues) {
+			error = ENOMEM;
+			goto exit;
+		}
+
 		LIST_INSERT_HEAD(&mqueue_head, mq, mq_list);
+		mq_total_queues++;
 		mq_new = NULL;
 		getnanotime(&mq->mq_btime);
 		mq->mq_atime = mq->mq_mtime = mq->mq_btime;
@@ -1122,8 +1134,10 @@
 	KNOTE(&mq->mq_wkq.ki_note, 0);
 
 	refcnt = mq->mq_refcnt;
-	if (refcnt == 0)
+	if (refcnt == 0) {
 		LIST_REMOVE(mq, mq_list);
+		mq_total_queues--;
+	}
 
 	lockmgr(&mq->mq_mtx, LK_RELEASE);
 error:
@@ -1166,4 +1180,8 @@
     CTLFLAG_RW, &mq_max_maxmsg, 0,
     "Maximal allowed message count");
 
+SYSCTL_INT(_kern_mqueue, OID_AUTO, mq_max_queues,
+    CTLFLAG_RW, &mq_max_queues, 0,
+    "Maximal number of message queues system-wide");
+
 SYSINIT(sys_mqueue_init, SI_SUB_PRE_DRIVERS, SI_ORDER_ANY, mqueue_sysinit, NULL);