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 *);