Date: Sat, 5 Apr 2014 18:56:02 +0000 (UTC) From: Marcel Moolenaar <marcel@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r264164 - head/sys/compat/freebsd32 Message-ID: <201404051856.s35Iu2TV032920@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: marcel Date: Sat Apr 5 18:56:01 2014 New Revision: 264164 URL: http://svnweb.freebsd.org/changeset/base/264164 Log: In freebsd32_sendmsg(), replace the call to sockargs() followed by a call to freebsd32_convert_msg_in() with freebsd32_copyin_control() to readin and convert in a single step. This makes it simpler to put all the control messages in a single mbuf or mbuf cluster as per the limitations imposed upon us by ip6_setpktopts(). The logic is as follows: 1. Go over the array of control messages to determine overall size and include extra padding for proper alignment as we go. 2. Get a mbuf or mbuf cluster as needed or fail if the overall (adjusted) size is larger than a cluster. 3. Go over the array of control messages again, but now copy them into kernel space and into aligned offsets. 4. Update the length of the control message to take padding between the header and the data into account (but not for padding added between one control message and the next). Obtained from: Juniper Networks, Inc. MFC after: 1 week Modified: head/sys/compat/freebsd32/freebsd32_misc.c Modified: head/sys/compat/freebsd32/freebsd32_misc.c ============================================================================== --- head/sys/compat/freebsd32/freebsd32_misc.c Sat Apr 5 18:41:08 2014 (r264163) +++ head/sys/compat/freebsd32/freebsd32_misc.c Sat Apr 5 18:56:01 2014 (r264164) @@ -1137,47 +1137,91 @@ freebsd32_recvmsg(td, uap) return (error); } - +/* + * Copy-in the array of control messages constructed using alignment + * and padding suitable for a 32-bit environment and construct an + * mbuf using alignment and padding suitable for a 64-bit kernel. + * The alignment and padding are defined indirectly by CMSG_DATA(), + * CMSG_SPACE() and CMSG_LEN(). + */ static int -freebsd32_convert_msg_in(struct mbuf **controlp) +freebsd32_copyin_control(struct mbuf **mp, caddr_t buf, u_int buflen) { - struct mbuf *control = *controlp; - struct cmsghdr *cm = mtod(control, struct cmsghdr *); - void *data; - socklen_t clen = control->m_len, datalen; + struct mbuf *m; + void *md; + u_int idx, len, msglen; int error; - error = 0; - *controlp = NULL; + buflen = FREEBSD32_ALIGN(buflen); - while (cm != NULL) { - if (sizeof(struct cmsghdr) > clen || cm->cmsg_len > clen) { - error = EINVAL; - break; - } + if (buflen > MCLBYTES) + return (EINVAL); - data = FREEBSD32_CMSG_DATA(cm); - datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; + /* + * Iterate over the buffer and get the length of each message + * in there. This has 32-bit alignment and padding. Use it to + * determine the length of these messages when using 64-bit + * alignment and padding. + */ + idx = 0; + len = 0; + while (idx < buflen) { + error = copyin(buf + idx, &msglen, sizeof(msglen)); + if (error) + return (error); + if (msglen < sizeof(struct cmsghdr)) + return (EINVAL); + msglen = FREEBSD32_ALIGN(msglen); + if (idx + msglen > buflen) + return (EINVAL); + idx += msglen; + msglen += CMSG_ALIGN(sizeof(struct cmsghdr)) - + FREEBSD32_ALIGN(sizeof(struct cmsghdr)); + len += CMSG_ALIGN(msglen); + } - *controlp = sbcreatecontrol(data, datalen, cm->cmsg_type, - cm->cmsg_level); - controlp = &(*controlp)->m_next; - - if (FREEBSD32_CMSG_SPACE(datalen) < clen) { - clen -= FREEBSD32_CMSG_SPACE(datalen); - cm = (struct cmsghdr *) - ((caddr_t)cm + FREEBSD32_CMSG_SPACE(datalen)); - } else { - clen = 0; - cm = NULL; + if (len > MCLBYTES) + return (EINVAL); + + m = m_get(M_WAITOK, MT_CONTROL); + if (len > MLEN) + MCLGET(m, M_WAITOK); + m->m_len = len; + + md = mtod(m, void *); + while (buflen > 0) { + error = copyin(buf, md, sizeof(struct cmsghdr)); + if (error) + break; + msglen = *(u_int *)md; + msglen = FREEBSD32_ALIGN(msglen); + + /* Modify the message length to account for alignment. */ + *(u_int *)md = msglen + CMSG_ALIGN(sizeof(struct cmsghdr)) - + FREEBSD32_ALIGN(sizeof(struct cmsghdr)); + + md = (char *)md + CMSG_ALIGN(sizeof(struct cmsghdr)); + buf += FREEBSD32_ALIGN(sizeof(struct cmsghdr)); + buflen -= FREEBSD32_ALIGN(sizeof(struct cmsghdr)); + + msglen -= FREEBSD32_ALIGN(sizeof(struct cmsghdr)); + if (msglen > 0) { + error = copyin(buf, md, msglen); + if (error) + break; + md = (char *)md + CMSG_ALIGN(msglen); + buf += msglen; + buflen -= msglen; } } - m_freem(control); + if (error) + m_free(m); + else + *mp = m; return (error); } - int freebsd32_sendmsg(struct thread *td, struct freebsd32_sendmsg_args *uap) @@ -1215,14 +1259,13 @@ freebsd32_sendmsg(struct thread *td, goto out; } - error = sockargs(&control, msg.msg_control, - msg.msg_controllen, MT_CONTROL); - if (error) - goto out; - - error = freebsd32_convert_msg_in(&control); + error = freebsd32_copyin_control(&control, msg.msg_control, + msg.msg_controllen); if (error) goto out; + + msg.msg_control = NULL; + msg.msg_controllen = 0; } error = kern_sendit(td, uap->s, &msg, uap->flags, control,
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201404051856.s35Iu2TV032920>