summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2018-11-21 16:50:50 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2018-11-21 16:50:50 +0000
commitcedd79da68cfed8bf4a1d1cab59449ddf2ae7e6e (patch)
treec715526f37ce2aba9f441f00ba999433198e82de /sys/kern
parent0938e5da3a603b8c340e9d228b80b002916f9df6 (diff)
When using MSG_PEEK to peak into packets skip control messages holding
SCM_RIGHTS from being sent to the userland since they hold kernel internal data and it does not make sense to externalize it. OK deraadt@, guenther@, visa@
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/uipc_socket.c22
-rw-r--r--sys/kern/uipc_usrreq.c9
2 files changed, 20 insertions, 11 deletions
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index 94d5afafe73..9ba5b442e77 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uipc_socket.c,v 1.228 2018/11/19 13:15:37 visa Exp $ */
+/* $OpenBSD: uipc_socket.c,v 1.229 2018/11/21 16:50:49 claudio Exp $ */
/* $NetBSD: uipc_socket.c,v 1.21 1996/02/04 02:17:52 christos Exp $ */
/*
@@ -665,9 +665,9 @@ soreceive(struct socket *so, struct mbuf **paddr, struct uio *uio,
mp = mp0;
if (paddr)
- *paddr = 0;
+ *paddr = NULL;
if (controlp)
- *controlp = 0;
+ *controlp = NULL;
if (flagsp)
flags = *flagsp &~ MSG_EOR;
else
@@ -814,8 +814,13 @@ dontblock:
}
}
while (m && m->m_type == MT_CONTROL && error == 0) {
+ int skip = 0;
if (flags & MSG_PEEK) {
- if (controlp)
+ if (mtod(m, struct cmsghdr *)->cmsg_type ==
+ SCM_RIGHTS) {
+ /* don't leak internalized SCM_RIGHTS msgs */
+ skip = 1;
+ } else if (controlp)
*controlp = m_copym(m, 0, m->m_len, M_NOWAIT);
m = m->m_next;
} else {
@@ -826,9 +831,7 @@ dontblock:
m = so->so_rcv.sb_mb;
sbsync(&so->so_rcv, nextrecord);
if (controlp) {
- if (pr->pr_domain->dom_externalize &&
- mtod(cm, struct cmsghdr *)->cmsg_type ==
- SCM_RIGHTS) {
+ if (pr->pr_domain->dom_externalize) {
error =
(*pr->pr_domain->dom_externalize)
(cm, controllen, flags);
@@ -839,8 +842,7 @@ dontblock:
* Dispose of any SCM_RIGHTS message that went
* through the read path rather than recv.
*/
- if (pr->pr_domain->dom_dispose &&
- mtod(cm, struct cmsghdr *)->cmsg_type == SCM_RIGHTS)
+ if (pr->pr_domain->dom_dispose)
pr->pr_domain->dom_dispose(cm);
m_free(cm);
}
@@ -849,7 +851,7 @@ dontblock:
nextrecord = so->so_rcv.sb_mb->m_nextpkt;
else
nextrecord = so->so_rcv.sb_mb;
- if (controlp) {
+ if (controlp && !skip) {
orig_resid = 0;
controlp = &(*controlp)->m_next;
}
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
index e9a6167c6f3..bd819c07086 100644
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uipc_usrreq.c,v 1.135 2018/11/09 14:14:31 claudio Exp $ */
+/* $OpenBSD: uipc_usrreq.c,v 1.136 2018/11/21 16:50:49 claudio Exp $ */
/* $NetBSD: uipc_usrreq.c,v 1.18 1996/02/09 19:00:50 christos Exp $ */
/*
@@ -663,6 +663,13 @@ unp_externalize(struct mbuf *rights, socklen_t controllen, int flags)
struct file *fp;
int nfds, error = 0;
+ /*
+ * This code only works because SCM_RIGHTS is the only supported
+ * control message type on unix sockets. Enforce this here.
+ */
+ if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET)
+ return EINVAL;
+
nfds = (cm->cmsg_len - CMSG_ALIGN(sizeof(*cm))) /
sizeof(struct fdpass);
if (controllen < CMSG_ALIGN(sizeof(struct cmsghdr)))