Author: gordon
Date: Wed Jul 24 12:57:49 2019
New Revision: 350286
URL: https://svnweb.freebsd.org/changeset/base/350286

Log:
  Fix file descriptor reference count leak.
  
  Approved by:  so
  Security:     FreeBSD-SA-19:17.fd
  Security:     CVE-2019-5607

Modified:
  releng/11.2/sys/kern/uipc_usrreq.c
  releng/11.3/sys/kern/uipc_usrreq.c
  releng/12.0/sys/kern/uipc_usrreq.c

Modified: releng/11.2/sys/kern/uipc_usrreq.c
==============================================================================
--- releng/11.2/sys/kern/uipc_usrreq.c  Wed Jul 24 12:56:06 2019        
(r350285)
+++ releng/11.2/sys/kern/uipc_usrreq.c  Wed Jul 24 12:57:49 2019        
(r350286)
@@ -1896,29 +1896,52 @@ unp_init(void)
        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;
@@ -2045,6 +2068,8 @@ unp_internalize(struct mbuf **controlp, struct thread 
        }
 
 out:
+       if (error != 0 && initial_controlp != NULL)
+               unp_internalize_cleanup_rights(*initial_controlp);
        m_freem(control);
        return (error);
 }

Modified: releng/11.3/sys/kern/uipc_usrreq.c
==============================================================================
--- releng/11.3/sys/kern/uipc_usrreq.c  Wed Jul 24 12:56:06 2019        
(r350285)
+++ releng/11.3/sys/kern/uipc_usrreq.c  Wed Jul 24 12:57:49 2019        
(r350286)
@@ -1908,30 +1908,53 @@ unp_init(void)
        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;
        struct timespec *ts;
-       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;
@@ -2082,6 +2105,8 @@ unp_internalize(struct mbuf **controlp, struct thread 
        }
 
 out:
+       if (error != 0 && initial_controlp != NULL)
+               unp_internalize_cleanup_rights(*initial_controlp);
        m_freem(control);
        return (error);
 }

Modified: releng/12.0/sys/kern/uipc_usrreq.c
==============================================================================
--- releng/12.0/sys/kern/uipc_usrreq.c  Wed Jul 24 12:56:06 2019        
(r350285)
+++ releng/12.0/sys/kern/uipc_usrreq.c  Wed Jul 24 12:57:49 2019        
(r350286)
@@ -2123,30 +2123,53 @@ unp_init(void)
        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;
        struct timespec *ts;
-       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;
@@ -2297,6 +2320,8 @@ unp_internalize(struct mbuf **controlp, struct thread 
        }
 
 out:
+       if (error != 0 && initial_controlp != NULL)
+               unp_internalize_cleanup_rights(*initial_controlp);
        m_freem(control);
        return (error);
 }
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to