[Midnightbsd-cvs] src [12222] trunk/sys/kern/uipc_usrreq.c: If a process attempts to transmit rights over a UNIX-domain socket and

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Wed Jul 24 23:21:26 EDT 2019


Revision: 12222
          http://svnweb.midnightbsd.org/src/?rev=12222
Author:   laffer1
Date:     2019-07-24 23:21:25 -0400 (Wed, 24 Jul 2019)
Log Message:
-----------
If a process attempts to transmit rights over a UNIX-domain socket and
an error causes the attempt to fail, references acquired on the rights
are not released and are leaked.  This bug can be used to cause the
reference counter to wrap around and free the corresponding file
structure.

Modified Paths:
--------------
    trunk/sys/kern/uipc_usrreq.c

Modified: trunk/sys/kern/uipc_usrreq.c
===================================================================
--- trunk/sys/kern/uipc_usrreq.c	2019-07-25 03:20:00 UTC (rev 12221)
+++ trunk/sys/kern/uipc_usrreq.c	2019-07-25 03:21:25 UTC (rev 12222)
@@ -1854,29 +1854,52 @@
 	UNP_DEFERRED_LOCK_INIT();
 }
 
+static void
+unp_internalize_cleanup_rights(struct mbuf *control)
+{
+	struct cmsghdr *cp;
+	struct mbuf *m;
+	void *data;
+	socklen_t datalen;
+
+	for (m = control; m != NULL; m = m->m_next) {
+		cp = mtod(m, struct cmsghdr *);
+		if (cp->cmsg_level != SOL_SOCKET ||
+		    cp->cmsg_type != SCM_RIGHTS)
+			continue;
+		data = CMSG_DATA(cp);
+		datalen = (caddr_t)cp + cp->cmsg_len - (caddr_t)data;
+		unp_freerights(data, datalen / sizeof(struct filedesc *));
+	}
+}
+
 static int
 unp_internalize(struct mbuf **controlp, struct thread *td)
 {
-	struct mbuf *control = *controlp;
-	struct proc *p = td->td_proc;
-	struct filedesc *fdesc = p->p_fd;
+	struct mbuf *control, **initial_controlp;
+	struct proc *p;
+	struct filedesc *fdesc;
 	struct bintime *bt;
-	struct cmsghdr *cm = mtod(control, struct cmsghdr *);
+	struct cmsghdr *cm;
 	struct cmsgcred *cmcred;
 	struct filedescent *fde, **fdep, *fdev;
 	struct file *fp;
 	struct timeval *tv;
-	int i, *fdp;
 	void *data;
-	socklen_t clen = control->m_len, datalen;
-	int error, oldfds;
+	socklen_t clen, datalen;
+	int i, error, *fdp, oldfds;
 	u_int newlen;
 
 	UNP_LINK_UNLOCK_ASSERT();
 
+	p = td->td_proc;
+	fdesc = p->p_fd;
 	error = 0;
+	control = *controlp;
+	clen = control->m_len;
 	*controlp = NULL;
-	while (cm != NULL) {
+	initial_controlp = controlp;
+	for (cm = mtod(control, struct cmsghdr *); cm != NULL;) {
 		if (sizeof(*cm) > clen || cm->cmsg_level != SOL_SOCKET
 		    || cm->cmsg_len > clen || cm->cmsg_len < sizeof(*cm)) {
 			error = EINVAL;
@@ -2003,6 +2026,8 @@
 	}
 
 out:
+	if (error != 0 && initial_controlp != NULL)
+		unp_internalize_cleanup_rights(*initial_controlp);
 	m_freem(control);
 	return (error);
 }



More information about the Midnightbsd-cvs mailing list