Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 22 May 2013 13:21:48 +0400
From:      Gleb Smirnoff <glebius@FreeBSD.org>
To:        Mateusz Guzik <mjg@FreeBSD.org>, pjd@FreeBSD.org
Cc:        svn-src-head@freebsd.org, svn-src-all@freebsd.org, src-committers@freebsd.org
Subject:   Re: svn commit: r250890 - head/sys/kern
Message-ID:  <20130522092148.GM67170@FreeBSD.org>
In-Reply-To: <201305212158.r4LLw1Ed076595@svn.freebsd.org>
References:  <201305212158.r4LLw1Ed076595@svn.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help

--gj572EiMnwbLXET9
Content-Type: text/plain; charset=koi8-r
Content-Disposition: inline

On Tue, May 21, 2013 at 09:58:01PM +0000, Mateusz Guzik wrote:
M> Author: mjg
M> Date: Tue May 21 21:58:00 2013
M> New Revision: 250890
M> URL: http://svnweb.freebsd.org/changeset/base/250890
M> 
M> Log:
M>   passing fd over unix socket: fix a corner case where caller
M>   wants to pass no descriptors.
M>   
M>   Previously the kernel would leak memory and try to free a potentially
M>   arbitrary pointer.
M>   
M>   Reviewed by:	pjd

Is it possible to make code more strict: assert that fdcount > 0, and
do not perform any processing if number of fds is 0?

Prototype patch against r250890 attached.

-- 
Totus tuus, Glebius.

--gj572EiMnwbLXET9
Content-Type: text/x-diff; charset=koi8-r
Content-Disposition: attachment; filename="uipc_usrreq.c.diff"

Index: uipc_usrreq.c
===================================================================
--- uipc_usrreq.c	(revision 250906)
+++ uipc_usrreq.c	(working copy)
@@ -1686,8 +1686,8 @@ unp_freerights(struct filedescent **fdep, int fdco
 	struct file *fp;
 	int i;
 
-	if (fdcount == 0)
-		return;
+	KASSERT(fdcount > 0, ("%s: fdcount %d", __func__, fdcount));
+
 	for (i = 0; i < fdcount; i++) {
 		fp = fdep[i]->fde_file;
 		filecaps_free(&fdep[i]->fde_caps);
@@ -1725,6 +1725,8 @@ unp_externalize(struct mbuf *control, struct mbuf
 		if (cm->cmsg_level == SOL_SOCKET
 		    && cm->cmsg_type == SCM_RIGHTS) {
 			newfds = datalen / sizeof(*fdep);
+			if (newfds == 0)
+				goto next;
 			fdep = data;
 
 			/* If we're not outputting the descriptors free them. */
@@ -1770,8 +1772,7 @@ unp_externalize(struct mbuf *control, struct mbuf
 				unp_externalize_fp(fde->fde_file);
 			}
 			FILEDESC_XUNLOCK(fdesc);
-			if (newfds != 0)
-				free(fdep[0], M_FILECAPS);
+			free(fdep[0], M_FILECAPS);
 		} else {
 			/* We can just copy anything else across. */
 			if (error || controlp == NULL)
@@ -1894,6 +1895,8 @@ unp_internalize(struct mbuf **controlp, struct thr
 
 		case SCM_RIGHTS:
 			oldfds = datalen / sizeof (int);
+			if (oldfds == 0)
+				break;
 			/*
 			 * Check that all the FDs passed in refer to legal
 			 * files.  If not, reject the entire operation.
@@ -1928,10 +1931,6 @@ unp_internalize(struct mbuf **controlp, struct thr
 				error = E2BIG;
 				goto out;
 			}
-			if (oldfds == 0) {
-				FILEDESC_SUNLOCK(fdesc);
-				break;
-			}
 			fdp = data;
 			fdep = (struct filedescent **)
 			    CMSG_DATA(mtod(*controlp, struct cmsghdr *));

--gj572EiMnwbLXET9--



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