Date: Wed, 24 Jul 2019 12:57:50 +0000 (UTC) From: Gordon Tetlow <gordon@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-releng@freebsd.org Subject: svn commit: r350286 - in releng: 11.2/sys/kern 11.3/sys/kern 12.0/sys/kern Message-ID: <201907241257.x6OCvo64076684@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201907241257.x6OCvo64076684>