diff options
author | Xavier Leroy <xavier.leroy@inria.fr> | 2012-09-24 11:26:54 +0000 |
---|---|---|
committer | Xavier Leroy <xavier.leroy@inria.fr> | 2012-09-24 11:26:54 +0000 |
commit | 96ad2a761234a7cd51bd463eb6c15b75d9252262 (patch) | |
tree | 6e9d48f27266c73fadf5e558adec558d0909fcd7 /otherlibs/unix/select.c | |
parent | 3734fe0799bce1aac5673e9a585ce1043e524512 (diff) |
PR#5563: harden Unix.select against file descriptors above FD_SETSIZE
(Picked from r12947 in 4.00 branch)
git-svn-id: http://caml.inria.fr/svn/ocaml/trunk@12948 f963ae5c-01c2-4b8c-9fe0-0dff7051ff02
Diffstat (limited to 'otherlibs/unix/select.c')
-rw-r--r-- | otherlibs/unix/select.c | 20 |
1 files changed, 12 insertions, 8 deletions
diff --git a/otherlibs/unix/select.c b/otherlibs/unix/select.c index 049383986..afbd92f1e 100644 --- a/otherlibs/unix/select.c +++ b/otherlibs/unix/select.c @@ -29,18 +29,20 @@ #endif #include <string.h> #include <unistd.h> +#include <errno.h> -typedef fd_set file_descr_set; - -static void fdlist_to_fdset(value fdlist, fd_set *fdset, int *maxfd) +static int fdlist_to_fdset(value fdlist, fd_set *fdset, int *maxfd) { value l; FD_ZERO(fdset); for (l = fdlist; l != Val_int(0); l = Field(l, 1)) { - int fd = Int_val(Field(l, 0)); - FD_SET(fd, fdset); + long fd = Long_val(Field(l, 0)); + /* PR#5563: harden against bad fds */ + if (fd < 0 || fd >= FD_SETSIZE) return -1; + FD_SET((int) fd, fdset); if (fd > *maxfd) *maxfd = fd; } + return 0; } static value fdset_to_fdlist(value fdlist, fd_set *fdset) @@ -75,9 +77,11 @@ CAMLprim value unix_select(value readfds, value writefds, value exceptfds, Begin_roots3 (readfds, writefds, exceptfds); maxfd = -1; - fdlist_to_fdset(readfds, &read, &maxfd); - fdlist_to_fdset(writefds, &write, &maxfd); - fdlist_to_fdset(exceptfds, &except, &maxfd); + retcode = fdlist_to_fdset(readfds, &read, &maxfd); + retcode += fdlist_to_fdset(writefds, &write, &maxfd); + retcode += fdlist_to_fdset(exceptfds, &except, &maxfd); + /* PR#5563: if a bad fd was encountered, report EINVAL error */ + if (retcode != 0) unix_error(EINVAL, "select", Nothing); tm = Double_val(timeout); if (tm < 0.0) tvp = (struct timeval *) NULL; |