aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2020-02-17 16:02:40 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2020-02-17 16:02:40 +0100
commit6c4f87e411aa5375eaea5a5909a5c610e38c7e70 (patch)
tree0ef3d39731e103f0cdbdf2eec4676eebba8236a0
parentb0d2dc7d62f6dea67b82e451510fa77243b4c60c (diff)
downloadbusybox-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.c168
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 * 2561static const char *
2562legal_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 */
2570static const char *pathopt; /* set by padvance */ 2597static const char *pathopt; /* set by padvance */
2571 2598
2572static int 2599static int
2573padvance(const char **path, const char *name) 2600padvance_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
2652static int
2653padvance(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 */
8223static void 8275static void
8224clearcmdentry(int firstchange) 8276clearcmdentry(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 */
8397static void FAST_FUNC 8447static void FAST_FUNC
8398changepath(const char *new) 8448changepath(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}
8435enum { 8471enum {
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