aboutsummaryrefslogtreecommitdiff
path: root/sys/compat
diff options
context:
space:
mode:
authorTijl Coosemans <tijl@FreeBSD.org>2018-11-20 14:18:57 +0000
committerTijl Coosemans <tijl@FreeBSD.org>2018-11-20 14:18:57 +0000
commit7df0e7beb7417750db24cc1eb342a3cd0f133ef5 (patch)
tree3b83a3d83c04c575524628617881d479f569eaac /sys/compat
parent0a05369d451d2d74aed16ac9f3aef22a1e798d62 (diff)
downloadsrc-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.c17
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) {