diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index 326cf031..fb696d3 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -939,10 +939,11 @@ freebsd32_copy_msg_out(struct msghdr *msg, struct mbuf *control) struct cmsghdr *cm; void *data; socklen_t clen, datalen; - int error; + int error, i, rights; caddr_t ctlbuf; int len, maxlen, copylen; struct mbuf *m; + error = 0; len = msg->msg_controllen; @@ -964,6 +965,10 @@ freebsd32_copy_msg_out(struct msghdr *msg, struct mbuf *control) break; } + rights = mtod(control, struct cmsghdr *)->cmsg_level + == SOL_SOCKET && mtod(control, struct cmsghdr *)-> + cmsg_type == SCM_RIGHTS; + data = CMSG_DATA(cm); datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; @@ -993,7 +998,15 @@ freebsd32_copy_msg_out(struct msghdr *msg, struct mbuf *control) copylen = datalen; if (len < copylen) { msg->msg_flags |= MSG_CTRUNC; - copylen = len; + if (rights) { + for (i = len / sizeof(int); + i < copylen / sizeof(int); i++) + kern_close(curthread, + ((int *)data)[i]); + copylen = rounddown(len, + sizeof(int)); + } else + copylen = len; } error = copyout(data,ctlbuf,copylen); @@ -1011,7 +1024,7 @@ freebsd32_copy_msg_out(struct msghdr *msg, struct mbuf *control) clen = 0; cm = NULL; } - } + } m = m->m_next; } diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index 06869b2..e6db978 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -944,6 +944,7 @@ kern_recvit(td, s, mp, fromseg, controlp) #ifdef KTRACE struct uio *ktruio = NULL; #endif + int rights; if (controlp != NULL) *controlp = NULL; @@ -1023,6 +1024,10 @@ kern_recvit(td, s, mp, fromseg, controlp) mp->msg_namelen = len; } if (mp->msg_control && controlp == NULL) { + rights = + mtod(control, struct cmsghdr *)->cmsg_level == SOL_SOCKET && + mtod(control, struct cmsghdr *)->cmsg_type == SCM_RIGHTS; + #ifdef COMPAT_OLDSOCK /* * We assume that old recvmsg calls won't receive access @@ -1032,13 +1037,8 @@ kern_recvit(td, s, mp, fromseg, controlp) * is tossed. */ if (control && mp->msg_flags & MSG_COMPAT) { - if (mtod(control, struct cmsghdr *)->cmsg_level != - SOL_SOCKET || - mtod(control, struct cmsghdr *)->cmsg_type != - SCM_RIGHTS) { - mp->msg_controllen = 0; + if (!rights) goto out; - } control->m_len -= sizeof (struct cmsghdr); control->m_data += sizeof (struct cmsghdr); } @@ -1055,7 +1055,26 @@ kern_recvit(td, s, mp, fromseg, controlp) tocopy = m->m_len; else { mp->msg_flags |= MSG_CTRUNC; - tocopy = len; + + /* + * If receiving cmsg has a short + * control buffer, truncated copyout + * must also close filedescriptors + * that cannot be copied to the + * userspace. + * + * We rely on the fact that + * unp_externalize() returns a single + * mbuf instead of chain. + */ + if (rights) { + tocopy = rounddown(len, sizeof(int)); + for (i = tocopy / sizeof(int); + i < m->m_len / sizeof(int); i++) + kern_close(td, + mtod(m, int *)[i]); + } else + tocopy = len; } if ((error = copyout(mtod(m, caddr_t),