ref: 9b8e21a6669c6312809b174220fca59728cbb68b
dir: /kern/sysproc.c/
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
#include "user.h"
#include "mem.h"
#include <a.out.h>
static int
shargs(char *s, int n, char **ap, int nap)
{
char *p;
int i;
if(n <= 2 || s[0] != '#' || s[1] != '!')
return -1;
s += 2;
n -= 2; /* skip #! */
if((p = memchr(s, '\n', n)) == nil)
return 0;
*p = 0;
i = tokenize(s, ap, nap-1);
ap[i] = nil;
return i;
}
ulong
beswal(ulong l)
{
uchar *p;
p = (uchar*)&l;
return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
}
uvlong
beswav(uvlong v)
{
uchar *p;
p = (uchar*)&v;
return ((uvlong)p[0]<<56) | ((uvlong)p[1]<<48) | ((uvlong)p[2]<<40)
| ((uvlong)p[3]<<32) | ((uvlong)p[4]<<24)
| ((uvlong)p[5]<<16) | ((uvlong)p[6]<<8)
| (uvlong)p[7];
}
void
evenaddr(uintptr addr)
{
if(addr & 3){
postnote(up, 1, "sys: odd address", NDebug);
error(Ebadarg);
}
}
Segment *
seg(Proc *p, uintptr addr, int dolock)
{
Segment **s, **et, *n;
et = &p->seg[NSEG];
for(s = p->seg; s < et; s++) {
if((n = *s) == nil)
continue;
print("Here %x %x %x\n", addr, n->base, n->top);
if(addr >= n->base && addr < n->top) {
if(dolock == 0)
return n;
qlock(&n->ql);
if(addr >= n->base && addr < n->top)
return n;
qunlock(&n->ql);
}
}
return nil;
}
int
okaddr(uintptr addr, ulong len, int wr)
{
Segment *s;
if((long)len >= 0 && len <= -addr)
for(;;) {
s = seg(up, addr, 0);
if(s == nil)
print("Nil seg\n");
if(s == nil || (wr && (s->type&SG_RONLY)))
break;
print("Here\n");
if((ulong)addr+len > s->top) {
len -= s->top - (ulong)addr;
addr = s->top;
print("Looping\n");
continue;
}
print("Good!\n");
return 1;
}
return 0;
}
void
validaddr(uintptr addr, ulong len, int wr)
{
if(!okaddr(addr, len, wr)) {
pprint("suicide: invalid address\n");
postnote(up, 1, "sys: bad address in syscall", NDebug);
error(Ebadarg);
}
}
/*
* &s[0] is known to be a valid address.
*/
void*
vmemchr(void *s, int c, ulong n)
{
uintptr a;
ulong m, i;
void *t;
i = n;
a = (uintptr)s;
for(;;){
m = BY2PG - (a & (BY2PG-1));
if(i <= m)
break;
/* spans pages; handle this page */
t = memchr((void*)a, c, m);
if(t != nil)
return t;
a += m;
i -= m;
if(a < KZERO)
validaddr(a, 1, 0);
}
print(" returning\n");
/* fits in one page */
return memchr((void*)a, c, i);
}
#undef read
int
sysexec(va_list list)
{
union {
struct {
Exec ex;
uvlong hdr[1];
} ehdr;
char buf[256];
} u;
char line[256];
char *progarg[32+1];
volatile char *args, *file0, *elem;
char **argv, **argp, **argp0;
char *a, *e, *file;
Chan *tc;
ulong magic, nbytes, nargs;
uintptr t, d, b, entry, text, align, data, bss, bssend;
int n, indir;
args = elem = nil;
file0 = va_arg(list, char*);
validaddr((uintptr)file0, 1, 0);
argp0 = va_arg(list, char**);
evenaddr((uintptr)argp0);
validaddr((uintptr)argp0, 2*BY2WD, 0);
if(*argp0 == nil)
error(Ebadarg);
file0 = validnamedup(file0, 1);
if(waserror()){
free(file0);
free(elem);
free(args);
/* Disaster after commit */
if(up->seg[SSEG] == nil)
pexit(up->errstr, 1);
nexterror();
}
align = BY2PG-1;
indir = 0;
file = file0;
for(;;){
tc = namec(file, Aopen, OEXEC, 0);
if(waserror()){
cclose(tc);
nexterror();
}
if(!indir)
kstrdup(&elem, up->genbuf);
n = devtab[tc->type]->read(tc, u.buf, sizeof(u.buf), 0);
if (n >= sizeof(Exec)){
magic = beswal(u.ehdr.ex.magic);
if(magic & AOUT_MAGIC) {
if(magic & HDR_MAGIC){
if(n < sizeof(u.ehdr))
error(Ebadexec);
entry = beswav(u.ehdr.hdr[0]);
text = UTZERO+sizeof(u.ehdr);
} else {
entry = beswal(u.ehdr.ex.entry);
text = UTZERO+sizeof(Exec);
}
if(entry < text)
error(Ebadexec);
text += beswal(u.ehdr.ex.text);
// Shouldn't have to cast to ulong here, unsure why it's needed
if((ulong)text <= (ulong)entry || (ulong)text >= (USTKTOP-USTKSIZE))
error(Ebadexec);
switch(magic){
case S_MAGIC: /* 2MB segment alignment for amd64 */
align = 0x1fffff;
break;
case P_MAGIC: /* 16K segment alignment for spim */
case V_MAGIC: /* 16K segment alignment for mips */
align = 0x3fff;
break;
case R_MAGIC: /* 64K segment alignment for arm64 */
align = 0xffff;
break;
}
break; /* for binary */
}
}
if(indir++)
error(Ebadexec);
/* Process #!/bin/sh args */
memmove(line, u.buf, n);
n = shargs(line, n, progarg, nelem(progarg));
if(n < 1)
error(Ebadexec);
/* First arg becomes complete file name */
progarg[n++] = file;
progarg[n] = nil;
argp0++;
file = progarg[0];
progarg[0] = elem;
poperror();
cclose(tc);
}
t = (text+align) & ~align;
text -= UTZERO;
data = beswal(u.ehdr.ex.data);
bss = beswal(u.ehdr.ex.bss);
align = BY2PG-1;
d = (t + data + align) & ~align;
bssend = t + data + bss;
b = (bssend + align) & ~align;
if(t >= (ulong)(USTKTOP-USTKSIZE) || d >= (ulong)(USTKTOP-USTKSIZE) || b >= (ulong)(USTKTOP-USTKSIZE))
error(Ebadexec);
/* Args: pass 1: count */
nbytes = sizeof(Tos);
nargs = 0;
if(indir){
argp = progarg;
while(*argp != nil){
a = *argp++;
nbytes += strlen(a)+1;
nargs++;
}
}
argp = argp0;
while(*argp != nil){
a = *argp++;
if(((uintptr)argp&(BY2PG-1)) < BY2WD)
validaddr((uintptr)argp, BY2WD, 0);
validaddr((uintptr)a, 1, 0);
e = vmemchr(a, 0, USTKSIZE);
if(e == nil)
error(Ebadarg);
nbytes += (e - a) + 1;
if(nbytes >= USTKSIZE)
error(Enovmem);
nargs++;
}
print("%d args\n", nargs);
// End of the road cleanup
poperror(); // tc
cclose(tc);
poperror(); // file0
free(file0);
return 0;
}