unp_internalize() tries to resize a mbuf by calling MCLGET() and then
copying the mbuf data into the extcluster allocated over the mbuf.
This fails badly since the exthdr is put into the data section of the
mbuf. So instead copy out the data into temporary storage and then copy
back after succesful cluster allocation.

This fixes a problem when trying to pass more then 26 fds on amd64.
-- 
:wq Claudio

Index: kern//uipc_usrreq.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_usrreq.c,v
retrieving revision 1.57
diff -u -p -r1.57 uipc_usrreq.c
--- kern//uipc_usrreq.c 13 Apr 2012 09:38:32 -0000      1.57
+++ kern//uipc_usrreq.c 13 Apr 2012 15:31:27 -0000
@@ -783,18 +783,24 @@ morespace:
        neededspace = CMSG_SPACE(nfds * sizeof(struct file *)) -
            control->m_len;
        if (neededspace > M_TRAILINGSPACE(control)) {
+               char *tmp;
                /* if we already have a cluster, the message is just too big */
                if (control->m_flags & M_EXT)
                        return (E2BIG);
 
+               /* copy cmsg data temporarily out of the mbuf */
+               tmp = malloc(control->m_len, M_TEMP, M_WAITOK);
+               memcpy(tmp, mtod(control, caddr_t), control->m_len);
+
                /* allocate a cluster and try again */
                MCLGET(control, M_WAIT);
                if ((control->m_flags & M_EXT) == 0)
                        return (ENOBUFS);       /* allocation failed */
 
-               /* copy the data to the cluster */
-               memcpy(mtod(control, char *), cm, cm->cmsg_len);
+               /* copy the data back into the cluster */
                cm = mtod(control, struct cmsghdr *);
+               memcpy(cm, tmp, control->m_len);
+               free(tmp, M_TEMP);
                goto morespace;
        }

Reply via email to