ash: exec: Stricter pathopt parsing
Upstream comment: Date: Sat, 19 May 2018 02:39:50 +0800 exec: Stricter pathopt parsing This patch changes the parsing of pathopt. First of all only %builtin and %func (with arbitrary suffixes) will be recognised. Any other pathopt will be treated as a normal directory. Furthermore, pathopt can now be specified before the directory, rather than after it. In fact, a future version may remove support for pathopt suffixes. Wherever the pathopt is placed, an optional % may be placed after it to terminate the pathopt. This is so that it is less likely that a genuine directory containing a % sign is parsed as a pathopt. Users of padvance outside of exec.c have also been modified: 1) cd(1) will always treat % characters as part of the path. 2) chkmail will continue to accept arbitrary pathopt. 3) find_dot_file will ignore the %builtin pathopt instead of trying to do a stat in the accompanying directory (which is usually the current directory). The patch also removes the clearcmdentry optimisation where we attempt to only partially flush the table where possible. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
b0d2dc7d62
commit
6c4f87e411
166
shell/ash.c
166
shell/ash.c
@ -2557,8 +2557,31 @@ listvars(int on, int off, struct strlist *lp, char ***end)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ============ Path search helper
|
/* ============ Path search helper */
|
||||||
*
|
static const char *
|
||||||
|
legal_pathopt(const char *opt, const char *term, int magic)
|
||||||
|
{
|
||||||
|
switch (magic) {
|
||||||
|
case 0:
|
||||||
|
opt = NULL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
opt = prefix(opt, "builtin") ?: prefix(opt, "func");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
opt += strcspn(opt, term);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt && *opt == '%')
|
||||||
|
opt++;
|
||||||
|
|
||||||
|
return opt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
* The variable path (passed by reference) should be set to the start
|
* The variable path (passed by reference) should be set to the start
|
||||||
* of the path before the first call; padvance will update
|
* of the path before the first call; padvance will update
|
||||||
* this value as it proceeds. Successive calls to padvance will return
|
* this value as it proceeds. Successive calls to padvance will return
|
||||||
@ -2566,40 +2589,70 @@ listvars(int on, int off, struct strlist *lp, char ***end)
|
|||||||
* a percent sign) appears in the path entry then the global variable
|
* a percent sign) appears in the path entry then the global variable
|
||||||
* pathopt will be set to point to it; otherwise pathopt will be set to
|
* pathopt will be set to point to it; otherwise pathopt will be set to
|
||||||
* NULL.
|
* NULL.
|
||||||
|
*
|
||||||
|
* If magic is 0 then pathopt recognition will be disabled. If magic is
|
||||||
|
* 1 we shall recognise %builtin/%func. Otherwise we shall accept any
|
||||||
|
* pathopt.
|
||||||
*/
|
*/
|
||||||
static const char *pathopt; /* set by padvance */
|
static const char *pathopt; /* set by padvance */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
padvance(const char **path, const char *name)
|
padvance_magic(const char **path, const char *name, int magic)
|
||||||
{
|
{
|
||||||
|
const char *term = "%:";
|
||||||
|
const char *lpathopt;
|
||||||
const char *p;
|
const char *p;
|
||||||
char *q;
|
char *q;
|
||||||
const char *start;
|
const char *start;
|
||||||
|
size_t qlen;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
if (*path == NULL)
|
if (*path == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
lpathopt = NULL;
|
||||||
start = *path;
|
start = *path;
|
||||||
for (p = start; *p && *p != ':' && *p != '%'; p++)
|
|
||||||
continue;
|
if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) {
|
||||||
len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
|
lpathopt = start + 1;
|
||||||
q = growstackto(len);
|
start = p;
|
||||||
if (p != start) {
|
term = ":";
|
||||||
q = mempcpy(q, start, p - start);
|
}
|
||||||
|
|
||||||
|
len = strcspn(start, term);
|
||||||
|
p = start + len;
|
||||||
|
|
||||||
|
if (*p == '%') {
|
||||||
|
size_t extra = strchrnul(p, ':') - p;
|
||||||
|
|
||||||
|
if (legal_pathopt(p + 1, term, magic))
|
||||||
|
lpathopt = p + 1;
|
||||||
|
else
|
||||||
|
len += extra;
|
||||||
|
|
||||||
|
p += extra;
|
||||||
|
}
|
||||||
|
|
||||||
|
pathopt = lpathopt;
|
||||||
|
*path = *p == ':' ? p + 1 : NULL;
|
||||||
|
|
||||||
|
/* "2" is for '/' and '\0' */
|
||||||
|
qlen = len + strlen(name) + 2;
|
||||||
|
q = growstackto(qlen);
|
||||||
|
|
||||||
|
if (len) {
|
||||||
|
q = mempcpy(q, start, len);
|
||||||
*q++ = '/';
|
*q++ = '/';
|
||||||
}
|
}
|
||||||
strcpy(q, name);
|
strcpy(q, name);
|
||||||
pathopt = NULL;
|
|
||||||
if (*p == '%') {
|
return qlen;
|
||||||
pathopt = ++p;
|
|
||||||
while (*p && *p != ':')
|
|
||||||
p++;
|
|
||||||
}
|
}
|
||||||
if (*p == ':')
|
|
||||||
*path = p + 1;
|
static int
|
||||||
else
|
padvance(const char **path, const char *name)
|
||||||
*path = NULL;
|
{
|
||||||
return len;
|
return padvance_magic(path, name, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -8217,11 +8270,10 @@ printentry(struct tblentry *cmdp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear out command entries. The argument specifies the first entry in
|
* Clear out command entries.
|
||||||
* PATH which has changed.
|
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
clearcmdentry(int firstchange)
|
clearcmdentry(void)
|
||||||
{
|
{
|
||||||
struct tblentry **tblp;
|
struct tblentry **tblp;
|
||||||
struct tblentry **pp;
|
struct tblentry **pp;
|
||||||
@ -8231,10 +8283,8 @@ clearcmdentry(int firstchange)
|
|||||||
for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
|
for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
|
||||||
pp = tblp;
|
pp = tblp;
|
||||||
while ((cmdp = *pp) != NULL) {
|
while ((cmdp = *pp) != NULL) {
|
||||||
if ((cmdp->cmdtype == CMDNORMAL &&
|
if (cmdp->cmdtype == CMDNORMAL
|
||||||
cmdp->param.index >= firstchange)
|
|| (cmdp->cmdtype == CMDBUILTIN && builtinloc > 0)
|
||||||
|| (cmdp->cmdtype == CMDBUILTIN &&
|
|
||||||
builtinloc >= firstchange)
|
|
||||||
) {
|
) {
|
||||||
*pp = cmdp->next;
|
*pp = cmdp->next;
|
||||||
free(cmdp);
|
free(cmdp);
|
||||||
@ -8334,7 +8384,7 @@ hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
|
|||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
if (nextopt("r") != '\0') {
|
if (nextopt("r") != '\0') {
|
||||||
clearcmdentry(0);
|
clearcmdentry();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8395,42 +8445,28 @@ hashcd(void)
|
|||||||
* Called with interrupts off.
|
* Called with interrupts off.
|
||||||
*/
|
*/
|
||||||
static void FAST_FUNC
|
static void FAST_FUNC
|
||||||
changepath(const char *new)
|
changepath(const char *newval)
|
||||||
{
|
{
|
||||||
const char *old;
|
const char *new;
|
||||||
int firstchange;
|
|
||||||
int idx;
|
int idx;
|
||||||
int idx_bltin;
|
int bltin;
|
||||||
|
|
||||||
old = pathval();
|
new = newval;
|
||||||
firstchange = 9999; /* assume no change */
|
|
||||||
idx = 0;
|
idx = 0;
|
||||||
idx_bltin = -1;
|
bltin = -1;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (*old != *new) {
|
if (*new == '%' && prefix(new + 1, "builtin")) {
|
||||||
firstchange = idx;
|
bltin = idx;
|
||||||
if ((*old == '\0' && *new == ':')
|
break;
|
||||||
|| (*old == ':' && *new == '\0')
|
}
|
||||||
) {
|
new = strchr(new, ':');
|
||||||
firstchange++;
|
if (!new)
|
||||||
}
|
|
||||||
old = new; /* ignore subsequent differences */
|
|
||||||
}
|
|
||||||
if (*new == '\0')
|
|
||||||
break;
|
break;
|
||||||
if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
|
|
||||||
idx_bltin = idx;
|
|
||||||
if (*new == ':')
|
|
||||||
idx++;
|
idx++;
|
||||||
new++;
|
new++;
|
||||||
old++;
|
|
||||||
}
|
}
|
||||||
if (builtinloc < 0 && idx_bltin >= 0)
|
builtinloc = bltin;
|
||||||
builtinloc = idx_bltin; /* zap builtins */
|
clearcmdentry();
|
||||||
if (builtinloc >= 0 && idx_bltin < 0)
|
|
||||||
firstchange = 0;
|
|
||||||
clearcmdentry(firstchange);
|
|
||||||
builtinloc = idx_bltin;
|
|
||||||
}
|
}
|
||||||
enum {
|
enum {
|
||||||
TEOF,
|
TEOF,
|
||||||
@ -11024,7 +11060,7 @@ chkmail(void)
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
len = padvance(&mpath, nullstr);
|
len = padvance_magic(&mpath, nullstr, 2);
|
||||||
if (!len)
|
if (!len)
|
||||||
break;
|
break;
|
||||||
p = stackblock();
|
p = stackblock();
|
||||||
@ -13360,7 +13396,9 @@ find_dot_file(char *basename)
|
|||||||
|
|
||||||
while ((len = padvance(&path, basename)) >= 0) {
|
while ((len = padvance(&path, basename)) >= 0) {
|
||||||
fullname = stackblock();
|
fullname = stackblock();
|
||||||
if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
|
if ((!pathopt || *pathopt == 'f')
|
||||||
|
&& !stat(fullname, &statb) && S_ISREG(statb.st_mode)
|
||||||
|
) {
|
||||||
/* This will be freed by the caller. */
|
/* This will be freed by the caller. */
|
||||||
return stalloc(len);
|
return stalloc(len);
|
||||||
}
|
}
|
||||||
@ -13566,17 +13604,19 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
|
|||||||
idx = -1;
|
idx = -1;
|
||||||
loop:
|
loop:
|
||||||
while ((len = padvance(&path, name)) >= 0) {
|
while ((len = padvance(&path, name)) >= 0) {
|
||||||
|
const char *lpathopt = pathopt;
|
||||||
|
|
||||||
fullname = stackblock();
|
fullname = stackblock();
|
||||||
idx++;
|
idx++;
|
||||||
if (pathopt) {
|
if (lpathopt) {
|
||||||
if (prefix(pathopt, "builtin")) {
|
if (*lpathopt == 'b') {
|
||||||
if (bcmd)
|
if (bcmd)
|
||||||
goto builtin_success;
|
goto builtin_success;
|
||||||
continue;
|
continue;
|
||||||
}
|
} else if (!(act & DO_NOFUNC)) {
|
||||||
if ((act & DO_NOFUNC)
|
/* handled below */
|
||||||
|| !prefix(pathopt, "func")
|
} else {
|
||||||
) { /* ignore unimplemented options */
|
/* ignore unimplemented options */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -13599,7 +13639,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
|
|||||||
e = EACCES; /* if we fail, this will be the error */
|
e = EACCES; /* if we fail, this will be the error */
|
||||||
if (!S_ISREG(statb.st_mode))
|
if (!S_ISREG(statb.st_mode))
|
||||||
continue;
|
continue;
|
||||||
if (pathopt) { /* this is a %func directory */
|
if (lpathopt) { /* this is a %func directory */
|
||||||
stalloc(len);
|
stalloc(len);
|
||||||
/* NB: stalloc will return space pointed by fullname
|
/* NB: stalloc will return space pointed by fullname
|
||||||
* (because we don't have any intervening allocations
|
* (because we don't have any intervening allocations
|
||||||
|
Loading…
x
Reference in New Issue
Block a user