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"

Reply via email to