disallow shrinking of segments when its shared by multiple processes. in a multithreaded application, process1 could do a blocking read in wich case the kernel will validate the accessability of the buffer *before* it calls into the device function wich then blocks. then process2 could shrink the segment and invalidate the buffer passed to the kernel by process1. now, when the blocking read for process1 unblocks, the kernel accesses invalid memory! when disallowing shrinking of shared segments, this can't happen anymore. heres no known plan9 application that needs shrinking of shared segments. Reference: /n/sources/patch/applied/kernel-ibrk-shrink-shared Date: Fri Apr 16 17:27:54 CES 2010 Signed-off-by: cinap_lenrek@gmx.de --- /sys/src/9/port/segment.c Fri Apr 16 17:27:43 2010 +++ /sys/src/9/port/segment.c Fri Apr 16 17:27:40 2010 @@ -465,6 +465,15 @@ newtop = PGROUND(addr); newsize = (newtop-s->base)/BY2PG; if(newtop < s->top) { + /* + * do not shrink when shared with other procs, as the freed + * address space may have been passed to the kernel already + * by another proc and is past the validaddr stage. + */ + if(s->ref > 1){ + qunlock(&s->lk); + error(Einuse); + } mfreeseg(s, newtop, (s->top-newtop)/BY2PG); s->top = newtop; s->size = newsize; @@ -676,19 +685,24 @@ * Starting at the lowest possible stack address - len, * check for an overlapping segment, and repeat at the * base of that segment - len until either a hole is found - * or the address space is exhausted. + * or the address space is exhausted. make sure we dont + * map the zero page. */ if(va == 0) { - va = p->seg[SSEG]->base - len; - for(;;) { - os = isoverlap(p, va, len); - if(os == nil) - break; + os = p->seg[SSEG]; + do { va = os->base; - if(len > va) + if(len >= va) error(Enovmem); va -= len; - } + os = isoverlap(p, va, len); + } while(os != nil); + } else { + va = va&~(BY2PG-1); + if(va == 0 || va >= USTKTOP) + error(Ebadarg); + if(isoverlap(p, va, len) != nil) + error(Esoverlap); } va = va&~(BY2PG-1);