sysproc: raise limit on #! lines, and allow quoted args

Our #! line length is very short, and the naïve quoting
makes it difficult to pass more complicated arguments to
the programs being run. This is fine for simple interpreters,
but it's often useful to pass arguments to more complicated
interpreters like auth/box or awk.

This change raises the limit, but also switches to tokenizing
via tokenize(2), rather than hand rolled whitespace splitting.

The limits chosen are arbitrary, but they leave approximately
3 KiB of stack space on 386, and 13k on amd64. This is a lot
of stack used, but it should leave enough for fairly deep
devtab chan stacks.
This commit is contained in:
Ori Bernstein 2022-07-25 04:48:44 +00:00
parent 3cc07dddfb
commit 520a39efcd
2 changed files with 31 additions and 39 deletions

View file

@ -67,6 +67,11 @@ and any initial arguments to that program, for example
ls | mc ls | mc
.EE .EE
.PP .PP
There may be up to 256 bytes of arguments passed to the interpreter.
These are tokenized into up to 32 arguments by
.IR tokenize (2)
before being passed as the interpreters argument vector.
.PP
When a C program is executed, When a C program is executed,
it is called as follows: it is called as follows:
.IP .IP

View file

@ -243,35 +243,19 @@ sysrfork(va_list list)
} }
static int static int
shargs(char *s, int n, char **ap) shargs(char *s, int n, char **ap, int nap)
{ {
char *p;
int i; int i;
if(n <= 2 || s[0] != '#' || s[1] != '!') if(n <= 2 || s[0] != '#' || s[1] != '!')
return -1; return -1;
s += 2; s += 2;
n -= 2; /* skip #! */ n -= 2; /* skip #! */
for(i=0;; i++){ if((p = memchr(s, '\n', n)) == nil)
if(i >= n)
return 0; return 0;
if(s[i]=='\n') *p = 0;
break; i = tokenize(s, ap, nap-1);
}
s[i] = 0;
i = 0;
for(;;) {
while(*s==' ' || *s=='\t')
s++;
if(*s == 0)
break;
ap[i++] = s++;
while(*s && *s!=' ' && *s!='\t')
s++;
if(*s == 0)
break;
*s++ = 0;
}
ap[i] = nil; ap[i] = nil;
return i; return i;
} }
@ -300,12 +284,15 @@ beswav(uvlong v)
uintptr uintptr
sysexec(va_list list) sysexec(va_list list)
{ {
union {
struct { struct {
Exec; Exec;
uvlong hdr[1]; uvlong hdr[1];
} ehdr; } ehdr;
char line[sizeof(ehdr)]; char buf[256];
char *progarg[sizeof(line)/2+1]; } u;
char line[256];
char *progarg[32+1];
volatile char *args, *elem, *file0; volatile char *args, *elem, *file0;
char **argv, **argp, **argp0; char **argv, **argp, **argp0;
char *a, *e, *charp, *file; char *a, *e, *charp, *file;
@ -353,22 +340,22 @@ sysexec(va_list list)
if(!indir) if(!indir)
kstrdup(&elem, up->genbuf); kstrdup(&elem, up->genbuf);
n = devtab[tc->type]->read(tc, &ehdr, sizeof(ehdr), 0); n = devtab[tc->type]->read(tc, u.buf, sizeof(u.buf), 0);
if(n >= sizeof(Exec)) { if(n >= sizeof(Exec)) {
magic = beswal(ehdr.magic); magic = beswal(u.ehdr.magic);
if(magic == AOUT_MAGIC) { if(magic == AOUT_MAGIC) {
if(magic & HDR_MAGIC) { if(magic & HDR_MAGIC) {
if(n < sizeof(ehdr)) if(n < sizeof(u.ehdr))
error(Ebadexec); error(Ebadexec);
entry = beswav(ehdr.hdr[0]); entry = beswav(u.ehdr.hdr[0]);
text = UTZERO+sizeof(ehdr); text = UTZERO+sizeof(u.ehdr);
} else { } else {
entry = beswal(ehdr.entry); entry = beswal(u.ehdr.entry);
text = UTZERO+sizeof(Exec); text = UTZERO+sizeof(Exec);
} }
if(entry < text) if(entry < text)
error(Ebadexec); error(Ebadexec);
text += beswal(ehdr.text); text += beswal(u.ehdr.text);
if(text <= entry || text >= (USTKTOP-USTKSIZE)) if(text <= entry || text >= (USTKTOP-USTKSIZE))
error(Ebadexec); error(Ebadexec);
@ -393,8 +380,8 @@ sysexec(va_list list)
/* /*
* Process #! /bin/sh args ... * Process #! /bin/sh args ...
*/ */
memmove(line, &ehdr, n); memmove(line, u.buf, n);
n = shargs(line, n, progarg); n = shargs(line, n, progarg, nelem(progarg));
if(n < 1) if(n < 1)
error(Ebadexec); error(Ebadexec);
/* /*
@ -411,8 +398,8 @@ sysexec(va_list list)
t = (text+align) & ~align; t = (text+align) & ~align;
text -= UTZERO; text -= UTZERO;
data = beswal(ehdr.data); data = beswal(u.ehdr.data);
bss = beswal(ehdr.bss); bss = beswal(u.ehdr.bss);
align = BY2PG-1; align = BY2PG-1;
d = (t + data + align) & ~align; d = (t + data + align) & ~align;
bssend = t + data + bss; bssend = t + data + bss;