diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2018-11-21 16:50:50 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2018-11-21 16:50:50 +0000 |
commit | cedd79da68cfed8bf4a1d1cab59449ddf2ae7e6e (patch) | |
tree | c715526f37ce2aba9f441f00ba999433198e82de /sys/kern | |
parent | 0938e5da3a603b8c340e9d228b80b002916f9df6 (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.c | 22 | ||||
-rw-r--r-- | sys/kern/uipc_usrreq.c | 9 |
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))) |