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/ash.c | |
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/ash.c')
-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, |