Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 22 Nov 2018 09:47:43 +0000 (UTC)
From:      Tijl Coosemans <tijl@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r340757 - stable/12/sys/compat/linux
Message-ID:  <201811220947.wAM9lh5R067225@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: tijl
Date: Thu Nov 22 09:47:42 2018
New Revision: 340757
URL: https://svnweb.freebsd.org/changeset/base/340757

Log:
  MFC r340674:
  
  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

Modified:
  stable/12/sys/compat/linux/linux_socket.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/compat/linux/linux_socket.c
==============================================================================
--- stable/12/sys/compat/linux/linux_socket.c	Thu Nov 22 09:41:54 2018	(r340756)
+++ stable/12/sys/compat/linux/linux_socket.c	Thu Nov 22 09:47:42 2018	(r340757)
@@ -1096,6 +1096,7 @@ linux_sendmsg_common(struct thread *td, l_int s, struc
 	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, struc
 
 	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, struc
 		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, struc
 				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, struc
 			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) {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201811220947.wAM9lh5R067225>