On Fri Mar 15 16:42:15 EDT 2013, [email protected] 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"