diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 8e7c851b5ca3..c765ee2b1f18 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -1581,6 +1581,34 @@ fdalloc(struct thread *td, int minfd, int *result) return (0); } +/* + * Allocate n file descriptors for the process. + */ +int +fdallocn(struct thread *td, int minfd, int *fds, int n) +{ + struct proc *p = td->td_proc; + struct filedesc *fdp = p->p_fd; + int i; + + FILEDESC_XLOCK_ASSERT(fdp); + + if (!fdavail(td, n)) + return (EMFILE); + + for (i = 0; i < n; i++) + if (fdalloc(td, 0, &fds[i]) != 0) + break; + + if (i < n) { + for (i--; i >= 0; i--) + fdunused(fdp, fds[i]); + return (EMFILE); + } + + return (0); +} + /* * Check to see whether n user file descriptors are available to the process * p. diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index 9b60eab9ec77..011c3ee3b34c 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -1706,7 +1706,6 @@ unp_externalize(struct mbuf *control, struct mbuf **controlp, int flags) void *data; socklen_t clen = control->m_len, datalen; int error, newfds; - int f; u_int newlen; UNP_LINK_UNLOCK_ASSERT(); @@ -1732,13 +1731,6 @@ unp_externalize(struct mbuf *control, struct mbuf **controlp, int flags) goto next; } FILEDESC_XLOCK(fdesc); - /* if the new FD's will not fit free them. */ - if (!fdavail(td, newfds)) { - FILEDESC_XUNLOCK(fdesc); - error = EMSGSIZE; - unp_freerights(fdep, newfds); - goto next; - } /* * Now change each pointer to an fd in the global @@ -1758,17 +1750,22 @@ unp_externalize(struct mbuf *control, struct mbuf **controlp, int flags) fdp = (int *) CMSG_DATA(mtod(*controlp, struct cmsghdr *)); + if (fdallocn(td, 0, fdp, newfds) != 0) { + FILEDESC_XUNLOCK(td->td_proc->p_fd); + error = EMSGSIZE; + unp_freerights(fdep, newfds); + m_freem(*controlp); + *controlp = NULL; + goto next; + } for (i = 0; i < newfds; i++, fdp++) { - if (fdalloc(td, 0, &f)) - panic("unp_externalize fdalloc failed"); - fde = &fdesc->fd_ofiles[f]; + fde = &fdesc->fd_ofiles[*fdp]; fde->fde_file = fdep[0]->fde_file; filecaps_move(&fdep[0]->fde_caps, &fde->fde_caps); if ((flags & MSG_CMSG_CLOEXEC) != 0) fde->fde_flags |= UF_EXCLOSE; unp_externalize_fp(fde->fde_file); - *fdp = f; } FILEDESC_XUNLOCK(fdesc); free(fdep[0], M_FILECAPS); diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h index d9fe0e0d8b46..1e51a9cfad45 100644 --- a/sys/sys/filedesc.h +++ b/sys/sys/filedesc.h @@ -150,6 +150,7 @@ int falloc_noinstall(struct thread *td, struct file **resultfp); int finstall(struct thread *td, struct file *fp, int *resultfp, int flags, struct filecaps *fcaps); int fdalloc(struct thread *td, int minfd, int *result); +int fdallocn(struct thread *td, int minfd, int *fds, int n); int fdavail(struct thread *td, int n); int fdcheckstd(struct thread *td); void fdclose(struct filedesc *fdp, struct file *fp, int idx, struct thread *td);