DragonFlyBSD Kernel Audit
DF-2702 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -1420,8 +1420,28 @@
 	 */
 	while (m && m->m_type == MT_CONTROL && error == 0) {
 		if (flags & MSG_PEEK) {
-			if (controlp)
-				*controlp = m_copym(m, 0, m->m_len, M_NOWAIT);
+			/*
+			 * NOTE: Control mbufs carrying SCM_RIGHTS still
+			 * contain their INTERNALIZED form (raw kernel
+			 * struct file pointers) while queued.  Externalizing
+			 * a copy here would wrongly drop the in-flight
+			 * rights references of the still-queued original,
+			 * and copying them out raw would disclose kernel
+			 * heap pointers to userland.  Rights are only
+			 * externalized when the message is consumed.
+			 */
+			if (controlp) {
+				const struct cmsghdr *cm = mtod(m,
+				    const struct cmsghdr *);
+
+				if (pr->pr_domain == NULL ||
+				    pr->pr_domain->dom_externalize == NULL ||
+				    cm->cmsg_level != SOL_SOCKET ||
+				    cm->cmsg_type != SCM_RIGHTS) {
+					*controlp = m_copym(m, 0, m->m_len,
+							   M_NOWAIT);
+				}
+			}
 			m = m->m_next;	/* XXX race */
 		} else {
 			const struct cmsghdr *cm = mtod(m, struct cmsghdr *);