ref: 631aef280d0363ea853b0ab878005e48153b5eea
parent: d526ee0750815820ac70e030ff87775ac56785e3
author: cinap_lenrek <[email protected]>
date: Sun Mar 10 21:16:34 EDT 2013
ape: fix thread race with close() and select() in ape close(), do the real filedescriptor _CLOSE() *after* we cleared the _fdinfo[] slot because once closed, we dont own the slot anymore and another process doing open() can trash the slot. make sure open() retuns fd < OPEN_MAX. double check in _startbuf() holding mux->lock if the fd is already buffered preveting running double copyprocs on a fd. dont zero the mux->rwant/ewant bitmaps at the end of select() as we do not hold the mix->lock. in _closebuf() kill copyproc while holding the mux->lock to make sure the copyproc isnt holding it at the time it is killed. run kill() multiple times to make sure the proc is gone.
--- a/sys/src/ape/lib/ap/plan9/_buf.c
+++ b/sys/src/ape/lib/ap/plan9/_buf.c
@@ -71,10 +71,20 @@
lock(&mux->lock);
f = &_fdinfo[fd];
+ if((f->flags&FD_ISOPEN) == 0){
+ unlock(&mux->lock);
+ errno = EBADF;
+ return -1;
+ }
if((f->flags&FD_BUFFERED) != 0){
unlock(&mux->lock);
return 0;
}
+ if((f->flags&FD_BUFFEREDX) != 0){
+ unlock(&mux->lock);
+ errno = EIO;
+ return -1;
+ }
slot = mux->curfds++;
if(mux->curfds > INITBUFS) {
@@ -127,14 +137,18 @@
_closebuf(int fd)
{
Muxbuf *b;
+ int i;
b = _fdinfo[fd].buf;
- if(!b)
+ if(b == 0 || mux == 0)
return;
lock(&mux->lock);
- b->fd = -1;
+ if(b->fd == fd){
+ b->fd = -1;
+ for(i=0; i<10 && kill(b->copypid, SIGKILL)==0; i++)
+ _SLEEP(1);
+ }
unlock(&mux->lock);
- kill(b->copypid, SIGKILL);
}
/* child copy procs execute this until eof */
@@ -149,7 +163,7 @@
for(;;) {
/* make sure there's room */
lock(&mux->lock);
- if(e - b->putnext < READMAX) {
+ if(b->fd == fd && (e - b->putnext) < READMAX) {
if(b->getnext == b->putnext) {
b->getnext = b->putnext = b->data;
unlock(&mux->lock);
@@ -168,12 +182,15 @@
*/
nzeros = 0;
do {
+ if(b->fd != fd)
+ break;
n = _READ(fd, b->putnext, READMAX);
- if(b->fd == -1) {
- _exit(0); /* we've been closed */
- }
- } while(n == 0 && ++nzeros < 3);
+ } while(b->fd == fd && n == 0 && ++nzeros < 3);
lock(&mux->lock);
+ if(b->fd != fd){
+ unlock(&mux->lock);
+ _exit(0); /* we've been closed */
+ }
if(n <= 0) {
b->eof = 1;
if(mux->selwait && FD_ISSET(fd, &mux->ewant)) {
@@ -222,6 +239,11 @@
int ngot;
b = _fdinfo[fd].buf;
+ if(b == nil || b->fd != fd){
+badfd:
+ errno = EBADF;
+ return -1;
+ }
if(b->eof && b->n == 0) {
goteof:
return 0;
@@ -230,8 +252,12 @@
errno = EAGAIN;
return -1;
}
- /* make sure there's data */
lock(&mux->lock);
+ if(b->fd != fd){
+ unlock(&mux->lock);
+ goto badfd;
+ }
+ /* make sure there's data */
ngot = b->putnext - b->getnext;
if(ngot == 0) {
/* maybe EOF just happened */
@@ -244,6 +270,10 @@
unlock(&mux->lock);
_RENDEZVOUS((unsigned long)&b->datawait, 0);
lock(&mux->lock);
+ if(b->fd != fd){
+ unlock(&mux->lock);
+ goto badfd;
+ }
ngot = b->putnext - b->getnext;
}
if(ngot == 0) {
@@ -285,7 +315,8 @@
return 0;
}
- _startbuf(-1);
+ if(_startbuf(-1) != 0)
+ return -1;
/* make sure all requested rfds and efds are buffered */
if(nfds >= OPEN_MAX)
@@ -363,9 +394,10 @@
mux->selwait = 1;
unlock(&mux->lock);
fd = _RENDEZVOUS((unsigned long)&mux->selwait, 0);
- if(fd >= 0) {
+ if(fd >= 0 && fd < nfds) {
b = _fdinfo[fd].buf;
- if(FD_ISSET(fd, &mux->rwant)) {
+ if(b == 0 || b->fd != fd) {
+ } else if(FD_ISSET(fd, &mux->rwant)) {
FD_SET(fd, rfds);
n = 1;
} else if(FD_ISSET(fd, &mux->ewant) && b->eof && b->n == 0) {
@@ -373,8 +405,6 @@
n = 1;
}
}
- FD_ZERO(&mux->rwant);
- FD_ZERO(&mux->ewant);
return n;
}
--- a/sys/src/ape/lib/ap/plan9/close.c
+++ b/sys/src/ape/lib/ap/plan9/close.c
@@ -20,9 +20,6 @@
_closebuf(d);
f->flags &= ~FD_BUFFERED;
}
- n = _CLOSE(d);
- if(n < 0)
- _syserrno();
_fdinfo[d].flags = 0;
_fdinfo[d].oflags = 0;
if(_fdinfo[d].name){
@@ -29,6 +26,9 @@
free(_fdinfo[d].name);
_fdinfo[d].name = 0;
}
+ n = _CLOSE(d);
+ if(n < 0)
+ _syserrno();
}
return n;
}
--- a/sys/src/ape/lib/ap/plan9/open.c
+++ b/sys/src/ape/lib/ap/plan9/open.c
@@ -46,6 +46,11 @@
if(n < 0)
_syserrno();
}
+ if(n >= OPEN_MAX){
+ _CLOSE(n);
+ errno = ENFILE;
+ return -1;
+ }
if(n >= 0){
fi = &_fdinfo[n];
fi->flags = FD_ISOPEN;
--- a/sys/src/ape/lib/ap/plan9/read.c
+++ b/sys/src/ape/lib/ap/plan9/read.c
@@ -38,7 +38,7 @@
}
n = _readbuf(d, buf, nbytes, noblock);
}else{
- n = _READ(d, buf, nbytes);
+ n = _READ(d, buf, nbytes);
if(n < 0)
_syserrno();
}