summaryrefslogtreecommitdiffstats
path: root/otherlibs/unix/select.c
diff options
context:
space:
mode:
authorXavier Leroy <xavier.leroy@inria.fr>2012-09-24 11:26:54 +0000
committerXavier Leroy <xavier.leroy@inria.fr>2012-09-24 11:26:54 +0000
commit96ad2a761234a7cd51bd463eb6c15b75d9252262 (patch)
tree6e9d48f27266c73fadf5e558adec558d0909fcd7 /otherlibs/unix/select.c
parent3734fe0799bce1aac5673e9a585ce1043e524512 (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.c20
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;