summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/kern/kern_descrip.c28
-rw-r--r--sys/kern/uipc_usrreq.c21
-rw-r--r--sys/sys/filedesc.h1
3 files changed, 38 insertions, 12 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 8e7c851..c765ee2 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -1582,6 +1582,34 @@ fdalloc(struct thread *td, int minfd, int *result)
}
/*
+ * 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 9b60eab..011c3ee 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 d9fe0e0..1e51a9c 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);
OpenPOWER on IntegriCloud