mirror of
https://git.hardenedbsd.org/hardenedbsd/HardenedBSD.git
synced 2024-12-29 23:24:13 +01:00
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
This commit is contained in:
parent
e40779571e
commit
0fa211be96
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=264164
@ -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;
|
||||
if (buflen > MCLBYTES)
|
||||
return (EINVAL);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
data = FREEBSD32_CMSG_DATA(cm);
|
||||
datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
|
||||
/* Modify the message length to account for alignment. */
|
||||
*(u_int *)md = msglen + CMSG_ALIGN(sizeof(struct cmsghdr)) -
|
||||
FREEBSD32_ALIGN(sizeof(struct cmsghdr));
|
||||
|
||||
*controlp = sbcreatecontrol(data, datalen, cm->cmsg_type,
|
||||
cm->cmsg_level);
|
||||
controlp = &(*controlp)->m_next;
|
||||
md = (char *)md + CMSG_ALIGN(sizeof(struct cmsghdr));
|
||||
buf += FREEBSD32_ALIGN(sizeof(struct cmsghdr));
|
||||
buflen -= FREEBSD32_ALIGN(sizeof(struct cmsghdr));
|
||||
|
||||
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;
|
||||
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,
|
||||
|
Loading…
Reference in New Issue
Block a user