On Fri Mar 15 16:42:15 EDT 2013, cinap_len...@gmx.de wrote: > note here: > > havnt tested this with any code yet. writing a simple test program > for this case would be a good next step.
what i can't explain is why this doesn't fail on a 32-bit kernel. i've attached a test program and a proposed fix. there are shorter fixes that disallow segments just below the stack, but that seems wrong since based on /proc/$pid/segment, that address space should be available for allocation. another way to approach this would be to always allocate ESEG and make it a new unmappable segment type, say SG_HOLE. finally one could put ESEG above the regular stack, but it's not clear to me that this isn't just a bit too sneaky. - erik minooka; 8.system2 vastart 0xdf7fe000 # (success) ; 6.system2 vastart 0x7ffffec00000 rc 2846: suicide: sys: trap: fault read addr=0x0 pc=0x2031e4 ; cat system2.c #include <u.h> #include <libc.h> void system(void) { execl("/bin/rc", "rc", nil); sysfatal("execl: %r"); } void* share(usize len) { uchar *vastart; vastart = segattach(0, "shared", nil, len); if(vastart== (void*)-1) sysfatal("segattach: %r"); fprint(2, "vastart %#p\n", vastart); return vastart; } void main(void) { share(10); system(); exits(""); } ----- minooka; diffy -c /sys/src/nix/port/sysproc.c /n/dump/2013/0315/sys/src/nix/port/sysproc.c:258,263 - /sys/src/nix/port/sysproc.c:258,281 /* no core preferred, don't change the process color */ } + uintptr + findhole(Proc *p, usize len) + { + uintptr va; + Segment *os; + + va = p->seg[SSEG]->base - len; + for(;;) { + os = isoverlap(p, va, len); + if(os == nil) + return va; + va = os->base; + if(len > va) + error("exec: no hole for ESEG"); + va -= len; + } + } + void sysexec(Ar0* ar0, va_list list) { /n/dump/2013/0315/sys/src/nix/port/sysproc.c:271,277 - /sys/src/nix/port/sysproc.c:289,295 char *a, *elem, *file, *p, *ufile, **argv; char line[sizeof(Exec)], *progarg[sizeof(Exec)/2+1]; long hdrsz, magic, textsz, datasz, bsssz; - uintptr textlim, datalim, bsslim, entry, stack; + uintptr textlim, datalim, bsslim, entry, stack, tstk; static int colorgen; /* /n/dump/2013/0315/sys/src/nix/port/sysproc.c:410,416 - /sys/src/nix/port/sysproc.c:428,435 qunlock(&up->seglock); nexterror(); } - up->seg[ESEG] = newseg(SG_STACK, TSTKTOP-USTKSIZE, TSTKTOP); + tstk = findhole(up, USTKSIZE); + up->seg[ESEG] = newseg(SG_STACK, tstk, tstk+USTKSIZE); up->seg[ESEG]->color = up->color; /* /n/dump/2013/0315/sys/src/nix/port/sysproc.c:417,423 - /sys/src/nix/port/sysproc.c:436,442 * Stack is a pointer into the temporary stack * segment, and will move as items are pushed. */ - stack = TSTKTOP-sizeof(Tos); + stack = tstk+USTKSIZE - sizeof(Tos); /* * First, the top-of-stack structure. /n/dump/2013/0315/sys/src/nix/port/sysproc.c:464,470 - /sys/src/nix/port/sysproc.c:483,489 * will not overflow the bottom of the stack. */ stack -= n; - if(stack < TSTKTOP-USTKSIZE) + if(stack < tstk) error(Enovmem); p = UINT2PTR(stack); memmove(p, a, n); /n/dump/2013/0315/sys/src/nix/port/sysproc.c:489,501 - /sys/src/nix/port/sysproc.c:508,520 */ a = p = UINT2PTR(stack); stack = sysexecstack(stack, argc); - if(stack-(argc+1)*sizeof(char**)-m->pgsz[up->seg[ESEG]->pgszi] < TSTKTOP-USTKSIZE) + if(stack-(argc+1)*sizeof(char**)-m->pgsz[up->seg[ESEG]->pgszi] < tstk) error(Enovmem); argv = (char**)stack; *--argv = nil; for(i = 0; i < argc; i++){ - *--argv = p + (USTKTOP-TSTKTOP); + *--argv = p + (USTKTOP-(tstk+USTKSIZE)); p += strlen(p) + 1; } /n/dump/2013/0315/sys/src/nix/port/sysproc.c:600,606 - /sys/src/nix/port/sysproc.c:619,625 s->base = USTKTOP-USTKSIZE; s->top = USTKTOP; - relocateseg(s, USTKTOP-TSTKTOP); + relocateseg(s, USTKTOP-(tstk+USTKSIZE)); /* * '/' processes are higher priority. /n/dump/2013/0315/sys/src/nix/port/sysproc.c:627,633 - /sys/src/nix/port/sysproc.c:646,652 if(up->hang) up->procctl = Proc_stopme; - ar0->v = sysexecregs(entry, TSTKTOP - PTR2UINT(argv), argc); + ar0->v = sysexecregs(entry, tstk+USTKSIZE - PTR2UINT(argv), argc); DBG("sysexec up %#p done\n" "textsz %lx datasz %lx bsssz %lx hdrsz %lx\n"