⬢ DragonFlyBSD Kernel Audit
DF-5816 / fix.diff
← back to finding ↓ download raw
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -48,6 +48,7 @@
 #include <sys/stat.h>
 #include <sys/mount.h>
 #include <sys/sysctl.h>
+#include <sys/caps.h>
 #include <sys/un.h>
 #include <sys/unpcb.h>
 #include <sys/vnode.h>
@@ -1433,7 +1434,7 @@
 unp_pcblist(SYSCTL_HANDLER_ARGS)
 {
 	struct unp_global_head *head = arg1;
-	int error, i, n;
+	int error, i, n, see_ptrs;
 	struct unpcb *unp, *marker;
 
 	KKASSERT(curproc != NULL);
@@ -1454,6 +1455,15 @@
 	marker = kmalloc(sizeof(*marker), M_UNPCB, M_WAITOK | M_ZERO);
 	marker->unp_flags |= UNP_MARKER;
 
+	/*
+	 * DF-5816: the raw kernel pointers exported in xu_unpp, xu_unp
+	 * (unp_socket, unp_conn, unp_addr, unp_vnode, unp_rvnode, unp_fp,
+	 * unp_refs/unp_reflink/unp_link) and xu_socket (xso_so, so_pcb)
+	 * must not be disclosed to unprivileged readers.  The copied
+	 * address payloads (xu_addr/xu_caddr) are unaffected.
+	 */
+	see_ptrs = (caps_priv_check_td(req->td, SYSCAP_RESTRICTEDROOT) == 0);
+
 	lwkt_gettoken(&unp_token);
 
 	n = head->count;
@@ -1493,6 +1503,22 @@
 		}
 		bcopy(unp, &xu.xu_unp, sizeof(*unp));
 		sotoxsocket(unp->unp_socket, &xu.xu_socket);
+		if (!see_ptrs) {
+			xu.xu_unpp = NULL;
+			xu.xu_unp.unp_socket = NULL;
+			xu.xu_unp.unp_conn = NULL;
+			xu.xu_unp.unp_refs.lh_first = NULL;
+			xu.xu_unp.unp_reflink.le_next = NULL;
+			xu.xu_unp.unp_reflink.le_prev = NULL;
+			xu.xu_unp.unp_addr = NULL;
+			xu.xu_unp.unp_fp = NULL;
+			xu.xu_unp.unp_vnode = NULL;
+			xu.xu_unp.unp_rvnode = NULL;
+			xu.xu_unp.unp_link.tqe_next = NULL;
+			xu.xu_unp.unp_link.tqe_prev = NULL;
+			xu.xu_socket.xso_so = NULL;
+			xu.xu_socket.so_pcb = NULL;
+		}
 
 		/* NOTE: This could block and temporarily release unp_token */
 		error = SYSCTL_OUT(req, &xu, sizeof(xu));