diff options
author | Tijl Coosemans <tijl@FreeBSD.org> | 2018-11-20 14:18:57 +0000 |
---|---|---|
committer | Tijl Coosemans <tijl@FreeBSD.org> | 2018-11-20 14:18:57 +0000 |
commit | 7df0e7beb7417750db24cc1eb342a3cd0f133ef5 (patch) | |
tree | 3b83a3d83c04c575524628617881d479f569eaac /sys/compat | |
parent | 0a05369d451d2d74aed16ac9f3aef22a1e798d62 (diff) | |
download | src-7df0e7beb7417750db24cc1eb342a3cd0f133ef5.tar.gz src-7df0e7beb7417750db24cc1eb342a3cd0f133ef5.zip |
Fix another user address dereference in linux_sendmsg syscall.
This was hidden behind the LINUX_CMSG_NXTHDR macro which dereferences its
second argument. Stop using the macro as well as LINUX_CMSG_FIRSTHDR. Use
the size field of the kernel copy of the control message header to obtain
the next control message.
PR: 217901
MFC after: 2 days
X-MFC-With: r340631
Notes
Notes:
svn path=/head/; revision=340674
Diffstat (limited to 'sys/compat')
-rw-r--r-- | sys/compat/linux/linux_socket.c | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c index 27c012d6531f..2979b257bd94 100644 --- a/sys/compat/linux/linux_socket.c +++ b/sys/compat/linux/linux_socket.c @@ -1096,6 +1096,7 @@ linux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr, sa_family_t sa_family; void *data; l_size_t len; + l_size_t clen; int error; error = copyin(msghdr, &linux_msg, sizeof(linux_msg)); @@ -1127,7 +1128,7 @@ linux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr, control = NULL; - if ((ptr_cmsg = LINUX_CMSG_FIRSTHDR(&linux_msg)) != NULL) { + if (linux_msg.msg_controllen >= sizeof(struct l_cmsghdr)) { error = kern_getsockname(td, s, &sa, &datalen); if (error != 0) goto bad; @@ -1140,6 +1141,8 @@ linux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr, data = mtod(control, void *); datalen = 0; + ptr_cmsg = PTRIN(linux_msg.msg_control); + clen = linux_msg.msg_controllen; do { error = copyin(ptr_cmsg, &linux_cmsg, sizeof(struct l_cmsghdr)); @@ -1147,7 +1150,8 @@ linux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr, goto bad; error = EINVAL; - if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr)) + if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr) || + linux_cmsg.cmsg_len > clen) goto bad; if (datalen + CMSG_HDRSZ > MCLBYTES) @@ -1199,7 +1203,14 @@ linux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr, cmsg->cmsg_len = CMSG_LEN(len); data = (char *)data + CMSG_SPACE(len); datalen += CMSG_SPACE(len); - } while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&linux_msg, ptr_cmsg))); + + if (clen <= LINUX_CMSG_ALIGN(linux_cmsg.cmsg_len)) + break; + + clen -= LINUX_CMSG_ALIGN(linux_cmsg.cmsg_len); + ptr_cmsg = (struct l_cmsghdr *)((char *)ptr_cmsg + + LINUX_CMSG_ALIGN(linux_cmsg.cmsg_len)); + } while(clen >= sizeof(struct l_cmsghdr)); control->m_len = datalen; if (datalen == 0) { |