DF-5816 / fix.diff
--- 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)); |