From: Ben Gras Date: Wed, 4 Oct 2006 13:28:38 +0000 (+0000) Subject: Change select() so that only as many words as necessary for the 'nfds' X-Git-Tag: v3.1.3~179 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/addsub.png?a=commitdiff_plain;h=cbfa0f4fb84667e1c10eee95d7a1829faed901fb;p=minix.git Change select() so that only as many words as necessary for the 'nfds' argument from the fd bitmasks are copied from and back to userspace. This solves an ABI dependency on OPEN_MAX. If nfds is too big for the current OPEN_MAX, select() fails (but that's relatively easy to fix by 'just' recompiling the system and not the application binaries), but if it's smaller, binaries keep working. --- diff --git a/servers/fs/select.c b/servers/fs/select.c index 609f009a4..066e17e9b 100644 --- a/servers/fs/select.c +++ b/servers/fs/select.c @@ -31,8 +31,8 @@ PRIVATE struct selectentry { fd_set readfds, writefds, errorfds; fd_set ready_readfds, ready_writefds, ready_errorfds; fd_set *vir_readfds, *vir_writefds, *vir_errorfds; - struct filp *filps[FD_SETSIZE]; - int type[FD_SETSIZE]; + struct filp *filps[OPEN_MAX]; + int type[OPEN_MAX]; int nfds, nreadyfds; clock_t expiry; timer_t timer; /* if expiry > 0 */ @@ -164,15 +164,22 @@ PRIVATE void ops2tab(int ops, int fd, struct selectentry *e) *===========================================================================*/ PRIVATE void copy_fdsets(struct selectentry *e) { + int fd_setsize; + if(e->nfds < 0 || e->nfds > OPEN_MAX) + panic(__FILE__, "select copy_fdsets: e->nfds wrong", e->nfds); + + /* Only copy back as many bits as the user expects. */ + fd_setsize = _FDSETWORDS(e->nfds)*_FDSETBITSPERWORD/8; + if (e->vir_readfds) sys_vircopy(SELF, D, (vir_bytes) &e->ready_readfds, - e->req_endpt, D, (vir_bytes) e->vir_readfds, sizeof(fd_set)); + e->req_endpt, D, (vir_bytes) e->vir_readfds, fd_setsize); if (e->vir_writefds) sys_vircopy(SELF, D, (vir_bytes) &e->ready_writefds, - e->req_endpt, D, (vir_bytes) e->vir_writefds, sizeof(fd_set)); + e->req_endpt, D, (vir_bytes) e->vir_writefds, fd_setsize); if (e->vir_errorfds) sys_vircopy(SELF, D, (vir_bytes) &e->ready_errorfds, - e->req_endpt, D, (vir_bytes) e->vir_errorfds, sizeof(fd_set)); + e->req_endpt, D, (vir_bytes) e->vir_errorfds, fd_setsize); return; } @@ -183,11 +190,11 @@ PRIVATE void copy_fdsets(struct selectentry *e) PUBLIC int do_select(void) { int r, nfds, is_timeout = 1, nonzero_timeout = 0, - fd, s, block = 0; + fd, s, block = 0, fd_setsize; struct timeval timeout; nfds = m_in.SEL_NFDS; - if (nfds < 0 || nfds > FD_SETSIZE) + if (nfds < 0 || nfds > OPEN_MAX) return EINVAL; for(s = 0; s < MAXSELECTS; s++) @@ -214,20 +221,26 @@ PUBLIC int do_select(void) selecttab[s].vir_writefds = (fd_set *) m_in.SEL_WRITEFDS; selecttab[s].vir_errorfds = (fd_set *) m_in.SEL_ERRORFDS; - /* copy args */ + /* Copy args. Our storage size is zeroed above. Only copy + * as many bits as user has supplied (nfds). + * Could be compiled with a different OPEN_MAX or FD_SETSIZE. + * If nfds is too large, we have already returned above. + */ + + fd_setsize = _FDSETWORDS(nfds)*_FDSETBITSPERWORD/8; if (selecttab[s].vir_readfds && (r=sys_vircopy(who_e, D, (vir_bytes) m_in.SEL_READFDS, - SELF, D, (vir_bytes) &selecttab[s].readfds, sizeof(fd_set))) != OK) + SELF, D, (vir_bytes) &selecttab[s].readfds, fd_setsize)) != OK) return r; if (selecttab[s].vir_writefds && (r=sys_vircopy(who_e, D, (vir_bytes) m_in.SEL_WRITEFDS, - SELF, D, (vir_bytes) &selecttab[s].writefds, sizeof(fd_set))) != OK) + SELF, D, (vir_bytes) &selecttab[s].writefds, fd_setsize)) != OK) return r; if (selecttab[s].vir_errorfds && (r=sys_vircopy(who_e, D, (vir_bytes) m_in.SEL_ERRORFDS, - SELF, D, (vir_bytes) &selecttab[s].errorfds, sizeof(fd_set))) != OK) + SELF, D, (vir_bytes) &selecttab[s].errorfds, fd_setsize)) != OK) return r; if (!m_in.SEL_TIMEOUT)