diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2016-09-21 16:25:58 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2016-09-21 16:25:58 +0200 |
| commit | b3f29b452a660a7293162897424bed205f7f9147 (patch) | |
| tree | bd334b845e1affd68620bcffe60c3e6381606958 /shell | |
| parent | d8330ca4a42a7f5d81b233a1cf7cbc7a7bd0be95 (diff) | |
| download | busybox-w32-b3f29b452a660a7293162897424bed205f7f9147.tar.gz busybox-w32-b3f29b452a660a7293162897424bed205f7f9147.tar.bz2 busybox-w32-b3f29b452a660a7293162897424bed205f7f9147.zip | |
ash: use glob() from libc
Adapted from dash.
The "homegrown" glob code is retained (ifdef'ed out).
This changes was inspired by bug 9261, which detected out-of bounds use of heap
for 2098 byte long name in the "homegrown" code. This is still not fixed...
function old new delta
expandarg 960 982 +22
static.syntax_index_table 26 25 -1
static.spec_symbls 27 26 -1
static.metachars 4 - -4
addfname 42 - -42
msort 126 - -126
expmeta 528 - -528
------------------------------------------------------------------------------
(add/remove: 0/4 grow/shrink: 1/2 up/down: 22/-702) Total: -680 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/ash.c | 102 |
1 files changed, 91 insertions, 11 deletions
diff --git a/shell/ash.c b/shell/ash.c index d96e56851..267493708 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
| @@ -39,6 +39,7 @@ | |||
| 39 | 39 | ||
| 40 | #include <setjmp.h> | 40 | #include <setjmp.h> |
| 41 | #include <fnmatch.h> | 41 | #include <fnmatch.h> |
| 42 | #include <glob.h> | ||
| 42 | #include <sys/times.h> | 43 | #include <sys/times.h> |
| 43 | #include <sys/utsname.h> /* for setting $HOSTNAME */ | 44 | #include <sys/utsname.h> /* for setting $HOSTNAME */ |
| 44 | 45 | ||
| @@ -2808,18 +2809,27 @@ enum { | |||
| 2808 | static int | 2809 | static int |
| 2809 | SIT(int c, int syntax) | 2810 | SIT(int c, int syntax) |
| 2810 | { | 2811 | { |
| 2811 | static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~"; | 2812 | /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */ |
| 2813 | static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~"; | ||
| 2814 | /* | ||
| 2815 | * This causes '/' to be prepended with CTLESC in dquoted string, | ||
| 2816 | * making "./file"* treated incorrectly because we feed | ||
| 2817 | * ".\/file*" string to glob(), confusing it (see expandmeta func). | ||
| 2818 | * The "homegrown" glob implementation is okay with that, | ||
| 2819 | * but glibc one isn't. With '/' always treated as CWORD, | ||
| 2820 | * both work fine. | ||
| 2821 | */ | ||
| 2812 | # if ENABLE_ASH_ALIAS | 2822 | # if ENABLE_ASH_ALIAS |
| 2813 | static const uint8_t syntax_index_table[] ALIGN1 = { | 2823 | static const uint8_t syntax_index_table[] ALIGN1 = { |
| 2814 | 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */ | 2824 | 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */ |
| 2815 | 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */ | 2825 | 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */ |
| 2816 | 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */ | 2826 | 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */ |
| 2817 | 11, 3 /* "}~" */ | 2827 | 11, 3 /* "}~" */ |
| 2818 | }; | 2828 | }; |
| 2819 | # else | 2829 | # else |
| 2820 | static const uint8_t syntax_index_table[] ALIGN1 = { | 2830 | static const uint8_t syntax_index_table[] ALIGN1 = { |
| 2821 | 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */ | 2831 | 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */ |
| 2822 | 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */ | 2832 | 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */ |
| 2823 | 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */ | 2833 | 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */ |
| 2824 | 10, 2 /* "}~" */ | 2834 | 10, 2 /* "}~" */ |
| 2825 | }; | 2835 | }; |
| @@ -2901,7 +2911,8 @@ static const uint8_t syntax_index_table[] ALIGN1 = { | |||
| 2901 | /* 44 "," */ CWORD_CWORD_CWORD_CWORD, | 2911 | /* 44 "," */ CWORD_CWORD_CWORD_CWORD, |
| 2902 | /* 45 "-" */ CWORD_CCTL_CCTL_CWORD, | 2912 | /* 45 "-" */ CWORD_CCTL_CCTL_CWORD, |
| 2903 | /* 46 "." */ CWORD_CWORD_CWORD_CWORD, | 2913 | /* 46 "." */ CWORD_CWORD_CWORD_CWORD, |
| 2904 | /* 47 "/" */ CWORD_CCTL_CCTL_CWORD, | 2914 | /* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */ |
| 2915 | /* 47 "/" */ CWORD_CWORD_CWORD_CWORD, | ||
| 2905 | /* 48 "0" */ CWORD_CWORD_CWORD_CWORD, | 2916 | /* 48 "0" */ CWORD_CWORD_CWORD_CWORD, |
| 2906 | /* 49 "1" */ CWORD_CWORD_CWORD_CWORD, | 2917 | /* 49 "1" */ CWORD_CWORD_CWORD_CWORD, |
| 2907 | /* 50 "2" */ CWORD_CWORD_CWORD_CWORD, | 2918 | /* 50 "2" */ CWORD_CWORD_CWORD_CWORD, |
| @@ -5633,7 +5644,6 @@ rmescapes(char *str, int flag) | |||
| 5633 | while (*p) { | 5644 | while (*p) { |
| 5634 | if ((unsigned char)*p == CTLQUOTEMARK) { | 5645 | if ((unsigned char)*p == CTLQUOTEMARK) { |
| 5635 | // Note: both inquotes and protect_against_glob only affect whether | 5646 | // Note: both inquotes and protect_against_glob only affect whether |
| 5636 | // CTLESC,<ch> gets converted to <ch> or to \<ch> | ||
| 5637 | inquotes = ~inquotes; | 5647 | inquotes = ~inquotes; |
| 5638 | p++; | 5648 | p++; |
| 5639 | protect_against_glob = globbing; | 5649 | protect_against_glob = globbing; |
| @@ -5697,11 +5707,14 @@ memtodest(const char *p, size_t len, int syntax, int quotes) | |||
| 5697 | unsigned char c = *p++; | 5707 | unsigned char c = *p++; |
| 5698 | if (c) { | 5708 | if (c) { |
| 5699 | int n = SIT(c, syntax); | 5709 | int n = SIT(c, syntax); |
| 5700 | if ((quotes & QUOTES_ESC) && | 5710 | if ((quotes & QUOTES_ESC) |
| 5701 | ((n == CCTL) || | 5711 | && ((n == CCTL) |
| 5702 | (((quotes & EXP_FULL) || syntax != BASESYNTAX) && | 5712 | || (((quotes & EXP_FULL) || syntax != BASESYNTAX) |
| 5703 | n == CBACK))) | 5713 | && n == CBACK) |
| 5714 | ) | ||
| 5715 | ) { | ||
| 5704 | USTPUTC(CTLESC, q); | 5716 | USTPUTC(CTLESC, q); |
| 5717 | } | ||
| 5705 | } else if (!(quotes & QUOTES_KEEPNUL)) | 5718 | } else if (!(quotes & QUOTES_KEEPNUL)) |
| 5706 | continue; | 5719 | continue; |
| 5707 | USTPUTC(c, q); | 5720 | USTPUTC(c, q); |
| @@ -6435,7 +6448,8 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
| 6435 | char *idx, *end; | 6448 | char *idx, *end; |
| 6436 | 6449 | ||
| 6437 | if (!repl) { | 6450 | if (!repl) { |
| 6438 | if ((repl=strchr(str, CTLESC))) | 6451 | repl = strchr(str, CTLESC); |
| 6452 | if (repl) | ||
| 6439 | *repl++ = '\0'; | 6453 | *repl++ = '\0'; |
| 6440 | else | 6454 | else |
| 6441 | repl = nullstr; | 6455 | repl = nullstr; |
| @@ -6976,6 +6990,70 @@ addfname(const char *name) | |||
| 6976 | exparg.lastp = &sp->next; | 6990 | exparg.lastp = &sp->next; |
| 6977 | } | 6991 | } |
| 6978 | 6992 | ||
| 6993 | /* If we want to use glob() from libc... */ | ||
| 6994 | #if 1 | ||
| 6995 | |||
| 6996 | /* Add the result of glob() to the list */ | ||
| 6997 | static void | ||
| 6998 | addglob(const glob_t *pglob) | ||
| 6999 | { | ||
| 7000 | char **p = pglob->gl_pathv; | ||
| 7001 | |||
| 7002 | do { | ||
| 7003 | addfname(*p); | ||
| 7004 | } while (*++p); | ||
| 7005 | } | ||
| 7006 | static void | ||
| 7007 | expandmeta(struct strlist *str /*, int flag*/) | ||
| 7008 | { | ||
| 7009 | /* TODO - EXP_REDIR */ | ||
| 7010 | |||
| 7011 | while (str) { | ||
| 7012 | char *p; | ||
| 7013 | glob_t pglob; | ||
| 7014 | int i; | ||
| 7015 | |||
| 7016 | if (fflag) | ||
| 7017 | goto nometa; | ||
| 7018 | INT_OFF; | ||
| 7019 | p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP); | ||
| 7020 | /* | ||
| 7021 | * GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match | ||
| 7022 | * TODO?: GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?) | ||
| 7023 | */ | ||
| 7024 | i = glob(p, GLOB_NOMAGIC, NULL, &pglob); | ||
| 7025 | if (p != str->text) | ||
| 7026 | free(p); | ||
| 7027 | switch (i) { | ||
| 7028 | case 0: | ||
| 7029 | /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */ | ||
| 7030 | if (!(pglob.gl_flags & GLOB_MAGCHAR)) | ||
| 7031 | goto nometa2; | ||
| 7032 | addglob(&pglob); | ||
| 7033 | globfree(&pglob); | ||
| 7034 | INT_ON; | ||
| 7035 | break; | ||
| 7036 | case GLOB_NOMATCH: | ||
| 7037 | nometa2: | ||
| 7038 | globfree(&pglob); | ||
| 7039 | INT_ON; | ||
| 7040 | nometa: | ||
| 7041 | *exparg.lastp = str; | ||
| 7042 | rmescapes(str->text, 0); | ||
| 7043 | exparg.lastp = &str->next; | ||
| 7044 | break; | ||
| 7045 | default: /* GLOB_NOSPACE */ | ||
| 7046 | globfree(&pglob); | ||
| 7047 | INT_ON; | ||
| 7048 | ash_msg_and_raise_error(bb_msg_memory_exhausted); | ||
| 7049 | } | ||
| 7050 | str = str->next; | ||
| 7051 | } | ||
| 7052 | } | ||
| 7053 | |||
| 7054 | #else | ||
| 7055 | /* Homegrown globbing code. (dash also has both, uses homegrown one.) */ | ||
| 7056 | |||
| 6979 | /* | 7057 | /* |
| 6980 | * Do metacharacter (i.e. *, ?, [...]) expansion. | 7058 | * Do metacharacter (i.e. *, ?, [...]) expansion. |
| 6981 | */ | 7059 | */ |
| @@ -7179,7 +7257,8 @@ expandmeta(struct strlist *str /*, int flag*/) | |||
| 7179 | p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP); | 7257 | p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP); |
| 7180 | { | 7258 | { |
| 7181 | int i = strlen(str->text); | 7259 | int i = strlen(str->text); |
| 7182 | expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ | 7260 | //BUGGY estimation of how long expanded name can be |
| 7261 | expdir = ckmalloc(i < 2048 ? 2048 : i+1); | ||
| 7183 | } | 7262 | } |
| 7184 | expmeta(expdir, expdir, p); | 7263 | expmeta(expdir, expdir, p); |
| 7185 | free(expdir); | 7264 | free(expdir); |
| @@ -7204,6 +7283,7 @@ expandmeta(struct strlist *str /*, int flag*/) | |||
| 7204 | str = str->next; | 7283 | str = str->next; |
| 7205 | } | 7284 | } |
| 7206 | } | 7285 | } |
| 7286 | #endif /* our globbing code */ | ||
| 7207 | 7287 | ||
| 7208 | /* | 7288 | /* |
| 7209 | * Perform variable substitution and command substitution on an argument, | 7289 | * Perform variable substitution and command substitution on an argument, |
