diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2020-02-17 16:02:40 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2020-02-17 16:02:40 +0100 |
commit | 6c4f87e411aa5375eaea5a5909a5c610e38c7e70 (patch) | |
tree | 0ef3d39731e103f0cdbdf2eec4676eebba8236a0 | |
parent | b0d2dc7d62f6dea67b82e451510fa77243b4c60c (diff) | |
download | busybox-w32-6c4f87e411aa5375eaea5a5909a5c610e38c7e70.tar.gz busybox-w32-6c4f87e411aa5375eaea5a5909a5c610e38c7e70.tar.bz2 busybox-w32-6c4f87e411aa5375eaea5a5909a5c610e38c7e70.zip |
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>
-rw-r--r-- | shell/ash.c | 168 |
1 files changed, 104 insertions, 64 deletions
diff --git a/shell/ash.c b/shell/ash.c index e89cecf0b..c383cccda 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -2557,8 +2557,31 @@ listvars(int on, int off, struct strlist *lp, char ***end) | |||
2557 | } | 2557 | } |
2558 | 2558 | ||
2559 | 2559 | ||
2560 | /* ============ Path search helper | 2560 | /* ============ Path search helper */ |
2561 | * | 2561 | static const char * |
2562 | legal_pathopt(const char *opt, const char *term, int magic) | ||
2563 | { | ||
2564 | switch (magic) { | ||
2565 | case 0: | ||
2566 | opt = NULL; | ||
2567 | break; | ||
2568 | |||
2569 | case 1: | ||
2570 | opt = prefix(opt, "builtin") ?: prefix(opt, "func"); | ||
2571 | break; | ||
2572 | |||
2573 | default: | ||
2574 | opt += strcspn(opt, term); | ||
2575 | break; | ||
2576 | } | ||
2577 | |||
2578 | if (opt && *opt == '%') | ||
2579 | opt++; | ||
2580 | |||
2581 | return opt; | ||
2582 | } | ||
2583 | |||
2584 | /* | ||
2562 | * The variable path (passed by reference) should be set to the start | 2585 | * The variable path (passed by reference) should be set to the start |
2563 | * of the path before the first call; padvance will update | 2586 | * of the path before the first call; padvance will update |
2564 | * this value as it proceeds. Successive calls to padvance will return | 2587 | * 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) | |||
2566 | * a percent sign) appears in the path entry then the global variable | 2589 | * a percent sign) appears in the path entry then the global variable |
2567 | * pathopt will be set to point to it; otherwise pathopt will be set to | 2590 | * pathopt will be set to point to it; otherwise pathopt will be set to |
2568 | * NULL. | 2591 | * NULL. |
2592 | * | ||
2593 | * If magic is 0 then pathopt recognition will be disabled. If magic is | ||
2594 | * 1 we shall recognise %builtin/%func. Otherwise we shall accept any | ||
2595 | * pathopt. | ||
2569 | */ | 2596 | */ |
2570 | static const char *pathopt; /* set by padvance */ | 2597 | static const char *pathopt; /* set by padvance */ |
2571 | 2598 | ||
2572 | static int | 2599 | static int |
2573 | padvance(const char **path, const char *name) | 2600 | padvance_magic(const char **path, const char *name, int magic) |
2574 | { | 2601 | { |
2602 | const char *term = "%:"; | ||
2603 | const char *lpathopt; | ||
2575 | const char *p; | 2604 | const char *p; |
2576 | char *q; | 2605 | char *q; |
2577 | const char *start; | 2606 | const char *start; |
2607 | size_t qlen; | ||
2578 | size_t len; | 2608 | size_t len; |
2579 | 2609 | ||
2580 | if (*path == NULL) | 2610 | if (*path == NULL) |
2581 | return -1; | 2611 | return -1; |
2612 | |||
2613 | lpathopt = NULL; | ||
2582 | start = *path; | 2614 | start = *path; |
2583 | for (p = start; *p && *p != ':' && *p != '%'; p++) | 2615 | |
2584 | continue; | 2616 | if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) { |
2585 | len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ | 2617 | lpathopt = start + 1; |
2586 | q = growstackto(len); | 2618 | start = p; |
2587 | if (p != start) { | 2619 | term = ":"; |
2588 | q = mempcpy(q, start, p - start); | ||
2589 | *q++ = '/'; | ||
2590 | } | 2620 | } |
2591 | strcpy(q, name); | 2621 | |
2592 | pathopt = NULL; | 2622 | len = strcspn(start, term); |
2623 | p = start + len; | ||
2624 | |||
2593 | if (*p == '%') { | 2625 | if (*p == '%') { |
2594 | pathopt = ++p; | 2626 | size_t extra = strchrnul(p, ':') - p; |
2595 | while (*p && *p != ':') | 2627 | |
2596 | p++; | 2628 | if (legal_pathopt(p + 1, term, magic)) |
2629 | lpathopt = p + 1; | ||
2630 | else | ||
2631 | len += extra; | ||
2632 | |||
2633 | p += extra; | ||
2597 | } | 2634 | } |
2598 | if (*p == ':') | 2635 | |
2599 | *path = p + 1; | 2636 | pathopt = lpathopt; |
2600 | else | 2637 | *path = *p == ':' ? p + 1 : NULL; |
2601 | *path = NULL; | 2638 | |
2602 | return len; | 2639 | /* "2" is for '/' and '\0' */ |
2640 | qlen = len + strlen(name) + 2; | ||
2641 | q = growstackto(qlen); | ||
2642 | |||
2643 | if (len) { | ||
2644 | q = mempcpy(q, start, len); | ||
2645 | *q++ = '/'; | ||
2646 | } | ||
2647 | strcpy(q, name); | ||
2648 | |||
2649 | return qlen; | ||
2650 | } | ||
2651 | |||
2652 | static int | ||
2653 | padvance(const char **path, const char *name) | ||
2654 | { | ||
2655 | return padvance_magic(path, name, 1); | ||
2603 | } | 2656 | } |
2604 | 2657 | ||
2605 | 2658 | ||
@@ -8217,11 +8270,10 @@ printentry(struct tblentry *cmdp) | |||
8217 | } | 8270 | } |
8218 | 8271 | ||
8219 | /* | 8272 | /* |
8220 | * Clear out command entries. The argument specifies the first entry in | 8273 | * Clear out command entries. |
8221 | * PATH which has changed. | ||
8222 | */ | 8274 | */ |
8223 | static void | 8275 | static void |
8224 | clearcmdentry(int firstchange) | 8276 | clearcmdentry(void) |
8225 | { | 8277 | { |
8226 | struct tblentry **tblp; | 8278 | struct tblentry **tblp; |
8227 | struct tblentry **pp; | 8279 | struct tblentry **pp; |
@@ -8231,10 +8283,8 @@ clearcmdentry(int firstchange) | |||
8231 | for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) { | 8283 | for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) { |
8232 | pp = tblp; | 8284 | pp = tblp; |
8233 | while ((cmdp = *pp) != NULL) { | 8285 | while ((cmdp = *pp) != NULL) { |
8234 | if ((cmdp->cmdtype == CMDNORMAL && | 8286 | if (cmdp->cmdtype == CMDNORMAL |
8235 | cmdp->param.index >= firstchange) | 8287 | || (cmdp->cmdtype == CMDBUILTIN && builtinloc > 0) |
8236 | || (cmdp->cmdtype == CMDBUILTIN && | ||
8237 | builtinloc >= firstchange) | ||
8238 | ) { | 8288 | ) { |
8239 | *pp = cmdp->next; | 8289 | *pp = cmdp->next; |
8240 | free(cmdp); | 8290 | free(cmdp); |
@@ -8334,7 +8384,7 @@ hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
8334 | char *name; | 8384 | char *name; |
8335 | 8385 | ||
8336 | if (nextopt("r") != '\0') { | 8386 | if (nextopt("r") != '\0') { |
8337 | clearcmdentry(0); | 8387 | clearcmdentry(); |
8338 | return 0; | 8388 | return 0; |
8339 | } | 8389 | } |
8340 | 8390 | ||
@@ -8395,42 +8445,28 @@ hashcd(void) | |||
8395 | * Called with interrupts off. | 8445 | * Called with interrupts off. |
8396 | */ | 8446 | */ |
8397 | static void FAST_FUNC | 8447 | static void FAST_FUNC |
8398 | changepath(const char *new) | 8448 | changepath(const char *newval) |
8399 | { | 8449 | { |
8400 | const char *old; | 8450 | const char *new; |
8401 | int firstchange; | ||
8402 | int idx; | 8451 | int idx; |
8403 | int idx_bltin; | 8452 | int bltin; |
8404 | 8453 | ||
8405 | old = pathval(); | 8454 | new = newval; |
8406 | firstchange = 9999; /* assume no change */ | ||
8407 | idx = 0; | 8455 | idx = 0; |
8408 | idx_bltin = -1; | 8456 | bltin = -1; |
8409 | for (;;) { | 8457 | for (;;) { |
8410 | if (*old != *new) { | 8458 | if (*new == '%' && prefix(new + 1, "builtin")) { |
8411 | firstchange = idx; | 8459 | bltin = idx; |
8412 | if ((*old == '\0' && *new == ':') | 8460 | break; |
8413 | || (*old == ':' && *new == '\0') | ||
8414 | ) { | ||
8415 | firstchange++; | ||
8416 | } | ||
8417 | old = new; /* ignore subsequent differences */ | ||
8418 | } | 8461 | } |
8419 | if (*new == '\0') | 8462 | new = strchr(new, ':'); |
8463 | if (!new) | ||
8420 | break; | 8464 | break; |
8421 | if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin")) | 8465 | idx++; |
8422 | idx_bltin = idx; | ||
8423 | if (*new == ':') | ||
8424 | idx++; | ||
8425 | new++; | 8466 | new++; |
8426 | old++; | ||
8427 | } | 8467 | } |
8428 | if (builtinloc < 0 && idx_bltin >= 0) | 8468 | builtinloc = bltin; |
8429 | builtinloc = idx_bltin; /* zap builtins */ | 8469 | clearcmdentry(); |
8430 | if (builtinloc >= 0 && idx_bltin < 0) | ||
8431 | firstchange = 0; | ||
8432 | clearcmdentry(firstchange); | ||
8433 | builtinloc = idx_bltin; | ||
8434 | } | 8470 | } |
8435 | enum { | 8471 | enum { |
8436 | TEOF, | 8472 | TEOF, |
@@ -11024,7 +11060,7 @@ chkmail(void) | |||
11024 | for (;;) { | 11060 | for (;;) { |
11025 | int len; | 11061 | int len; |
11026 | 11062 | ||
11027 | len = padvance(&mpath, nullstr); | 11063 | len = padvance_magic(&mpath, nullstr, 2); |
11028 | if (!len) | 11064 | if (!len) |
11029 | break; | 11065 | break; |
11030 | p = stackblock(); | 11066 | p = stackblock(); |
@@ -13360,7 +13396,9 @@ find_dot_file(char *basename) | |||
13360 | 13396 | ||
13361 | while ((len = padvance(&path, basename)) >= 0) { | 13397 | while ((len = padvance(&path, basename)) >= 0) { |
13362 | fullname = stackblock(); | 13398 | fullname = stackblock(); |
13363 | if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) { | 13399 | if ((!pathopt || *pathopt == 'f') |
13400 | && !stat(fullname, &statb) && S_ISREG(statb.st_mode) | ||
13401 | ) { | ||
13364 | /* This will be freed by the caller. */ | 13402 | /* This will be freed by the caller. */ |
13365 | return stalloc(len); | 13403 | return stalloc(len); |
13366 | } | 13404 | } |
@@ -13566,17 +13604,19 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
13566 | idx = -1; | 13604 | idx = -1; |
13567 | loop: | 13605 | loop: |
13568 | while ((len = padvance(&path, name)) >= 0) { | 13606 | while ((len = padvance(&path, name)) >= 0) { |
13607 | const char *lpathopt = pathopt; | ||
13608 | |||
13569 | fullname = stackblock(); | 13609 | fullname = stackblock(); |
13570 | idx++; | 13610 | idx++; |
13571 | if (pathopt) { | 13611 | if (lpathopt) { |
13572 | if (prefix(pathopt, "builtin")) { | 13612 | if (*lpathopt == 'b') { |
13573 | if (bcmd) | 13613 | if (bcmd) |
13574 | goto builtin_success; | 13614 | goto builtin_success; |
13575 | continue; | 13615 | continue; |
13576 | } | 13616 | } else if (!(act & DO_NOFUNC)) { |
13577 | if ((act & DO_NOFUNC) | 13617 | /* handled below */ |
13578 | || !prefix(pathopt, "func") | 13618 | } else { |
13579 | ) { /* ignore unimplemented options */ | 13619 | /* ignore unimplemented options */ |
13580 | continue; | 13620 | continue; |
13581 | } | 13621 | } |
13582 | } | 13622 | } |
@@ -13599,7 +13639,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
13599 | e = EACCES; /* if we fail, this will be the error */ | 13639 | e = EACCES; /* if we fail, this will be the error */ |
13600 | if (!S_ISREG(statb.st_mode)) | 13640 | if (!S_ISREG(statb.st_mode)) |
13601 | continue; | 13641 | continue; |
13602 | if (pathopt) { /* this is a %func directory */ | 13642 | if (lpathopt) { /* this is a %func directory */ |
13603 | stalloc(len); | 13643 | stalloc(len); |
13604 | /* NB: stalloc will return space pointed by fullname | 13644 | /* NB: stalloc will return space pointed by fullname |
13605 | * (because we don't have any intervening allocations | 13645 | * (because we don't have any intervening allocations |