Page MenuHomeFreeBSD

D16561.id46166.diff
No OneTemporary

D16561.id46166.diff

Index: sys/compat/cloudabi/cloudabi_sock.c
===================================================================
--- sys/compat/cloudabi/cloudabi_sock.c
+++ sys/compat/cloudabi/cloudabi_sock.c
@@ -120,9 +120,10 @@
sizeof(int);
if (nfds > fdslen) {
/* Unable to store file descriptors. */
- nfds = fdslen;
*rflags |=
CLOUDABI_SOCK_RECV_FDS_TRUNCATED;
+ m_dispose_extcontrolm(control);
+ break;
}
error = copyout(CMSG_DATA(chdr), fds,
nfds * sizeof(int));
@@ -135,9 +136,13 @@
*rfdslen += nfds;
}
}
- m_free(control);
+ if (control != NULL) {
+ if (error != 0)
+ m_dispose_extcontrolm(control);
+ m_free(control);
+ }
}
- return (0);
+ return (error);
}
int
Index: sys/compat/freebsd32/freebsd32_misc.c
===================================================================
--- sys/compat/freebsd32/freebsd32_misc.c
+++ sys/compat/freebsd32/freebsd32_misc.c
@@ -1133,15 +1133,11 @@
maxlen = msg->msg_controllen;
msg->msg_controllen = 0;
- m = control;
ctlbuf = msg->msg_control;
-
- while (m && len > 0) {
+ for (m = control; m != NULL && len > 0; m = m->m_next) {
cm = mtod(m, struct cmsghdr *);
clen = m->m_len;
-
while (cm != NULL) {
-
if (sizeof(struct cmsghdr) > clen ||
cm->cmsg_len > clen) {
error = EINVAL;
@@ -1160,7 +1156,8 @@
copylen = sizeof(struct cmsghdr);
if (len < copylen) {
msg->msg_flags |= MSG_CTRUNC;
- copylen = len;
+ m_dispose_extcontrolm(m);
+ goto exit;
}
error = copyout(cm, ctlbuf, copylen);
@@ -1177,7 +1174,8 @@
copylen = datalen_out;
if (len < copylen) {
msg->msg_flags |= MSG_CTRUNC;
- copylen = len;
+ m_dispose_extcontrolm(m);
+ goto exit;
}
error = copyout(data, ctlbuf, copylen);
@@ -1190,20 +1188,18 @@
if (CMSG_SPACE(datalen) < clen) {
clen -= CMSG_SPACE(datalen);
cm = (struct cmsghdr *)
- ((caddr_t)cm + CMSG_SPACE(datalen));
+ ((caddr_t)cm + CMSG_SPACE(datalen));
} else {
clen = 0;
cm = NULL;
}
- }
- m = m->m_next;
+ }
+ msg->msg_controllen = (len <= 0) ? maxlen :
+ ctlbuf - (caddr_t)msg->msg_control;
}
- msg->msg_controllen = (len <= 0) ? maxlen : ctlbuf - (caddr_t)msg->msg_control;
-
exit:
return (error);
-
}
int
@@ -1240,12 +1236,12 @@
error = kern_recvit(td, uap->s, &msg, UIO_USERSPACE, controlp);
if (error == 0) {
msg.msg_iov = uiov;
-
+
if (control != NULL)
error = freebsd32_copy_msg_out(&msg, control);
else
msg.msg_controllen = 0;
-
+
if (error == 0)
error = freebsd32_copyoutmsghdr(&msg, uap->msg);
}
Index: sys/compat/linux/linux_socket.c
===================================================================
--- sys/compat/linux/linux_socket.c
+++ sys/compat/linux/linux_socket.c
@@ -1338,9 +1338,8 @@
bsd_to_linux_cmsg_type(cm->cmsg_type);
linux_cmsg->cmsg_level =
bsd_to_linux_sockopt_level(cm->cmsg_level);
- if (linux_cmsg->cmsg_type == -1
- || cm->cmsg_level != SOL_SOCKET)
- {
+ if (linux_cmsg->cmsg_type == -1 ||
+ cm->cmsg_level != SOL_SOCKET) {
error = EINVAL;
goto bad;
}
@@ -1348,8 +1347,7 @@
data = CMSG_DATA(cm);
datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
- switch (cm->cmsg_type)
- {
+ switch (cm->cmsg_type) {
case SCM_RIGHTS:
if (flags & LINUX_MSG_CMSG_CLOEXEC) {
fds = datalen / sizeof(int);
@@ -1402,6 +1400,7 @@
} else {
linux_msg.msg_flags |=
LINUX_MSG_CTRUNC;
+ m_dispose_extcontrolm(control);
goto out;
}
}
@@ -1429,8 +1428,12 @@
error = copyout(&linux_msg, msghdr, sizeof(linux_msg));
bad:
+ if (control != NULL) {
+ if (error != 0)
+ m_dispose_extcontrolm(control);
+ m_freem(control);
+ }
free(iov, M_IOV);
- m_freem(control);
free(linux_cmsg, M_LINUX);
return (error);
Index: sys/kern/uipc_syscalls.c
===================================================================
--- sys/kern/uipc_syscalls.c
+++ sys/kern/uipc_syscalls.c
@@ -894,7 +894,7 @@
{
struct uio auio;
struct iovec *iov;
- struct mbuf *m, *control = NULL;
+ struct mbuf *control, *m;
caddr_t ctlbuf;
struct file *fp;
struct socket *so;
@@ -941,6 +941,7 @@
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,
@@ -1004,30 +1005,22 @@
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);
@@ -1039,8 +1032,11 @@
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);
}
@@ -1562,3 +1558,51 @@
}
return (error);
}
+
+/*
+ * 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);
+ }
+}
Index: sys/kern/uipc_usrreq.c
===================================================================
--- sys/kern/uipc_usrreq.c
+++ sys/kern/uipc_usrreq.c
@@ -2046,6 +2046,13 @@
&fdep[i]->fde_caps);
unp_externalize_fp(fdep[i]->fde_file);
}
+
+ /*
+ * The new type indicates that the mbuf data refers to
+ * kernel resources that may need to be released before
+ * the mbuf is freed.
+ */
+ m_chtype(*controlp, MT_EXTCONTROL);
FILEDESC_XUNLOCK(fdesc);
free(fdep[0], M_FILECAPS);
} else {
Index: sys/sys/mbuf.h
===================================================================
--- sys/sys/mbuf.h
+++ sys/sys/mbuf.h
@@ -568,7 +568,8 @@
#define MT_EXP4 12 /* for experimental use */
#define MT_CONTROL 14 /* extra-data protocol message */
-#define MT_OOBDATA 15 /* expedited data */
+#define MT_EXTCONTROL 15 /* control message with externalized contents */
+#define MT_OOBDATA 16 /* expedited data */
#define MT_NOINIT 255 /* Not a type but a flag to allocate
a non-initialized mbuf */
@@ -633,6 +634,7 @@
void m_demote(struct mbuf *, int, int);
struct mbuf *m_devget(char *, int, int, struct ifnet *,
void (*)(char *, caddr_t, u_int));
+void m_dispose_extcontrolm(struct mbuf *m);
struct mbuf *m_dup(const struct mbuf *, int);
int m_dup_pkthdr(struct mbuf *, const struct mbuf *, int);
void m_extadd(struct mbuf *, char *, u_int, m_ext_free_t,

File Metadata

Mime Type
text/plain
Expires
Mon, Dec 22, 11:20 PM (4 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27165918
Default Alt Text
D16561.id46166.diff (8 KB)

Event Timeline