summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/kern/uipc_syscalls.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/kern/uipc_syscalls.c')
-rw-r--r--freebsd/sys/kern/uipc_syscalls.c97
1 files changed, 76 insertions, 21 deletions
diff --git a/freebsd/sys/kern/uipc_syscalls.c b/freebsd/sys/kern/uipc_syscalls.c
index 0872aa62..9c4c52e4 100644
--- a/freebsd/sys/kern/uipc_syscalls.c
+++ b/freebsd/sys/kern/uipc_syscalls.c
@@ -60,6 +60,8 @@ __FBSDID("$FreeBSD$");
#include <sys/socketvar.h>
#include <sys/syscallsubr.h>
#include <sys/uio.h>
+#include <sys/un.h>
+#include <sys/unpcb.h>
#ifdef KTRACE
#include <sys/ktrace.h>
#endif
@@ -831,6 +833,15 @@ kern_socketpair(struct thread *td, int domain, int type, int protocol,
error = soconnect2(so2, so1);
if (error != 0)
goto free4;
+ } else if (so1->so_proto->pr_flags & PR_CONNREQUIRED) {
+ struct unpcb *unp, *unp2;
+ unp = sotounpcb(so1);
+ unp2 = sotounpcb(so2);
+ /*
+ * No need to lock the unps, because the sockets are brand-new.
+ * No other threads can be using them yet
+ */
+ unp_copy_peercred(td, unp, unp2, unp);
}
finit(fp1, FREAD | FWRITE | fflag, DTYPE_SOCKET, fp1->f_data,
&socketops);
@@ -1260,7 +1271,7 @@ kern_recvit(struct thread *td, int s, struct msghdr *mp, enum uio_seg fromseg,
{
struct uio auio;
struct iovec *iov;
- struct mbuf *m, *control = NULL;
+ struct mbuf *control, *m;
caddr_t ctlbuf;
struct file *fp;
struct socket *so;
@@ -1307,6 +1318,7 @@ kern_recvit(struct thread *td, int s, struct msghdr *mp, enum uio_seg fromseg,
if (KTRPOINT(td, KTR_GENIO))
ktruio = cloneuio(&auio);
#endif
+ control = NULL;
len = auio.uio_resid;
error = soreceive(so, &fromsa, &auio, NULL,
(mp->msg_control || controlp) ? &control : NULL,
@@ -1370,30 +1382,22 @@ kern_recvit(struct thread *td, int s, struct msghdr *mp, enum uio_seg fromseg,
control->m_data += sizeof (struct cmsghdr);
}
#endif
+ ctlbuf = mp->msg_control;
len = mp->msg_controllen;
- m = control;
mp->msg_controllen = 0;
- ctlbuf = mp->msg_control;
-
- while (m && len > 0) {
- unsigned int tocopy;
-
- if (len >= m->m_len)
- tocopy = m->m_len;
- else {
- mp->msg_flags |= MSG_CTRUNC;
- tocopy = len;
- }
-
- if ((error = copyout(mtod(m, caddr_t),
- ctlbuf, tocopy)) != 0)
+ for (m = control; m != NULL && len >= m->m_len; m = m->m_next) {
+ if ((error = copyout(mtod(m, caddr_t), ctlbuf,
+ m->m_len)) != 0)
goto out;
- ctlbuf += tocopy;
- len -= tocopy;
- m = m->m_next;
+ ctlbuf += m->m_len;
+ len -= m->m_len;
+ mp->msg_controllen += m->m_len;
+ }
+ if (m != NULL) {
+ mp->msg_flags |= MSG_CTRUNC;
+ m_dispose_extcontrolm(m);
}
- mp->msg_controllen = ctlbuf - (caddr_t)mp->msg_control;
}
out:
fdrop(fp, td);
@@ -1405,8 +1409,11 @@ out:
if (error == 0 && controlp != NULL)
*controlp = control;
- else if (control)
+ else if (control != NULL) {
+ if (error != 0)
+ m_dispose_extcontrolm(control);
m_freem(control);
+ }
return (error);
}
@@ -2134,3 +2141,51 @@ getsockaddr(struct sockaddr **namp, caddr_t uaddr, size_t len)
return (0);
#endif /* __rtems__ */
}
+
+/*
+ * Dispose of externalized rights from an SCM_RIGHTS message. This function
+ * should be used in error or truncation cases to avoid leaking file descriptors
+ * into the recipient's (the current thread's) table.
+ */
+void
+m_dispose_extcontrolm(struct mbuf *m)
+{
+ struct cmsghdr *cm;
+ struct file *fp;
+ struct thread *td;
+ socklen_t clen, datalen;
+ int error, fd, *fds, nfd;
+
+ td = curthread;
+ for (; m != NULL; m = m->m_next) {
+ if (m->m_type != MT_EXTCONTROL)
+ continue;
+ cm = mtod(m, struct cmsghdr *);
+ clen = m->m_len;
+ while (clen > 0) {
+ if (clen < sizeof(*cm))
+ panic("%s: truncated mbuf %p", __func__, m);
+ datalen = CMSG_SPACE(cm->cmsg_len - CMSG_SPACE(0));
+ if (clen < datalen)
+ panic("%s: truncated mbuf %p", __func__, m);
+
+ if (cm->cmsg_level == SOL_SOCKET &&
+ cm->cmsg_type == SCM_RIGHTS) {
+ fds = (int *)CMSG_DATA(cm);
+ nfd = (cm->cmsg_len - CMSG_SPACE(0)) /
+ sizeof(int);
+
+ while (nfd-- > 0) {
+ fd = *fds++;
+ error = fget(td, fd, &cap_no_rights,
+ &fp);
+ if (error == 0)
+ fdclose(td, fp, fd);
+ }
+ }
+ clen -= datalen;
+ cm = (struct cmsghdr *)((uint8_t *)cm + datalen);
+ }
+ m_chtype(m, MT_CONTROL);
+ }
+}